Merge tag 'efi-urgent-for-v6.0-2' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 22 Sep 2022 17:27:38 +0000 (10:27 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 22 Sep 2022 17:27:38 +0000 (10:27 -0700)
Pull EFI fixes from Ard Biesheuvel:

 - Use the right variable to check for shim insecure mode

 - Wipe setup_data field when booting via EFI

 - Add missing error check to efibc driver

* tag 'efi-urgent-for-v6.0-2' of git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi:
  efi: libstub: check Shim mode using MokSBStateRT
  efi: x86: Wipe setup_data on pure EFI boot
  efi: efibc: Guard against allocation failure

1406 files changed:
.get_maintainer.ignore
.mailmap
Documentation/ABI/testing/sysfs-devices-system-cpu
Documentation/admin-guide/README.rst
Documentation/admin-guide/hw-vuln/processor_mmio_stale_data.rst
Documentation/admin-guide/kernel-parameters.txt
Documentation/admin-guide/mm/damon/usage.rst
Documentation/admin-guide/sysctl/net.rst
Documentation/arm64/elf_hwcaps.rst
Documentation/arm64/silicon-errata.rst
Documentation/atomic_bitops.txt
Documentation/block/index.rst
Documentation/block/ublk.rst [new file with mode: 0644]
Documentation/conf.py
Documentation/devicetree/bindings/arm/amlogic/amlogic,meson-gx-ao-secure.yaml
Documentation/devicetree/bindings/display/allwinner,sun4i-a10-tcon.yaml
Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.yaml
Documentation/devicetree/bindings/display/amlogic,meson-vpu.yaml
Documentation/devicetree/bindings/display/bridge/analogix,anx7814.yaml
Documentation/devicetree/bindings/display/bridge/ite,it66121.yaml
Documentation/devicetree/bindings/display/panel/sgd,gktw70sdae4se.yaml
Documentation/devicetree/bindings/hwmon/moortec,mr75203.yaml
Documentation/devicetree/bindings/i2c/amlogic,meson6-i2c.yaml
Documentation/devicetree/bindings/i2c/renesas,riic.yaml
Documentation/devicetree/bindings/iio/gyroscope/bosch,bmg160.yaml
Documentation/devicetree/bindings/input/touchscreen/goodix.yaml
Documentation/devicetree/bindings/interconnect/fsl,imx8m-noc.yaml
Documentation/devicetree/bindings/interrupt-controller/apple,aic.yaml
Documentation/devicetree/bindings/mailbox/amlogic,meson-gxbb-mhu.yaml
Documentation/devicetree/bindings/media/amlogic,axg-ge2d.yaml
Documentation/devicetree/bindings/media/amlogic,gx-vdec.yaml
Documentation/devicetree/bindings/media/amlogic,meson-gx-ao-cec.yaml
Documentation/devicetree/bindings/mfd/khadas,mcu.yaml
Documentation/devicetree/bindings/net/amlogic,meson-dwmac.yaml
Documentation/devicetree/bindings/net/qcom-emac.txt
Documentation/devicetree/bindings/phy/amlogic,axg-mipi-dphy.yaml
Documentation/devicetree/bindings/phy/amlogic,meson-g12a-usb2-phy.yaml
Documentation/devicetree/bindings/phy/amlogic,meson-g12a-usb3-pcie-phy.yaml
Documentation/devicetree/bindings/pinctrl/qcom,sc7280-lpass-lpi-pinctrl.yaml
Documentation/devicetree/bindings/pinctrl/qcom,sc7280-pinctrl.yaml
Documentation/devicetree/bindings/power/amlogic,meson-ee-pwrc.yaml
Documentation/devicetree/bindings/power/qcom,rpmpd.yaml
Documentation/devicetree/bindings/regulator/nxp,pca9450-regulator.yaml
Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.yaml
Documentation/devicetree/bindings/reset/amlogic,meson-reset.yaml
Documentation/devicetree/bindings/riscv/sifive-l2-cache.yaml
Documentation/devicetree/bindings/rng/amlogic,meson-rng.yaml
Documentation/devicetree/bindings/serial/amlogic,meson-uart.yaml
Documentation/devicetree/bindings/soc/amlogic/amlogic,canvas.yaml
Documentation/devicetree/bindings/spi/amlogic,meson-gx-spicc.yaml
Documentation/devicetree/bindings/spi/amlogic,meson6-spifc.yaml
Documentation/devicetree/bindings/spi/cdns,qspi-nor-peripheral-props.yaml
Documentation/devicetree/bindings/spi/cdns,qspi-nor.yaml
Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml
Documentation/devicetree/bindings/thermal/rcar-thermal.yaml
Documentation/devicetree/bindings/thermal/thermal-zones.yaml
Documentation/devicetree/bindings/usb/amlogic,meson-g12a-usb-ctrl.yaml
Documentation/devicetree/bindings/usb/mediatek,mtu3.yaml
Documentation/devicetree/bindings/usb/qcom,dwc3.yaml
Documentation/devicetree/bindings/watchdog/amlogic,meson-gxbb-wdt.yaml
Documentation/i2c/busses/i2c-piix4.rst
Documentation/i2c/i2c-topology.rst
Documentation/input/joydev/joystick.rst
Documentation/kbuild/kconfig-language.rst
Documentation/networking/devlink/netdevsim.rst
Documentation/networking/driver.rst
Documentation/networking/ip-sysctl.rst
Documentation/networking/ipvlan.rst
Documentation/networking/l2tp.rst
Documentation/networking/rxrpc.rst
Documentation/networking/switchdev.rst
Documentation/sphinx/kerneldoc-preamble.sty
Documentation/tools/rtla/rtla-timerlat-hist.rst
Documentation/translations/ja_JP/SubmittingPatches
MAINTAINERS
Makefile
arch/Kconfig
arch/alpha/include/asm/bitops.h
arch/arm/boot/dts/arm-realview-eb.dtsi
arch/arm/boot/dts/arm-realview-pb1176.dts
arch/arm/boot/dts/arm-realview-pb11mp.dts
arch/arm/boot/dts/arm-realview-pbx.dtsi
arch/arm/boot/dts/at91-sama5d27_wlsom1.dtsi
arch/arm/boot/dts/at91-sama5d2_icp.dts
arch/arm/boot/dts/at91-sama7g5ek.dts
arch/arm/boot/dts/bcm63178.dtsi
arch/arm/boot/dts/bcm6846.dtsi
arch/arm/boot/dts/bcm6878.dtsi
arch/arm/boot/dts/imx6qdl-kontron-samx6i.dtsi
arch/arm/boot/dts/imx6qdl-vicut1.dtsi
arch/arm/boot/dts/integratorap-im-pd1.dts
arch/arm/boot/dts/versatile-ab.dts
arch/arm/configs/at91_dt_defconfig
arch/arm/configs/sama7_defconfig
arch/arm/kernel/irq.c
arch/arm/mach-at91/pm.c
arch/arm/mach-at91/pm_suspend.S
arch/arm/mach-ixp4xx/ixp4xx-of.c
arch/arm64/Kconfig
arch/arm64/boot/dts/arm/juno-base.dtsi
arch/arm64/boot/dts/arm/juno-cs-r1r2.dtsi
arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-65bb.dts
arch/arm64/boot/dts/freescale/imx8mm-venice-gw7901.dts
arch/arm64/boot/dts/freescale/imx8mm-verdin.dtsi
arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi
arch/arm64/boot/dts/freescale/imx8mp-venice-gw74xx.dts
arch/arm64/boot/dts/freescale/imx8mp-verdin.dtsi
arch/arm64/boot/dts/freescale/imx8mq-tqma8mq.dtsi
arch/arm64/boot/dts/renesas/r8a779g0.dtsi
arch/arm64/include/asm/cache.h
arch/arm64/include/asm/fpsimd.h
arch/arm64/include/asm/kernel-pgtable.h
arch/arm64/include/asm/kvm_host.h
arch/arm64/include/asm/setup.h
arch/arm64/include/asm/sysreg.h
arch/arm64/include/uapi/asm/kvm.h
arch/arm64/kernel/cacheinfo.c
arch/arm64/kernel/cpu_errata.c
arch/arm64/kernel/cpufeature.c
arch/arm64/kernel/entry.S
arch/arm64/kernel/fpsimd.c
arch/arm64/kernel/head.S
arch/arm64/kernel/machine_kexec_file.c
arch/arm64/kernel/pi/kaslr_early.c
arch/arm64/kernel/ptrace.c
arch/arm64/kernel/signal.c
arch/arm64/kernel/sleep.S
arch/arm64/kernel/topology.c
arch/arm64/kvm/arm.c
arch/arm64/kvm/guest.c
arch/arm64/kvm/mmu.c
arch/arm64/kvm/sys_regs.c
arch/arm64/mm/mmu.c
arch/arm64/tools/cpucaps
arch/hexagon/include/asm/bitops.h
arch/ia64/include/asm/bitops.h
arch/loongarch/Kconfig
arch/loongarch/include/asm/acpi.h
arch/loongarch/include/asm/addrspace.h
arch/loongarch/include/asm/cmpxchg.h
arch/loongarch/include/asm/io.h
arch/loongarch/include/asm/irq.h
arch/loongarch/include/asm/page.h
arch/loongarch/include/asm/percpu.h
arch/loongarch/include/asm/pgtable.h
arch/loongarch/include/asm/reboot.h [deleted file]
arch/loongarch/kernel/acpi.c
arch/loongarch/kernel/reset.c
arch/loongarch/kernel/signal.c
arch/loongarch/kernel/vmlinux.lds.S
arch/loongarch/lib/dump_tlb.c
arch/loongarch/mm/fault.c
arch/loongarch/mm/init.c
arch/loongarch/mm/mmap.c
arch/loongarch/vdso/vgetcpu.c
arch/loongarch/vdso/vgettimeofday.c
arch/m68k/include/asm/bitops.h
arch/mips/Kconfig
arch/mips/cavium-octeon/executive/cvmx-cmd-queue.c
arch/mips/cavium-octeon/octeon-irq.c
arch/mips/cavium-octeon/setup.c
arch/mips/include/asm/kvm_host.h
arch/mips/kvm/mmu.c
arch/mips/lantiq/clk.c
arch/mips/loongson32/common/platform.c
arch/mips/loongson32/ls1c/board.c
arch/nios2/include/asm/entry.h
arch/nios2/include/asm/ptrace.h
arch/nios2/kernel/entry.S
arch/nios2/kernel/signal.c
arch/nios2/kernel/syscall_table.c
arch/parisc/Kconfig
arch/parisc/include/asm/bitops.h
arch/parisc/kernel/head.S
arch/parisc/kernel/irq.c
arch/parisc/kernel/unaligned.c
arch/powerpc/include/asm/firmware.h
arch/powerpc/include/asm/hw_irq.h
arch/powerpc/include/asm/kvm_book3s_64.h
arch/powerpc/kernel/irq.c
arch/powerpc/kernel/pci-common.c
arch/powerpc/kernel/pci_32.c
arch/powerpc/kernel/rtas_entry.S
arch/powerpc/kernel/systbl.S
arch/powerpc/kvm/book3s_64_mmu_host.c
arch/powerpc/kvm/book3s_64_mmu_hv.c
arch/powerpc/kvm/book3s_64_mmu_radix.c
arch/powerpc/kvm/book3s_hv_nested.c
arch/powerpc/kvm/book3s_hv_rm_mmu.c
arch/powerpc/kvm/e500_mmu_host.c
arch/powerpc/platforms/pseries/papr_scm.c
arch/powerpc/platforms/pseries/plpks.c
arch/riscv/boot/dts/microchip/mpfs-icicle-kit.dts
arch/riscv/boot/dts/microchip/mpfs-polarberry.dts
arch/riscv/boot/dts/microchip/mpfs.dtsi
arch/riscv/include/asm/kvm_vcpu_sbi.h
arch/riscv/include/asm/signal.h [new file with mode: 0644]
arch/riscv/include/asm/thread_info.h
arch/riscv/kernel/cpufeature.c
arch/riscv/kernel/signal.c
arch/riscv/kernel/traps.c
arch/riscv/kvm/mmu.c
arch/riscv/kvm/vcpu_sbi.c
arch/riscv/kvm/vcpu_timer.c
arch/riscv/mm/pageattr.c
arch/s390/configs/debug_defconfig
arch/s390/configs/defconfig
arch/s390/configs/zfcpdump_defconfig
arch/s390/hypfs/hypfs_diag.c
arch/s390/hypfs/inode.c
arch/s390/include/asm/bitops.h
arch/s390/include/asm/hugetlb.h
arch/s390/include/asm/kvm_host.h
arch/s390/include/asm/softirq_stack.h
arch/s390/kernel/nmi.c
arch/s390/kernel/process.c
arch/s390/kernel/setup.c
arch/s390/kernel/vmlinux.lds.S
arch/s390/kvm/pci.c
arch/s390/mm/fault.c
arch/s390/pci/Makefile
arch/s390/pci/pci_kvm_hook.c [new file with mode: 0644]
arch/sh/include/asm/bitops-op32.h
arch/sh/kernel/irq.c
arch/sparc/kernel/irq_64.c
arch/um/Makefile
arch/um/drivers/virtio_uml.c
arch/um/include/asm/cpufeature.h
arch/um/kernel/sysrq.c
arch/um/kernel/um_arch.c
arch/x86/Makefile
arch/x86/boot/compressed/misc.h
arch/x86/boot/compressed/sev.c
arch/x86/configs/xen.config
arch/x86/entry/entry_64_compat.S
arch/x86/events/intel/core.c
arch/x86/events/intel/ds.c
arch/x86/events/intel/lbr.c
arch/x86/events/intel/uncore_snb.c
arch/x86/include/asm/bitops.h
arch/x86/include/asm/cpufeature.h
arch/x86/include/asm/cpufeatures.h
arch/x86/include/asm/extable_fixup_types.h
arch/x86/include/asm/ibt.h
arch/x86/include/asm/intel-family.h
arch/x86/include/asm/irq_stack.h
arch/x86/include/asm/kvm_host.h
arch/x86/include/asm/nospec-branch.h
arch/x86/include/asm/rmwcc.h
arch/x86/include/asm/sev.h
arch/x86/include/asm/word-at-a-time.h
arch/x86/kernel/cpu/bugs.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/irq_32.c
arch/x86/kernel/kprobes/core.c
arch/x86/kernel/sev.c
arch/x86/kernel/unwind_orc.c
arch/x86/kvm/emulate.c
arch/x86/kvm/mmu/mmu.c
arch/x86/kvm/mmu/paging_tmpl.h
arch/x86/kvm/mmu/spte.h
arch/x86/kvm/vmx/vmx.c
arch/x86/kvm/x86.c
arch/x86/mm/extable.c
arch/x86/mm/init_64.c
arch/x86/mm/pat/memtype.c
arch/x86/um/shared/sysdep/syscalls_32.h
arch/x86/um/tls_32.c
arch/x86/um/vdso/Makefile
block/blk-core.c
block/blk-lib.c
block/blk-mq-debugfs.c
block/blk-mq.c
block/partitions/core.c
drivers/acpi/processor_thermal.c
drivers/acpi/property.c
drivers/amba/bus.c
drivers/android/binder.c
drivers/android/binder_alloc.c
drivers/ata/libata-eh.c
drivers/base/arch_topology.c
drivers/base/dd.c
drivers/base/driver.c
drivers/base/firmware_loader/sysfs.c
drivers/base/firmware_loader/sysfs.h
drivers/base/firmware_loader/sysfs_upload.c
drivers/base/power/domain.c
drivers/base/regmap/regmap-spi.c
drivers/block/loop.c
drivers/block/ublk_drv.c
drivers/block/xen-blkback/common.h
drivers/block/xen-blkback/xenbus.c
drivers/block/xen-blkfront.c
drivers/block/zram/zram_drv.c
drivers/block/zram/zram_drv.h
drivers/bus/mhi/host/main.c
drivers/char/mem.c
drivers/clk/bcm/clk-raspberrypi.c
drivers/clk/clk.c
drivers/clk/ti/clk.c
drivers/cpufreq/cpufreq.c
drivers/dma-buf/dma-resv.c
drivers/dma/ti/k3-udma-private.c
drivers/dma/xilinx/xilinx_dma.c
drivers/dma/xilinx/zynqmp_dma.c
drivers/firmware/dmi_scan.c
drivers/gpio/gpio-104-dio-48e.c
drivers/gpio/gpio-104-idi-48.c
drivers/gpio/gpio-104-idio-16.c
drivers/gpio/gpio-ftgpio010.c
drivers/gpio/gpio-ixp4xx.c
drivers/gpio/gpio-mockup.c
drivers/gpio/gpio-mpc8xxx.c
drivers/gpio/gpio-mt7621.c
drivers/gpio/gpio-pca953x.c
drivers/gpio/gpio-pxa.c
drivers/gpio/gpio-realtek-otto.c
drivers/gpio/gpio-rockchip.c
drivers/gpio/gpio-tqmx86.c
drivers/gpio/gpio-ws16c48.c
drivers/gpio/gpiolib-cdev.c
drivers/gpu/drm/amd/amdgpu/aldebaran.c
drivers/gpu/drm/amd/amdgpu/amdgpu.h
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c
drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c
drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
drivers/gpu/drm/amd/amdgpu/amdgpu_reset.h
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h
drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c
drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c
drivers/gpu/drm/amd/amdgpu/athub_v3_0.c
drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
drivers/gpu/drm/amd/amdgpu/dce_v8_0.c
drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
drivers/gpu/drm/amd/amdgpu/hdp_v5_2.c
drivers/gpu/drm/amd/amdgpu/ih_v6_0.c
drivers/gpu/drm/amd/amdgpu/mes_v11_0.c
drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c
drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_1.c
drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.c
drivers/gpu/drm/amd/amdgpu/navi10_ih.c
drivers/gpu/drm/amd/amdgpu/nbio_v2_3.c
drivers/gpu/drm/amd/amdgpu/nbio_v6_1.c
drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c
drivers/gpu/drm/amd/amdgpu/nbio_v7_7.c
drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
drivers/gpu/drm/amd/amdgpu/psp_v13_0.c
drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c
drivers/gpu/drm/amd/amdgpu/soc15.c
drivers/gpu/drm/amd/amdgpu/soc21.c
drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
drivers/gpu/drm/amd/amdgpu/vega10_ih.c
drivers/gpu/drm/amd/amdgpu/vega20_ih.c
drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
drivers/gpu/drm/amd/amdkfd/kfd_device.c
drivers/gpu/drm/amd/amdkfd/kfd_events.c
drivers/gpu/drm/amd/amdkfd/kfd_priv.h
drivers/gpu/drm/amd/amdkfd/kfd_svm.c
drivers/gpu/drm/amd/amdkfd/kfd_svm.h
drivers/gpu/drm/amd/amdkfd/kfd_topology.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.h
drivers/gpu/drm/amd/display/dc/basics/conversion.c
drivers/gpu/drm/amd/display/dc/basics/conversion.h
drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.h
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.c
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.h
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_smu.h
drivers/gpu/drm/amd/display/dc/core/dc.c
drivers/gpu/drm/amd/display/dc/core/dc_link.c
drivers/gpu/drm/amd/display/dc/core/dc_resource.c
drivers/gpu/drm/amd/display/dc/core/dc_stream.c
drivers/gpu/drm/amd/display/dc/dc.h
drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
drivers/gpu/drm/amd/display/dc/dc_link.h
drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp.c
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.c
drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hubbub.c
drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c
drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hubp.c
drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c
drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c
drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_stream_encoder.h
drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c
drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.h
drivers/gpu/drm/amd/display/dc/dcn314/Makefile
drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dio_stream_encoder.c
drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c
drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.h
drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c
drivers/gpu/drm/amd/display/dc/dcn314/dcn314_optc.c
drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c
drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.h
drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.h
drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.h
drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dccg.c
drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dio_stream_encoder.c
drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubp.c
drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c
drivers/gpu/drm/amd/display/dc/dcn32/dcn32_optc.c
drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h
drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c
drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c
drivers/gpu/drm/amd/display/dc/dml/Makefile
drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c
drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c
drivers/gpu/drm/amd/display/dc/dml/dcn301/dcn301_fpu.c
drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.c
drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c
drivers/gpu/drm/amd/display/dc/dml/dcn31/display_rq_dlg_calc_31.c
drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c
drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c
drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c
drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.h
drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c
drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.c
drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h
drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h
drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h
drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_dp.c
drivers/gpu/drm/amd/display/include/dal_asic_id.h
drivers/gpu/drm/amd/display/include/logger_types.h
drivers/gpu/drm/amd/display/modules/color/color_gamma.c
drivers/gpu/drm/amd/display/modules/freesync/freesync.c
drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_7_0_offset.h
drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_7_0_sh_mask.h
drivers/gpu/drm/amd/include/mes_v11_api_def.h
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_4.h
drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h
drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_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_4_ppt.c
drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c
drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
drivers/gpu/drm/bridge/lvds-codec.c
drivers/gpu/drm/drm_debugfs.c
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/drm_gem.c
drivers/gpu/drm/drm_internal.h
drivers/gpu/drm/drm_prime.c
drivers/gpu/drm/gma500/cdv_device.c
drivers/gpu/drm/gma500/gem.c
drivers/gpu/drm/gma500/gma_display.c
drivers/gpu/drm/gma500/oaktrail_device.c
drivers/gpu/drm/gma500/power.c
drivers/gpu/drm/gma500/psb_drv.c
drivers/gpu/drm/gma500/psb_drv.h
drivers/gpu/drm/gma500/psb_irq.c
drivers/gpu/drm/gma500/psb_irq.h
drivers/gpu/drm/hyperv/hyperv_drm_drv.c
drivers/gpu/drm/i915/display/icl_dsi.c
drivers/gpu/drm/i915/display/intel_backlight.c
drivers/gpu/drm/i915/display/intel_bios.c
drivers/gpu/drm/i915/display/intel_bw.c
drivers/gpu/drm/i915/display/intel_dp.c
drivers/gpu/drm/i915/display/intel_dp_link_training.c
drivers/gpu/drm/i915/display/intel_quirks.c
drivers/gpu/drm/i915/display/intel_vdsc.c
drivers/gpu/drm/i915/display/vlv_dsi.c
drivers/gpu/drm/i915/gem/i915_gem_object.c
drivers/gpu/drm/i915/gem/i915_gem_object_types.h
drivers/gpu/drm/i915/gem/i915_gem_pages.c
drivers/gpu/drm/i915/gem/i915_gem_ttm.c
drivers/gpu/drm/i915/gt/intel_gt.c
drivers/gpu/drm/i915/gt/intel_gt.h
drivers/gpu/drm/i915/gt/intel_gt_pm.h
drivers/gpu/drm/i915/gt/intel_gt_types.h
drivers/gpu/drm/i915/gt/intel_llc.c
drivers/gpu/drm/i915/gt/intel_migrate.c
drivers/gpu/drm/i915/gt/intel_ppgtt.c
drivers/gpu/drm/i915/gt/intel_region_lmem.c
drivers/gpu/drm/i915/gt/intel_rps.c
drivers/gpu/drm/i915/gt/intel_rps.h
drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
drivers/gpu/drm/i915/gvt/aperture_gm.c
drivers/gpu/drm/i915/gvt/gtt.c
drivers/gpu/drm/i915/gvt/handlers.c
drivers/gpu/drm/i915/gvt/mmio_context.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/i915_vma.c
drivers/gpu/drm/i915/i915_vma.h
drivers/gpu/drm/i915/i915_vma_resource.c
drivers/gpu/drm/i915/i915_vma_resource.h
drivers/gpu/drm/i915/intel_gvt_mmio_table.c
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/imx/dcss/dcss-kms.c
drivers/gpu/drm/meson/meson_drv.c
drivers/gpu/drm/meson/meson_plane.c
drivers/gpu/drm/meson/meson_viu.c
drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
drivers/gpu/drm/msm/dp/dp_ctrl.c
drivers/gpu/drm/msm/dsi/dsi_cfg.c
drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
drivers/gpu/drm/msm/msm_drv.c
drivers/gpu/drm/msm/msm_gpu_devfreq.c
drivers/gpu/drm/msm/msm_rd.c
drivers/gpu/drm/nouveau/nouveau_bo.c
drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
drivers/gpu/drm/panel/panel-edp.c
drivers/gpu/drm/panfrost/panfrost_devfreq.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/rockchip/cdn-dp-core.c
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
drivers/gpu/drm/ttm/ttm_bo.c
drivers/gpu/drm/ttm/ttm_bo_util.c
drivers/gpu/drm/vc4/Kconfig
drivers/gpu/drm/vc4/vc4_hdmi.c
drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
drivers/hid/hid-asus.c
drivers/hid/hid-ids.h
drivers/hid/hid-input.c
drivers/hid/hid-nintendo.c
drivers/hid/hid-quirks.c
drivers/hid/hid-steam.c
drivers/hid/hid-thrustmaster.c
drivers/hid/hidraw.c
drivers/hid/intel-ish-hid/ipc/hw-ish.h
drivers/hid/intel-ish-hid/ipc/pci-ish.c
drivers/hid/intel-ish-hid/ishtp-hid.h
drivers/hid/intel-ish-hid/ishtp/client.c
drivers/hv/hv_fcopy.c
drivers/hv/vmbus_drv.c
drivers/hwmon/asus-ec-sensors.c
drivers/hwmon/gpio-fan.c
drivers/hwmon/mr75203.c
drivers/hwmon/pmbus/pmbus_core.c
drivers/hwmon/tps23861.c
drivers/i2c/busses/i2c-imx.c
drivers/i2c/busses/i2c-scmi.c
drivers/iio/adc/ad7292.c
drivers/iio/adc/mcp3911.c
drivers/iio/light/cm32181.c
drivers/iio/light/cm3605.c
drivers/infiniband/core/cma.c
drivers/infiniband/core/umem_dmabuf.c
drivers/infiniband/core/umem_odp.c
drivers/infiniband/hw/cxgb4/cm.c
drivers/infiniband/hw/erdma/erdma_qp.c
drivers/infiniband/hw/erdma/erdma_verbs.c
drivers/infiniband/hw/hns/hns_roce_device.h
drivers/infiniband/hw/hns/hns_roce_hw_v2.c
drivers/infiniband/hw/hns/hns_roce_hw_v2.h
drivers/infiniband/hw/hns/hns_roce_main.c
drivers/infiniband/hw/hns/hns_roce_qp.c
drivers/infiniband/hw/irdma/uk.c
drivers/infiniband/hw/irdma/utils.c
drivers/infiniband/hw/irdma/verbs.c
drivers/infiniband/hw/mlx5/mad.c
drivers/infiniband/hw/mlx5/main.c
drivers/infiniband/hw/mlx5/mlx5_ib.h
drivers/infiniband/hw/mlx5/umr.c
drivers/infiniband/sw/siw/siw_qp_tx.c
drivers/infiniband/ulp/iser/iser_initiator.c
drivers/infiniband/ulp/rtrs/rtrs-clt.c
drivers/infiniband/ulp/rtrs/rtrs-srv.c
drivers/infiniband/ulp/srp/ib_srp.c
drivers/input/joystick/iforce/iforce-main.c
drivers/input/joystick/iforce/iforce-serio.c
drivers/input/joystick/iforce/iforce-usb.c
drivers/input/joystick/iforce/iforce.h
drivers/input/misc/rk805-pwrkey.c
drivers/input/touchscreen/goodix.c
drivers/iommu/amd/iommu.c
drivers/iommu/amd/iommu_v2.c
drivers/iommu/hyperv-iommu.c
drivers/iommu/intel/iommu.c
drivers/iommu/intel/iommu.h
drivers/iommu/iommu.c
drivers/iommu/of_iommu.c
drivers/iommu/virtio-iommu.c
drivers/irqchip/irq-loongarch-cpu.c
drivers/irqchip/irq-loongson-eiointc.c
drivers/irqchip/irq-loongson-liointc.c
drivers/irqchip/irq-loongson-pch-msi.c
drivers/irqchip/irq-loongson-pch-pic.c
drivers/md/md.c
drivers/md/raid10.c
drivers/media/rc/mceusb.c
drivers/misc/fastrpc.c
drivers/mmc/core/sd.c
drivers/mmc/host/Kconfig
drivers/mmc/host/meson-gx-mmc.c
drivers/mmc/host/mtk-sd.c
drivers/mmc/host/pxamci.c
drivers/mmc/host/sdhci-of-dwcmshc.c
drivers/net/bonding/bond_3ad.c
drivers/net/bonding/bond_main.c
drivers/net/dsa/microchip/ksz9477.c
drivers/net/dsa/microchip/ksz_common.c
drivers/net/dsa/microchip/ksz_common.h
drivers/net/dsa/mv88e6060.c
drivers/net/dsa/ocelot/felix_vsc9959.c
drivers/net/dsa/ocelot/seville_vsc9953.c
drivers/net/dsa/qca/qca8k-8xxx.c
drivers/net/dsa/sja1105/sja1105_devlink.c
drivers/net/dsa/xrs700x/xrs700x.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
drivers/net/ethernet/broadcom/bnxt/bnxt.c
drivers/net/ethernet/broadcom/bnxt/bnxt.h
drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c
drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c
drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c
drivers/net/ethernet/broadcom/tg3.c
drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c
drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
drivers/net/ethernet/cortina/gemini.c
drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
drivers/net/ethernet/freescale/fec.h
drivers/net/ethernet/freescale/fec_main.c
drivers/net/ethernet/freescale/fec_ptp.c
drivers/net/ethernet/fungible/funeth/funeth_txrx.h
drivers/net/ethernet/google/gve/gve_ethtool.c
drivers/net/ethernet/google/gve/gve_main.c
drivers/net/ethernet/huawei/hinic/hinic_rx.c
drivers/net/ethernet/huawei/hinic/hinic_tx.c
drivers/net/ethernet/intel/i40e/i40e_client.c
drivers/net/ethernet/intel/i40e/i40e_ethtool.c
drivers/net/ethernet/intel/i40e/i40e_main.c
drivers/net/ethernet/intel/i40e/i40e_txrx.c
drivers/net/ethernet/intel/iavf/iavf_adminq.c
drivers/net/ethernet/intel/iavf/iavf_main.c
drivers/net/ethernet/intel/ice/ice.h
drivers/net/ethernet/intel/ice/ice_base.c
drivers/net/ethernet/intel/ice/ice_fltr.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_vf_lib.c
drivers/net/ethernet/intel/ice/ice_virtchnl.c
drivers/net/ethernet/intel/ice/ice_xsk.c
drivers/net/ethernet/intel/ice/ice_xsk.h
drivers/net/ethernet/intel/igb/igb.h
drivers/net/ethernet/intel/igb/igb_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
drivers/net/ethernet/lantiq_xrx200.c
drivers/net/ethernet/marvell/mvpp2/mvpp2_debugfs.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/mellanox/mlx5/core/en/tc/act/police.c
drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.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/eswitch_offloads.c
drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
drivers/net/ethernet/mellanox/mlx5/core/main.c
drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c
drivers/net/ethernet/mellanox/mlx5/core/sriov.c
drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h
drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c
drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h
drivers/net/ethernet/mellanox/mlxsw/spectrum.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.h
drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c
drivers/net/ethernet/microchip/lan966x/lan966x_main.c
drivers/net/ethernet/microchip/sparx5/sparx5_packet.c
drivers/net/ethernet/microsoft/mana/gdma_main.c
drivers/net/ethernet/moxa/moxart_ether.c
drivers/net/ethernet/mscc/ocelot.c
drivers/net/ethernet/mscc/ocelot_net.c
drivers/net/ethernet/mscc/ocelot_vsc7514.c
drivers/net/ethernet/mscc/vsc7514_regs.c
drivers/net/ethernet/netronome/nfp/flower/qos_conf.c
drivers/net/ethernet/netronome/nfp/nfp_net_common.c
drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c
drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c
drivers/net/ethernet/pensando/ionic/ionic_lif.c
drivers/net/ethernet/pensando/ionic/ionic_main.c
drivers/net/ethernet/rocker/rocker_ofdpa.c
drivers/net/ethernet/smsc/smsc911x.c
drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/fddi/skfp/h/hwmtm.h
drivers/net/ieee802154/adf7242.c
drivers/net/ieee802154/ca8210.c
drivers/net/ieee802154/cc2520.c
drivers/net/ipa/ipa_mem.c
drivers/net/ipa/ipa_reg.h
drivers/net/ipvlan/ipvtap.c
drivers/net/macsec.c
drivers/net/mdio/fwnode_mdio.c
drivers/net/netdevsim/netdev.c
drivers/net/phy/meson-gxl.c
drivers/net/phy/micrel.c
drivers/net/phy/microchip_t1.c
drivers/net/phy/phy_device.c
drivers/net/usb/cdc_ether.c
drivers/net/usb/qmi_wwan.c
drivers/net/usb/r8152.c
drivers/net/virtio_net.c
drivers/net/wireless/intel/iwlegacy/4965-rs.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c
drivers/net/wireless/microchip/wilc1000/netdev.h
drivers/net/wireless/microchip/wilc1000/sdio.c
drivers/net/wireless/microchip/wilc1000/wlan.c
drivers/net/xen-netback/xenbus.c
drivers/nfc/pn533/uart.c
drivers/nvme/host/core.c
drivers/nvme/host/pci.c
drivers/nvme/host/tcp.c
drivers/nvme/target/auth.c
drivers/nvme/target/core.c
drivers/nvme/target/tcp.c
drivers/nvme/target/zns.c
drivers/of/fdt.c
drivers/parisc/ccio-dma.c
drivers/parisc/iosapic.c
drivers/parisc/led.c
drivers/peci/controller/peci-aspeed.c
drivers/peci/cpu.c
drivers/perf/arm_pmu_platform.c
drivers/perf/riscv_pmu_legacy.c
drivers/perf/riscv_pmu_sbi.c
drivers/pinctrl/pinctrl-ocelot.c
drivers/pinctrl/qcom/pinctrl-sc8180x.c
drivers/pinctrl/sunxi/pinctrl-sun50i-a100-r.c
drivers/platform/mellanox/mlxbf-tmfifo.c
drivers/platform/mellanox/mlxreg-lc.c
drivers/platform/surface/surface_aggregator_registry.c
drivers/platform/x86/acer-wmi.c
drivers/platform/x86/asus-wmi.c
drivers/platform/x86/p2sb.c
drivers/platform/x86/pmc_atom.c
drivers/platform/x86/serial-multi-instantiate.c
drivers/platform/x86/thinkpad_acpi.c
drivers/platform/x86/x86-android-tablets.c
drivers/regulator/core.c
drivers/regulator/pfuze100-regulator.c
drivers/remoteproc/remoteproc_virtio.c
drivers/s390/crypto/ap_bus.c
drivers/s390/crypto/ap_bus.h
drivers/s390/virtio/virtio_ccw.c
drivers/scsi/hosts.c
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_scsi.c
drivers/scsi/megaraid/megaraid_sas_base.c
drivers/scsi/megaraid/megaraid_sas_fusion.c
drivers/scsi/mpt3sas/mpt3sas_scsih.c
drivers/scsi/qla2xxx/qla_target.c
drivers/scsi/scsi.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_priv.h
drivers/scsi/scsi_scan.c
drivers/scsi/scsi_sysfs.c
drivers/scsi/sd.c
drivers/scsi/sd.h
drivers/scsi/storvsc_drv.c
drivers/soc/bcm/brcmstb/pm/pm-arm.c
drivers/soc/fsl/Kconfig
drivers/soc/imx/gpcv2.c
drivers/soc/imx/imx8m-blk-ctrl.c
drivers/soundwire/qcom.c
drivers/spi/spi-bitbang-txrx.h
drivers/spi/spi-cadence-quadspi.c
drivers/spi/spi-meson-spicc.c
drivers/spi/spi-mux.c
drivers/spi/spi.c
drivers/staging/r8188eu/os_dep/os_intfs.c
drivers/staging/r8188eu/os_dep/usb_intf.c
drivers/staging/rtl8712/rtl8712_cmd.c
drivers/tee/tee_shm.c
drivers/thermal/intel/int340x_thermal/int3400_thermal.c
drivers/thermal/thermal_core.c
drivers/thunderbolt/Kconfig
drivers/thunderbolt/ctl.c
drivers/thunderbolt/switch.c
drivers/tty/n_gsm.c
drivers/tty/serial/atmel_serial.c
drivers/tty/serial/fsl_lpuart.c
drivers/tty/tty_buffer.c
drivers/tty/vt/vt.c
drivers/ufs/core/ufshcd.c
drivers/ufs/host/ufs-exynos.c
drivers/usb/cdns3/cdns3-gadget.c
drivers/usb/class/cdc-acm.c
drivers/usb/core/hub.c
drivers/usb/dwc2/platform.c
drivers/usb/dwc3/core.c
drivers/usb/dwc3/dwc3-pci.c
drivers/usb/dwc3/dwc3-qcom.c
drivers/usb/dwc3/gadget.c
drivers/usb/dwc3/host.c
drivers/usb/gadget/function/f_uac2.c
drivers/usb/gadget/function/storage_common.c
drivers/usb/gadget/udc/core.c
drivers/usb/host/xhci-hub.c
drivers/usb/host/xhci-mtk-sch.c
drivers/usb/host/xhci-plat.c
drivers/usb/host/xhci.c
drivers/usb/host/xhci.h
drivers/usb/misc/onboard_usb_hub.c
drivers/usb/musb/Kconfig
drivers/usb/serial/ch341.c
drivers/usb/serial/cp210x.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio_ids.h
drivers/usb/serial/option.c
drivers/usb/storage/unusual_devs.h
drivers/usb/storage/unusual_uas.h
drivers/usb/typec/altmodes/displayport.c
drivers/usb/typec/class.c
drivers/usb/typec/mux/intel_pmc_mux.c
drivers/usb/typec/tcpm/tcpm.c
drivers/usb/typec/ucsi/ucsi.c
drivers/vfio/pci/vfio_pci_zdev.c
drivers/vfio/vfio_iommu_type1.c
drivers/video/console/sticore.c
drivers/video/fbdev/aty/atyfb_base.c
drivers/video/fbdev/aty/radeon_base.c
drivers/video/fbdev/bw2.c
drivers/video/fbdev/chipsfb.c
drivers/video/fbdev/cirrusfb.c
drivers/video/fbdev/clps711x-fb.c
drivers/video/fbdev/core/fbcon.c
drivers/video/fbdev/core/fbsysfs.c
drivers/video/fbdev/cyber2000fb.c
drivers/video/fbdev/ffb.c
drivers/video/fbdev/geode/gx1fb_core.c
drivers/video/fbdev/gxt4500.c
drivers/video/fbdev/hyperv_fb.c
drivers/video/fbdev/i740fb.c
drivers/video/fbdev/imxfb.c
drivers/video/fbdev/matrox/matroxfb_base.c
drivers/video/fbdev/omap/omapfb_main.c
drivers/video/fbdev/omap2/omapfb/omapfb-main.c
drivers/video/fbdev/pm2fb.c
drivers/video/fbdev/pxa168fb.c
drivers/video/fbdev/pxafb.c
drivers/video/fbdev/s3fb.c
drivers/video/fbdev/simplefb.c
drivers/video/fbdev/sis/sis_main.c
drivers/video/fbdev/sm501fb.c
drivers/video/fbdev/ssd1307fb.c
drivers/video/fbdev/sstfb.c
drivers/video/fbdev/sunxvr1000.c
drivers/video/fbdev/sunxvr2500.c
drivers/video/fbdev/sunxvr500.c
drivers/video/fbdev/tcx.c
drivers/video/fbdev/tdfxfb.c
drivers/video/fbdev/tgafb.c
drivers/video/fbdev/tridentfb.c
drivers/virt/nitro_enclaves/Kconfig
drivers/virtio/virtio_mmio.c
drivers/virtio/virtio_pci_common.c
drivers/virtio/virtio_pci_common.h
drivers/virtio/virtio_pci_legacy.c
drivers/virtio/virtio_pci_modern.c
drivers/virtio/virtio_ring.c
drivers/virtio/virtio_vdpa.c
drivers/xen/grant-table.c
drivers/xen/privcmd.c
drivers/xen/xen-scsiback.c
drivers/xen/xenbus/xenbus_probe_frontend.c
fs/afs/flock.c
fs/afs/fsclient.c
fs/afs/internal.h
fs/afs/misc.c
fs/afs/rxrpc.c
fs/afs/yfsclient.c
fs/btrfs/block-group.c
fs/btrfs/block-group.h
fs/btrfs/ctree.c
fs/btrfs/ctree.h
fs/btrfs/dev-replace.c
fs/btrfs/disk-io.c
fs/btrfs/disk-io.h
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/file.c
fs/btrfs/inode.c
fs/btrfs/locking.c
fs/btrfs/locking.h
fs/btrfs/relocation.c
fs/btrfs/root-tree.c
fs/btrfs/space-info.c
fs/btrfs/tree-checker.c
fs/btrfs/tree-log.c
fs/btrfs/volumes.c
fs/btrfs/xattr.c
fs/btrfs/zoned.c
fs/cachefiles/internal.h
fs/cachefiles/ondemand.c
fs/cifs/cifs_debug.c
fs/cifs/cifsencrypt.c
fs/cifs/cifsfs.c
fs/cifs/cifsfs.h
fs/cifs/cifsglob.h
fs/cifs/cifsproto.h
fs/cifs/cifsroot.c
fs/cifs/connect.c
fs/cifs/file.c
fs/cifs/misc.c
fs/cifs/netmisc.c
fs/cifs/readdir.c
fs/cifs/smb2file.c
fs/cifs/smb2misc.c
fs/cifs/smb2ops.c
fs/cifs/smb2pdu.c
fs/cifs/smb2proto.h
fs/cifs/transport.c
fs/dcache.c
fs/debugfs/inode.c
fs/erofs/fscache.c
fs/erofs/internal.h
fs/erofs/zmap.c
fs/exec.c
fs/exfat/fatent.c
fs/fs-writeback.c
fs/inode.c
fs/ksmbd/ksmbd_netlink.h
fs/ksmbd/mgmt/share_config.c
fs/ksmbd/mgmt/share_config.h
fs/ksmbd/mgmt/tree_connect.c
fs/ksmbd/smb2pdu.c
fs/locks.c
fs/namespace.c
fs/nfs/dir.c
fs/nfs/file.c
fs/nfs/inode.c
fs/nfs/internal.h
fs/nfs/nfs42proc.c
fs/nfs/nfs4file.c
fs/nfs/pnfs.c
fs/nfs/super.c
fs/nfs/write.c
fs/nfsd/vfs.c
fs/ntfs3/attrib.c
fs/ntfs3/bitmap.c
fs/ntfs3/file.c
fs/ntfs3/frecord.c
fs/ntfs3/fslog.c
fs/ntfs3/fsntfs.c
fs/ntfs3/index.c
fs/ntfs3/inode.c
fs/ntfs3/namei.c
fs/ntfs3/ntfs_fs.h
fs/ntfs3/record.c
fs/ntfs3/run.c
fs/ntfs3/super.c
fs/ntfs3/xattr.c
fs/ocfs2/dlmglue.c
fs/ocfs2/super.c
fs/open.c
fs/overlayfs/inode.c
fs/posix_acl.c
fs/proc/task_mmu.c
fs/squashfs/file.c
fs/squashfs/file_direct.c
fs/squashfs/page_actor.c
fs/squashfs/page_actor.h
fs/tracefs/inode.c
fs/userfaultfd.c
include/asm-generic/bitops/atomic.h
include/asm-generic/bitops/generic-non-atomic.h
include/asm-generic/bitops/instrumented-non-atomic.h
include/asm-generic/bitops/non-atomic.h
include/asm-generic/bitops/non-instrumented-non-atomic.h
include/asm-generic/sections.h
include/asm-generic/softirq_stack.h
include/drm/drm_connector.h
include/drm/drm_edid.h
include/kunit/test.h
include/linux/amba/bus.h
include/linux/bitops.h
include/linux/blk-mq.h
include/linux/buffer_head.h
include/linux/cgroup.h
include/linux/compiler.h
include/linux/cpumask.h
include/linux/debugfs.h
include/linux/device/driver.h
include/linux/dma-mapping.h
include/linux/fscache.h
include/linux/hp_sdc.h
include/linux/ieee80211.h
include/linux/kvm_host.h
include/linux/libata.h
include/linux/lsm_hook_defs.h
include/linux/lsm_hooks.h
include/linux/memcontrol.h
include/linux/mlx5/driver.h
include/linux/mm.h
include/linux/netdevice.h
include/linux/netfilter_bridge/ebtables.h
include/linux/nfs_fs.h
include/linux/of_device.h
include/linux/overflow.h
include/linux/pci_ids.h
include/linux/platform_data/x86/pmc_atom.h
include/linux/psi.h
include/linux/rmap.h
include/linux/security.h
include/linux/serial_core.h
include/linux/shmem_fs.h
include/linux/skbuff.h
include/linux/spi/spi.h
include/linux/trace_events.h
include/linux/udp.h
include/linux/usb.h
include/linux/usb/typec_dp.h
include/linux/userfaultfd_k.h
include/linux/virtio.h
include/linux/virtio_config.h
include/linux/vm_event_item.h
include/linux/wait_bit.h
include/net/af_rxrpc.h
include/net/bond_3ad.h
include/net/busy_poll.h
include/net/dropreason.h
include/net/gro.h
include/net/ip_tunnels.h
include/net/neighbour.h
include/net/netfilter/nf_conntrack.h
include/net/netfilter/nf_flow_table.h
include/net/netfilter/nf_tables.h
include/net/netns/conntrack.h
include/net/netns/ipv4.h
include/net/sock.h
include/net/udp_tunnel.h
include/scsi/scsi_device.h
include/scsi/scsi_host.h
include/soc/at91/sama7-ddr.h
include/soc/mscc/ocelot.h
include/trace/events/skb.h
include/uapi/linux/bpf.h
include/uapi/linux/io_uring.h
include/uapi/linux/virtio_net.h
include/uapi/linux/virtio_ring.h
include/uapi/linux/xfrm.h
include/ufs/ufshci.h
init/Kconfig
init/main.c
io_uring/cancel.c
io_uring/io_uring.c
io_uring/kbuf.h
io_uring/msg_ring.c
io_uring/net.c
io_uring/net.h
io_uring/notif.c
io_uring/notif.h
io_uring/opdef.c
io_uring/opdef.h
io_uring/rsrc.c
io_uring/rsrc.h
io_uring/rw.c
io_uring/uring_cmd.c
kernel/audit_fsnotify.c
kernel/auditsc.c
kernel/bpf/cgroup.c
kernel/bpf/core.c
kernel/bpf/reuseport_array.c
kernel/bpf/syscall.c
kernel/bpf/verifier.c
kernel/cgroup/cgroup-v1.c
kernel/cgroup/cgroup.c
kernel/cgroup/cpuset.c
kernel/crash_core.c
kernel/dma/debug.c
kernel/dma/mapping.c
kernel/dma/swiotlb.c
kernel/fork.c
kernel/kprobes.c
kernel/module/main.c
kernel/nsproxy.c
kernel/sched/debug.c
kernel/sched/psi.c
kernel/sched/wait_bit.c
kernel/sys_ni.c
kernel/trace/ftrace.c
kernel/trace/rv/monitors/wip/wip.h
kernel/trace/rv/monitors/wwnr/wwnr.h
kernel/trace/rv/reactor_panic.c
kernel/trace/rv/reactor_printk.c
kernel/trace/trace_eprobe.c
kernel/trace/trace_event_perf.c
kernel/trace/trace_events.c
kernel/trace/trace_events_trigger.c
kernel/trace/trace_preemptirq.c
kernel/trace/trace_probe.c
kernel/tracepoint.c
lib/Kconfig.debug
lib/Makefile
lib/cpumask.c
lib/cpumask_kunit.c [moved from lib/test_cpumask.c with 58% similarity]
lib/crypto/Kconfig
lib/ratelimit.c
mm/backing-dev.c
mm/bootmem_info.c
mm/damon/dbgfs.c
mm/gup.c
mm/huge_memory.c
mm/hugetlb.c
mm/mmap.c
mm/mprotect.c
mm/page-writeback.c
mm/pagewalk.c
mm/ptdump.c
mm/rmap.c
mm/shmem.c
mm/slab_common.c
mm/userfaultfd.c
mm/vmstat.c
mm/zsmalloc.c
net/bluetooth/hci_event.c
net/bluetooth/hci_sync.c
net/bluetooth/hidp/core.c
net/bluetooth/iso.c
net/bluetooth/l2cap_core.c
net/bluetooth/mgmt.c
net/bridge/br_netfilter_hooks.c
net/bridge/br_netfilter_ipv6.c
net/bridge/netfilter/ebtable_broute.c
net/bridge/netfilter/ebtable_filter.c
net/bridge/netfilter/ebtable_nat.c
net/bridge/netfilter/ebtables.c
net/core/.gitignore [deleted file]
net/core/Makefile
net/core/bpf_sk_storage.c
net/core/datagram.c
net/core/dev.c
net/core/filter.c
net/core/gen_stats.c
net/core/gro_cells.c
net/core/neighbour.c
net/core/rtnetlink.c
net/core/skbuff.c
net/core/skmsg.c
net/core/sock.c
net/core/sysctl_net_core.c
net/dsa/port.c
net/dsa/slave.c
net/dsa/tag_hellcreek.c
net/ipv4/devinet.c
net/ipv4/fib_frontend.c
net/ipv4/ip_gre.c
net/ipv4/ip_output.c
net/ipv4/ip_sockglue.c
net/ipv4/ip_tunnel.c
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_output.c
net/ipv4/udp.c
net/ipv4/udp_tunnel_core.c
net/ipv6/addrconf.c
net/ipv6/ip6_tunnel.c
net/ipv6/ipv6_sockglue.c
net/ipv6/ndisc.c
net/ipv6/netfilter/nf_conntrack_reasm.c
net/ipv6/seg6.c
net/ipv6/udp.c
net/kcm/kcmsock.c
net/key/af_key.c
net/mac80211/ibss.c
net/mac80211/mlme.c
net/mac80211/rx.c
net/mac80211/scan.c
net/mac80211/sta_info.c
net/mac80211/tx.c
net/mac80211/wpa.c
net/mac802154/rx.c
net/mpls/af_mpls.c
net/mptcp/protocol.c
net/netfilter/Kconfig
net/netfilter/ipvs/ip_vs_sync.c
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_ftp.c
net/netfilter/nf_conntrack_h323_main.c
net/netfilter/nf_conntrack_helper.c
net/netfilter/nf_conntrack_irc.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_conntrack_proto_tcp.c
net/netfilter/nf_conntrack_sane.c
net/netfilter/nf_conntrack_standalone.c
net/netfilter/nf_flow_table_core.c
net/netfilter/nf_flow_table_offload.c
net/netfilter/nf_tables_api.c
net/netfilter/nfnetlink.c
net/netfilter/nft_ct.c
net/netfilter/nft_osf.c
net/netfilter/nft_payload.c
net/netfilter/nft_tproxy.c
net/netfilter/nft_tunnel.c
net/netlink/genetlink.c
net/netlink/policy.c
net/openvswitch/datapath.c
net/qrtr/mhi.c
net/rds/ib_recv.c
net/rose/rose_loopback.c
net/rxrpc/ar-internal.h
net/rxrpc/call_event.c
net/rxrpc/call_object.c
net/rxrpc/local_object.c
net/rxrpc/peer_event.c
net/rxrpc/recvmsg.c
net/rxrpc/rxkad.c
net/rxrpc/sendmsg.c
net/sched/cls_route.c
net/sched/sch_generic.c
net/sched/sch_sfb.c
net/sched/sch_tbf.c
net/smc/af_smc.c
net/smc/smc_core.c
net/smc/smc_core.h
net/smc/smc_wr.c
net/smc/smc_wr.h
net/socket.c
net/sunrpc/clnt.c
net/sunrpc/sysfs.c
net/sunrpc/xprt.c
net/tipc/monitor.c
net/tls/tls_sw.c
net/wireless/debugfs.c
net/wireless/lib80211_crypt_ccmp.c
net/xdp/xsk_buff_pool.c
net/xfrm/espintcp.c
net/xfrm/xfrm_input.c
net/xfrm/xfrm_output.c
net/xfrm/xfrm_policy.c
net/xfrm/xfrm_state.c
scripts/Makefile.extrawarn
scripts/Makefile.gcc-plugins
scripts/clang-tools/run-clang-tools.py
scripts/dummy-tools/gcc
scripts/extract-ikconfig
scripts/gcc-goto.sh [deleted file]
scripts/gcc-ld [deleted file]
scripts/mksysmap
scripts/mod/modpost.c
security/landlock/fs.c
security/loadpin/loadpin.c
security/security.c
security/selinux/hooks.c
security/selinux/include/classmap.h
security/smack/smack_lsm.c
sound/core/control.c
sound/core/info.c
sound/core/init.c
sound/core/memalloc.c
sound/core/oss/pcm_oss.c
sound/core/seq/oss/seq_oss_midi.c
sound/core/seq/seq_clientmgr.c
sound/drivers/aloop.c
sound/hda/intel-nhlt.c
sound/pci/emu10k1/emupcm.c
sound/pci/hda/cs35l41_hda.c
sound/pci/hda/hda_bind.c
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_tegra.c
sound/pci/hda/patch_cs8409-tables.c
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/soc/amd/yc/acp6x-mach.c
sound/soc/atmel/mchp-spdiftx.c
sound/soc/codecs/cs42l42.c
sound/soc/codecs/nau8540.c
sound/soc/codecs/nau8821.c
sound/soc/codecs/nau8824.c
sound/soc/codecs/nau8825.c
sound/soc/codecs/rt5640.c
sound/soc/codecs/tas2770.c
sound/soc/codecs/tas2770.h
sound/soc/codecs/tlv320aic32x4.c
sound/soc/fsl/fsl_aud2htx.c
sound/soc/fsl/fsl_mqs.c
sound/soc/fsl/fsl_sai.c
sound/soc/intel/avs/pcm.c
sound/soc/intel/boards/sof_es8336.c
sound/soc/mediatek/mt8186/mt8186-dai-adda.c
sound/soc/qcom/sm8250.c
sound/soc/sh/rz-ssi.c
sound/soc/soc-pcm.c
sound/soc/sof/Kconfig
sound/soc/sof/debug.c
sound/soc/sof/intel/hda.c
sound/soc/sof/ipc3-topology.c
sound/soc/sof/ipc4-topology.c
sound/usb/card.c
sound/usb/endpoint.c
sound/usb/quirks.c
sound/usb/stream.c
tools/arch/arm64/include/uapi/asm/kvm.h
tools/arch/s390/include/uapi/asm/kvm.h
tools/arch/x86/include/asm/cpufeatures.h
tools/arch/x86/include/asm/msr-index.h
tools/arch/x86/include/asm/rmwcc.h
tools/arch/x86/include/uapi/asm/kvm.h
tools/arch/x86/include/uapi/asm/vmx.h
tools/debugging/kernel-chktaint
tools/hv/hv_kvp_daemon.c
tools/include/linux/compiler_types.h
tools/include/uapi/asm/errno.h
tools/include/uapi/drm/i915_drm.h
tools/include/uapi/linux/fscrypt.h
tools/include/uapi/linux/kvm.h
tools/include/uapi/linux/perf_event.h
tools/include/uapi/linux/vhost.h
tools/lib/perf/cpumap.c
tools/lib/perf/evlist.c
tools/lib/perf/evsel.c
tools/lib/perf/include/perf/cpumap.h
tools/lib/perf/include/perf/event.h
tools/lib/perf/include/perf/evsel.h
tools/lib/perf/tests/test-evsel.c
tools/objtool/check.c
tools/perf/Documentation/intel-hybrid.txt
tools/perf/Documentation/perf-record.txt
tools/perf/Makefile.config
tools/perf/Makefile.perf
tools/perf/builtin-c2c.c
tools/perf/builtin-lock.c
tools/perf/builtin-record.c
tools/perf/builtin-sched.c
tools/perf/builtin-script.c
tools/perf/builtin-stat.c
tools/perf/dlfilters/dlfilter-show-cycles.c
tools/perf/tests/cpumap.c
tools/perf/tests/sample-parsing.c
tools/perf/tests/shell/stat.sh
tools/perf/tests/shell/stat_bpf_counters_cgrp.sh [new file with mode: 0755]
tools/perf/tests/wp.c
tools/perf/trace/beauty/include/linux/socket.h
tools/perf/util/affinity.c
tools/perf/util/bpf_counter_cgroup.c
tools/perf/util/bpf_skel/bperf_cgroup.bpf.c
tools/perf/util/cpumap.c
tools/perf/util/cpumap.h
tools/perf/util/event.h
tools/perf/util/evsel.c
tools/perf/util/genelf.c
tools/perf/util/genelf.h
tools/perf/util/metricgroup.c
tools/perf/util/scripting-engines/trace-event-python.c
tools/perf/util/session.c
tools/perf/util/stat-shadow.c
tools/perf/util/symbol-elf.c
tools/perf/util/synthetic-events.c
tools/perf/util/synthetic-events.h
tools/testing/selftests/Makefile
tools/testing/selftests/bpf/DENYLIST.s390x
tools/testing/selftests/bpf/verifier/precise.c
tools/testing/selftests/drivers/net/bonding/Makefile [new file with mode: 0644]
tools/testing/selftests/drivers/net/bonding/bond-break-lacpdu-tx.sh [new file with mode: 0755]
tools/testing/selftests/drivers/net/bonding/config [new file with mode: 0644]
tools/testing/selftests/drivers/net/bonding/settings [new file with mode: 0644]
tools/testing/selftests/kvm/include/x86_64/processor.h
tools/testing/selftests/landlock/Makefile
tools/testing/selftests/landlock/fs_test.c
tools/testing/selftests/lib.mk
tools/testing/selftests/net/.gitignore
tools/testing/selftests/net/io_uring_zerocopy_tx.c
tools/testing/selftests/net/io_uring_zerocopy_tx.sh
tools/testing/selftests/netfilter/nft_conntrack_helper.sh
tools/testing/selftests/netfilter/nft_flowtable.sh
tools/testing/selftests/powerpc/pmu/event_code_tests/.gitignore [new file with mode: 0644]
tools/testing/selftests/powerpc/pmu/sampling_tests/.gitignore
tools/testing/selftests/sgx/sigstruct.c
tools/testing/selftests/timens/Makefile
tools/testing/selftests/timens/vfork_exec.c [deleted file]
tools/tracing/rtla/Makefile
tools/tracing/rtla/src/timerlat_hist.c
tools/tracing/rtla/src/timerlat_top.c
virt/kvm/kvm_main.c
virt/kvm/pfncache.c

index a64d219..c298bab 100644 (file)
@@ -1,2 +1,4 @@
+Alan Cox <alan@lxorguk.ukuu.org.uk>
+Alan Cox <root@hraefn.swansea.linux.org.uk>
 Christoph Hellwig <hch@lst.de>
 Marc Gonzalez <marc.w.gonzalez@free.fr>
index 38255d4..d175777 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -98,8 +98,7 @@ Christian Brauner <brauner@kernel.org> <christian.brauner@ubuntu.com>
 Christian Marangi <ansuelsmth@gmail.com>
 Christophe Ricard <christophe.ricard@gmail.com>
 Christoph Hellwig <hch@lst.de>
-Colin Ian King <colin.king@intel.com> <colin.king@canonical.com>
-Colin Ian King <colin.king@intel.com> <colin.i.king@gmail.com>
+Colin Ian King <colin.i.king@gmail.com> <colin.king@canonical.com>
 Corey Minyard <minyard@acm.org>
 Damian Hobson-Garcia <dhobsong@igel.co.jp>
 Daniel Borkmann <daniel@iogearbox.net> <danborkmann@googlemail.com>
@@ -150,6 +149,8 @@ Greg Kroah-Hartman <gregkh@suse.de>
 Greg Kroah-Hartman <greg@kroah.com>
 Greg Kurz <groug@kaod.org> <gkurz@linux.vnet.ibm.com>
 Gregory CLEMENT <gregory.clement@bootlin.com> <gregory.clement@free-electrons.com>
+Guilherme G. Piccoli <kernel@gpiccoli.net> <gpiccoli@linux.vnet.ibm.com>
+Guilherme G. Piccoli <kernel@gpiccoli.net> <gpiccoli@canonical.com>
 Guo Ren <guoren@kernel.org> <guoren@linux.alibaba.com>
 Guo Ren <guoren@kernel.org> <ren_guo@c-sky.com>
 Gustavo Padovan <gustavo@las.ic.unicamp.br>
@@ -253,6 +254,7 @@ Linus Lüssing <linus.luessing@c0d3.blue> <linus.luessing@web.de>
 Li Yang <leoyang.li@nxp.com> <leoli@freescale.com>
 Li Yang <leoyang.li@nxp.com> <leo@zh-kernel.org>
 Lorenzo Pieralisi <lpieralisi@kernel.org> <lorenzo.pieralisi@arm.com>
+Luca Ceresoli <luca.ceresoli@bootlin.com> <luca@lucaceresoli.net>
 Lukasz Luba <lukasz.luba@arm.com> <l.luba@partner.samsung.com>
 Maciej W. Rozycki <macro@mips.com> <macro@imgtec.com>
 Maciej W. Rozycki <macro@orcam.me.uk> <macro@linux-mips.org>
@@ -313,6 +315,7 @@ Morten Welinder <welinder@troll.com>
 Mythri P K <mythripk@ti.com>
 Nadia Yvette Chambers <nyc@holomorphy.com> William Lee Irwin III <wli@holomorphy.com>
 Nathan Chancellor <nathan@kernel.org> <natechancellor@gmail.com>
+Neil Armstrong <neil.armstrong@linaro.org> <narmstrong@baylibre.com>
 Nguyen Anh Quynh <aquynh@gmail.com>
 Nicholas Piggin <npiggin@gmail.com> <npiggen@suse.de>
 Nicholas Piggin <npiggin@gmail.com> <npiggin@kernel.dk>
index 5bf6188..760c889 100644 (file)
@@ -523,6 +523,7 @@ What:               /sys/devices/system/cpu/vulnerabilities
                /sys/devices/system/cpu/vulnerabilities/tsx_async_abort
                /sys/devices/system/cpu/vulnerabilities/itlb_multihit
                /sys/devices/system/cpu/vulnerabilities/mmio_stale_data
+               /sys/devices/system/cpu/vulnerabilities/retbleed
 Date:          January 2018
 Contact:       Linux kernel mailing list <linux-kernel@vger.kernel.org>
 Description:   Information about CPU vulnerabilities
index caa3c09..9eb6b90 100644 (file)
@@ -1,9 +1,9 @@
 .. _readme:
 
-Linux kernel release 5.x <http://kernel.org/>
+Linux kernel release 6.x <http://kernel.org/>
 =============================================
 
-These are the release notes for Linux version 5.  Read them carefully,
+These are the release notes for Linux version 6.  Read them carefully,
 as they tell you what this is all about, explain how to install the
 kernel, and what to do if something goes wrong.
 
@@ -63,7 +63,7 @@ Installing the kernel source
    directory where you have permissions (e.g. your home directory) and
    unpack it::
 
-     xz -cd linux-5.x.tar.xz | tar xvf -
+     xz -cd linux-6.x.tar.xz | tar xvf -
 
    Replace "X" with the version number of the latest kernel.
 
@@ -72,12 +72,12 @@ Installing the kernel source
    files.  They should match the library, and not get messed up by
    whatever the kernel-du-jour happens to be.
 
- - You can also upgrade between 5.x releases by patching.  Patches are
+ - You can also upgrade between 6.x releases by patching.  Patches are
    distributed in the xz format.  To install by patching, get all the
    newer patch files, enter the top level directory of the kernel source
-   (linux-5.x) and execute::
+   (linux-6.x) and execute::
 
-     xz -cd ../patch-5.x.xz | patch -p1
+     xz -cd ../patch-6.x.xz | patch -p1
 
    Replace "x" for all versions bigger than the version "x" of your current
    source tree, **in_order**, and you should be ok.  You may want to remove
@@ -85,13 +85,13 @@ Installing the kernel source
    that there are no failed patches (some-file-name# or some-file-name.rej).
    If there are, either you or I have made a mistake.
 
-   Unlike patches for the 5.x kernels, patches for the 5.x.y kernels
+   Unlike patches for the 6.x kernels, patches for the 6.x.y kernels
    (also known as the -stable kernels) are not incremental but instead apply
-   directly to the base 5.x kernel.  For example, if your base kernel is 5.0
-   and you want to apply the 5.0.3 patch, you must not first apply the 5.0.1
-   and 5.0.2 patches. Similarly, if you are running kernel version 5.0.2 and
-   want to jump to 5.0.3, you must first reverse the 5.0.2 patch (that is,
-   patch -R) **before** applying the 5.0.3 patch. You can read more on this in
+   directly to the base 6.x kernel.  For example, if your base kernel is 6.0
+   and you want to apply the 6.0.3 patch, you must not first apply the 6.0.1
+   and 6.0.2 patches. Similarly, if you are running kernel version 6.0.2 and
+   want to jump to 6.0.3, you must first reverse the 6.0.2 patch (that is,
+   patch -R) **before** applying the 6.0.3 patch. You can read more on this in
    :ref:`Documentation/process/applying-patches.rst <applying_patches>`.
 
    Alternatively, the script patch-kernel can be used to automate this
@@ -114,7 +114,7 @@ Installing the kernel source
 Software requirements
 ---------------------
 
-   Compiling and running the 5.x kernels requires up-to-date
+   Compiling and running the 6.x kernels requires up-to-date
    versions of various software packages.  Consult
    :ref:`Documentation/process/changes.rst <changes>` for the minimum version numbers
    required and how to get updates for these packages.  Beware that using
@@ -132,12 +132,12 @@ Build directory for the kernel
    place for the output files (including .config).
    Example::
 
-     kernel source code: /usr/src/linux-5.x
+     kernel source code: /usr/src/linux-6.x
      build directory:    /home/name/build/kernel
 
    To configure and build the kernel, use::
 
-     cd /usr/src/linux-5.x
+     cd /usr/src/linux-6.x
      make O=/home/name/build/kernel menuconfig
      make O=/home/name/build/kernel
      sudo make O=/home/name/build/kernel modules_install install
index 9393c50..c98fd11 100644 (file)
@@ -230,6 +230,20 @@ The possible values in this file are:
      * - 'Mitigation: Clear CPU buffers'
        - The processor is vulnerable and the CPU buffer clearing mitigation is
          enabled.
+     * - 'Unknown: No mitigations'
+       - The processor vulnerability status is unknown because it is
+        out of Servicing period. Mitigation is not attempted.
+
+Definitions:
+------------
+
+Servicing period: The process of providing functional and security updates to
+Intel processors or platforms, utilizing the Intel Platform Update (IPU)
+process or other similar mechanisms.
+
+End of Servicing Updates (ESU): ESU is the date at which Intel will no
+longer provide Servicing, such as through IPU or other similar update
+processes. ESU dates will typically be aligned to end of quarter.
 
 If the processor is vulnerable then the following information is appended to
 the above information:
index d7f3090..426fa89 100644 (file)
        rodata=         [KNL]
                on      Mark read-only kernel memory as read-only (default).
                off     Leave read-only kernel memory writable for debugging.
+               full    Mark read-only kernel memory and aliases as read-only
+                       [arm64]
 
        rockchip.usb_uart
                        Enable the uart passthrough on the designated usb port
index d52f572..ca91ecc 100644 (file)
@@ -50,10 +50,10 @@ For a short example, users can monitor the virtual address space of a given
 workload as below. ::
 
     # cd /sys/kernel/mm/damon/admin/
-    # echo 1 > kdamonds/nr && echo 1 > kdamonds/0/contexts/nr
+    # echo 1 > kdamonds/nr_kdamonds && echo 1 > kdamonds/0/contexts/nr_contexts
     # echo vaddr > kdamonds/0/contexts/0/operations
-    # echo 1 > kdamonds/0/contexts/0/targets/nr
-    # echo $(pidof <workload>) > kdamonds/0/contexts/0/targets/0/pid
+    # echo 1 > kdamonds/0/contexts/0/targets/nr_targets
+    # echo $(pidof <workload>) > kdamonds/0/contexts/0/targets/0/pid_target
     # echo on > kdamonds/0/state
 
 Files Hierarchy
@@ -366,12 +366,12 @@ memory rate becomes larger than 60%, or lower than 30%". ::
     # echo 1 > kdamonds/0/contexts/0/schemes/nr_schemes
     # cd kdamonds/0/contexts/0/schemes/0
     # # set the basic access pattern and the action
-    # echo 4096 > access_patterns/sz/min
-    # echo 8192 > access_patterns/sz/max
-    # echo 0 > access_patterns/nr_accesses/min
-    # echo 5 > access_patterns/nr_accesses/max
-    # echo 10 > access_patterns/age/min
-    # echo 20 > access_patterns/age/max
+    # echo 4096 > access_pattern/sz/min
+    # echo 8192 > access_pattern/sz/max
+    # echo 0 > access_pattern/nr_accesses/min
+    # echo 5 > access_pattern/nr_accesses/max
+    # echo 10 > access_pattern/age/min
+    # echo 20 > access_pattern/age/max
     # echo pageout > action
     # # set quotas
     # echo 10 > quotas/ms
index 805f228..60d4416 100644 (file)
@@ -271,7 +271,7 @@ poll cycle or the number of packets processed reaches netdev_budget.
 netdev_max_backlog
 ------------------
 
-Maximum number  of  packets,  queued  on  the  INPUT  side, when the interface
+Maximum number of packets, queued on the INPUT side, when the interface
 receives packets faster than kernel can process them.
 
 netdev_rss_key
index 52b75a2..311021f 100644 (file)
@@ -242,44 +242,34 @@ HWCAP2_MTE3
     by Documentation/arm64/memory-tagging-extension.rst.
 
 HWCAP2_SME
-
     Functionality implied by ID_AA64PFR1_EL1.SME == 0b0001, as described
     by Documentation/arm64/sme.rst.
 
 HWCAP2_SME_I16I64
-
     Functionality implied by ID_AA64SMFR0_EL1.I16I64 == 0b1111.
 
 HWCAP2_SME_F64F64
-
     Functionality implied by ID_AA64SMFR0_EL1.F64F64 == 0b1.
 
 HWCAP2_SME_I8I32
-
     Functionality implied by ID_AA64SMFR0_EL1.I8I32 == 0b1111.
 
 HWCAP2_SME_F16F32
-
     Functionality implied by ID_AA64SMFR0_EL1.F16F32 == 0b1.
 
 HWCAP2_SME_B16F32
-
     Functionality implied by ID_AA64SMFR0_EL1.B16F32 == 0b1.
 
 HWCAP2_SME_F32F32
-
     Functionality implied by ID_AA64SMFR0_EL1.F32F32 == 0b1.
 
 HWCAP2_SME_FA64
-
     Functionality implied by ID_AA64SMFR0_EL1.FA64 == 0b1.
 
 HWCAP2_WFXT
-
     Functionality implied by ID_AA64ISAR2_EL1.WFXT == 0b0010.
 
 HWCAP2_EBF16
-
     Functionality implied by ID_AA64ISAR1_EL1.BF16 == 0b0010.
 
 4. Unused AT_HWCAP bits
index 33b04db..fda97b3 100644 (file)
@@ -52,6 +52,8 @@ stable kernels.
 | Allwinner      | A64/R18         | UNKNOWN1        | SUN50I_ERRATUM_UNKNOWN1     |
 +----------------+-----------------+-----------------+-----------------------------+
 +----------------+-----------------+-----------------+-----------------------------+
+| ARM            | Cortex-A510     | #2457168        | ARM64_ERRATUM_2457168       |
++----------------+-----------------+-----------------+-----------------------------+
 | ARM            | Cortex-A510     | #2064142        | ARM64_ERRATUM_2064142       |
 +----------------+-----------------+-----------------+-----------------------------+
 | ARM            | Cortex-A510     | #2038923        | ARM64_ERRATUM_2038923       |
index 093cdae..edea465 100644 (file)
@@ -58,13 +58,11 @@ Like with atomic_t, the rule of thumb is:
 
  - RMW operations that have a return value are fully ordered.
 
- - RMW operations that are conditional are unordered on FAILURE,
-   otherwise the above rules apply. In the case of test_and_{}_bit() operations,
-   if the bit in memory is unchanged by the operation then it is deemed to have
-   failed.
+ - RMW operations that are conditional are fully ordered.
 
-Except for a successful test_and_set_bit_lock() which has ACQUIRE semantics and
-clear_bit_unlock() which has RELEASE semantics.
+Except for a successful test_and_set_bit_lock() which has ACQUIRE semantics,
+clear_bit_unlock() which has RELEASE semantics and test_bit_acquire which has
+ACQUIRE semantics.
 
 Since a platform only has a single means of achieving atomic operations
 the same barriers as for atomic_t are used, see atomic_t.txt.
index 68f115f..c4c73db 100644 (file)
@@ -23,3 +23,4 @@ Block
    stat
    switching-sched
    writeback_cache_control
+   ublk
diff --git a/Documentation/block/ublk.rst b/Documentation/block/ublk.rst
new file mode 100644 (file)
index 0000000..2122d1a
--- /dev/null
@@ -0,0 +1,253 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+===========================================
+Userspace block device driver (ublk driver)
+===========================================
+
+Overview
+========
+
+ublk is a generic framework for implementing block device logic from userspace.
+The motivation behind it is that moving virtual block drivers into userspace,
+such as loop, nbd and similar can be very helpful. It can help to implement
+new virtual block device such as ublk-qcow2 (there are several attempts of
+implementing qcow2 driver in kernel).
+
+Userspace block devices are attractive because:
+
+- They can be written many programming languages.
+- They can use libraries that are not available in the kernel.
+- They can be debugged with tools familiar to application developers.
+- Crashes do not kernel panic the machine.
+- Bugs are likely to have a lower security impact than bugs in kernel
+  code.
+- They can be installed and updated independently of the kernel.
+- They can be used to simulate block device easily with user specified
+  parameters/setting for test/debug purpose
+
+ublk block device (``/dev/ublkb*``) is added by ublk driver. Any IO request
+on the device will be forwarded to ublk userspace program. For convenience,
+in this document, ``ublk server`` refers to generic ublk userspace
+program. ``ublksrv`` [#userspace]_ is one of such implementation. It
+provides ``libublksrv`` [#userspace_lib]_ library for developing specific
+user block device conveniently, while also generic type block device is
+included, such as loop and null. Richard W.M. Jones wrote userspace nbd device
+``nbdublk`` [#userspace_nbdublk]_  based on ``libublksrv`` [#userspace_lib]_.
+
+After the IO is handled by userspace, the result is committed back to the
+driver, thus completing the request cycle. This way, any specific IO handling
+logic is totally done by userspace, such as loop's IO handling, NBD's IO
+communication, or qcow2's IO mapping.
+
+``/dev/ublkb*`` is driven by blk-mq request-based driver. Each request is
+assigned by one queue wide unique tag. ublk server assigns unique tag to each
+IO too, which is 1:1 mapped with IO of ``/dev/ublkb*``.
+
+Both the IO request forward and IO handling result committing are done via
+``io_uring`` passthrough command; that is why ublk is also one io_uring based
+block driver. It has been observed that using io_uring passthrough command can
+give better IOPS than block IO; which is why ublk is one of high performance
+implementation of userspace block device: not only IO request communication is
+done by io_uring, but also the preferred IO handling in ublk server is io_uring
+based approach too.
+
+ublk provides control interface to set/get ublk block device parameters.
+The interface is extendable and kabi compatible: basically any ublk request
+queue's parameter or ublk generic feature parameters can be set/get via the
+interface. Thus, ublk is generic userspace block device framework.
+For example, it is easy to setup a ublk device with specified block
+parameters from userspace.
+
+Using ublk
+==========
+
+ublk requires userspace ublk server to handle real block device logic.
+
+Below is example of using ``ublksrv`` to provide ublk-based loop device.
+
+- add a device::
+
+     ublk add -t loop -f ublk-loop.img
+
+- format with xfs, then use it::
+
+     mkfs.xfs /dev/ublkb0
+     mount /dev/ublkb0 /mnt
+     # do anything. all IOs are handled by io_uring
+     ...
+     umount /mnt
+
+- list the devices with their info::
+
+     ublk list
+
+- delete the device::
+
+     ublk del -a
+     ublk del -n $ublk_dev_id
+
+See usage details in README of ``ublksrv`` [#userspace_readme]_.
+
+Design
+======
+
+Control plane
+-------------
+
+ublk driver provides global misc device node (``/dev/ublk-control``) for
+managing and controlling ublk devices with help of several control commands:
+
+- ``UBLK_CMD_ADD_DEV``
+
+  Add a ublk char device (``/dev/ublkc*``) which is talked with ublk server
+  WRT IO command communication. Basic device info is sent together with this
+  command. It sets UAPI structure of ``ublksrv_ctrl_dev_info``,
+  such as ``nr_hw_queues``, ``queue_depth``, and max IO request buffer size,
+  for which the info is negotiated with the driver and sent back to the server.
+  When this command is completed, the basic device info is immutable.
+
+- ``UBLK_CMD_SET_PARAMS`` / ``UBLK_CMD_GET_PARAMS``
+
+  Set or get parameters of the device, which can be either generic feature
+  related, or request queue limit related, but can't be IO logic specific,
+  because the driver does not handle any IO logic. This command has to be
+  sent before sending ``UBLK_CMD_START_DEV``.
+
+- ``UBLK_CMD_START_DEV``
+
+  After the server prepares userspace resources (such as creating per-queue
+  pthread & io_uring for handling ublk IO), this command is sent to the
+  driver for allocating & exposing ``/dev/ublkb*``. Parameters set via
+  ``UBLK_CMD_SET_PARAMS`` are applied for creating the device.
+
+- ``UBLK_CMD_STOP_DEV``
+
+  Halt IO on ``/dev/ublkb*`` and remove the device. When this command returns,
+  ublk server will release resources (such as destroying per-queue pthread &
+  io_uring).
+
+- ``UBLK_CMD_DEL_DEV``
+
+  Remove ``/dev/ublkc*``. When this command returns, the allocated ublk device
+  number can be reused.
+
+- ``UBLK_CMD_GET_QUEUE_AFFINITY``
+
+  When ``/dev/ublkc`` is added, the driver creates block layer tagset, so
+  that each queue's affinity info is available. The server sends
+  ``UBLK_CMD_GET_QUEUE_AFFINITY`` to retrieve queue affinity info. It can
+  set up the per-queue context efficiently, such as bind affine CPUs with IO
+  pthread and try to allocate buffers in IO thread context.
+
+- ``UBLK_CMD_GET_DEV_INFO``
+
+  For retrieving device info via ``ublksrv_ctrl_dev_info``. It is the server's
+  responsibility to save IO target specific info in userspace.
+
+Data plane
+----------
+
+ublk server needs to create per-queue IO pthread & io_uring for handling IO
+commands via io_uring passthrough. The per-queue IO pthread
+focuses on IO handling and shouldn't handle any control & management
+tasks.
+
+The's IO is assigned by a unique tag, which is 1:1 mapping with IO
+request of ``/dev/ublkb*``.
+
+UAPI structure of ``ublksrv_io_desc`` is defined for describing each IO from
+the driver. A fixed mmaped area (array) on ``/dev/ublkc*`` is provided for
+exporting IO info to the server; such as IO offset, length, OP/flags and
+buffer address. Each ``ublksrv_io_desc`` instance can be indexed via queue id
+and IO tag directly.
+
+The following IO commands are communicated via io_uring passthrough command,
+and each command is only for forwarding the IO and committing the result
+with specified IO tag in the command data:
+
+- ``UBLK_IO_FETCH_REQ``
+
+  Sent from the server IO pthread for fetching future incoming IO requests
+  destined to ``/dev/ublkb*``. This command is sent only once from the server
+  IO pthread for ublk driver to setup IO forward environment.
+
+- ``UBLK_IO_COMMIT_AND_FETCH_REQ``
+
+  When an IO request is destined to ``/dev/ublkb*``, the driver stores
+  the IO's ``ublksrv_io_desc`` to the specified mapped area; then the
+  previous received IO command of this IO tag (either ``UBLK_IO_FETCH_REQ``
+  or ``UBLK_IO_COMMIT_AND_FETCH_REQ)`` is completed, so the server gets
+  the IO notification via io_uring.
+
+  After the server handles the IO, its result is committed back to the
+  driver by sending ``UBLK_IO_COMMIT_AND_FETCH_REQ`` back. Once ublkdrv
+  received this command, it parses the result and complete the request to
+  ``/dev/ublkb*``. In the meantime setup environment for fetching future
+  requests with the same IO tag. That is, ``UBLK_IO_COMMIT_AND_FETCH_REQ``
+  is reused for both fetching request and committing back IO result.
+
+- ``UBLK_IO_NEED_GET_DATA``
+
+  With ``UBLK_F_NEED_GET_DATA`` enabled, the WRITE request will be firstly
+  issued to ublk server without data copy. Then, IO backend of ublk server
+  receives the request and it can allocate data buffer and embed its addr
+  inside this new io command. After the kernel driver gets the command,
+  data copy is done from request pages to this backend's buffer. Finally,
+  backend receives the request again with data to be written and it can
+  truly handle the request.
+
+  ``UBLK_IO_NEED_GET_DATA`` adds one additional round-trip and one
+  io_uring_enter() syscall. Any user thinks that it may lower performance
+  should not enable UBLK_F_NEED_GET_DATA. ublk server pre-allocates IO
+  buffer for each IO by default. Any new project should try to use this
+  buffer to communicate with ublk driver. However, existing project may
+  break or not able to consume the new buffer interface; that's why this
+  command is added for backwards compatibility so that existing projects
+  can still consume existing buffers.
+
+- data copy between ublk server IO buffer and ublk block IO request
+
+  The driver needs to copy the block IO request pages into the server buffer
+  (pages) first for WRITE before notifying the server of the coming IO, so
+  that the server can handle WRITE request.
+
+  When the server handles READ request and sends
+  ``UBLK_IO_COMMIT_AND_FETCH_REQ`` to the server, ublkdrv needs to copy
+  the server buffer (pages) read to the IO request pages.
+
+Future development
+==================
+
+Container-aware ublk deivice
+----------------------------
+
+ublk driver doesn't handle any IO logic. Its function is well defined
+for now and very limited userspace interfaces are needed, which is also
+well defined too. It is possible to make ublk devices container-aware block
+devices in future as Stefan Hajnoczi suggested [#stefan]_, by removing
+ADMIN privilege.
+
+Zero copy
+---------
+
+Zero copy is a generic requirement for nbd, fuse or similar drivers. A
+problem [#xiaoguang]_ Xiaoguang mentioned is that pages mapped to userspace
+can't be remapped any more in kernel with existing mm interfaces. This can
+occurs when destining direct IO to ``/dev/ublkb*``. Also, he reported that
+big requests (IO size >= 256 KB) may benefit a lot from zero copy.
+
+
+References
+==========
+
+.. [#userspace] https://github.com/ming1/ubdsrv
+
+.. [#userspace_lib] https://github.com/ming1/ubdsrv/tree/master/lib
+
+.. [#userspace_nbdublk] https://gitlab.com/rwmjones/libnbd/-/tree/nbdublk
+
+.. [#userspace_readme] https://github.com/ming1/ubdsrv/blob/master/README
+
+.. [#stefan] https://lore.kernel.org/linux-block/YoOr6jBfgVm8GvWg@stefanha-x1.localdomain/
+
+.. [#xiaoguang] https://lore.kernel.org/linux-block/YoOr6jBfgVm8GvWg@stefanha-x1.localdomain/
index 934727e..255384d 100644 (file)
@@ -86,6 +86,7 @@ if major >= 3:
             "__used",
             "__weak",
             "noinline",
+            "__fix_address",
 
             # include/linux/memblock.h:
             "__init_memblock",
index 6cc7452..1748f16 100644 (file)
@@ -8,7 +8,7 @@ $schema: "http://devicetree.org/meta-schemas/core.yaml#"
 title: Amlogic Meson Firmware registers Interface
 
 maintainers:
-  - Neil Armstrong <narmstrong@baylibre.com>
+  - Neil Armstrong <neil.armstrong@linaro.org>
 
 description: |
   The Meson SoCs have a register bank with status and data shared with the
index 4a92a4c..f816898 100644 (file)
@@ -233,6 +233,7 @@ allOf:
               - allwinner,sun8i-a83t-tcon-lcd
               - allwinner,sun8i-v3s-tcon
               - allwinner,sun9i-a80-tcon-lcd
+              - allwinner,sun20i-d1-tcon-lcd
 
     then:
       properties:
@@ -252,6 +253,7 @@ allOf:
               - allwinner,sun8i-a83t-tcon-tv
               - allwinner,sun8i-r40-tcon-tv
               - allwinner,sun9i-a80-tcon-tv
+              - allwinner,sun20i-d1-tcon-tv
 
     then:
       properties:
@@ -278,6 +280,7 @@ allOf:
               - allwinner,sun9i-a80-tcon-lcd
               - allwinner,sun4i-a10-tcon
               - allwinner,sun8i-a83t-tcon-lcd
+              - allwinner,sun20i-d1-tcon-lcd
 
     then:
       required:
@@ -294,6 +297,7 @@ allOf:
               - allwinner,sun8i-a23-tcon
               - allwinner,sun8i-a33-tcon
               - allwinner,sun8i-a83t-tcon-lcd
+              - allwinner,sun20i-d1-tcon-lcd
 
     then:
       properties:
index 2e208d2..7cdffdb 100644 (file)
@@ -8,7 +8,7 @@ $schema: "http://devicetree.org/meta-schemas/core.yaml#"
 title: Amlogic specific extensions to the Synopsys Designware HDMI Controller
 
 maintainers:
-  - Neil Armstrong <narmstrong@baylibre.com>
+  - Neil Armstrong <neil.armstrong@linaro.org>
 
 allOf:
   - $ref: /schemas/sound/name-prefix.yaml#
index 047fd69..6655a93 100644 (file)
@@ -8,7 +8,7 @@ $schema: "http://devicetree.org/meta-schemas/core.yaml#"
 title: Amlogic Meson Display Controller
 
 maintainers:
-  - Neil Armstrong <narmstrong@baylibre.com>
+  - Neil Armstrong <neil.armstrong@linaro.org>
 
 description: |
   The Amlogic Meson Display controller is composed of several components
index bce96b5..4a5e5d9 100644 (file)
@@ -8,7 +8,7 @@ title: Analogix ANX7814 SlimPort (Full-HD Transmitter)
 
 maintainers:
   - Andrzej Hajda <andrzej.hajda@intel.com>
-  - Neil Armstrong <narmstrong@baylibre.com>
+  - Neil Armstrong <neil.armstrong@linaro.org>
   - Robert Foss <robert.foss@linaro.org>
 
 properties:
index c6e81f5..1b2185b 100644 (file)
@@ -8,7 +8,7 @@ title: ITE it66121 HDMI bridge Device Tree Bindings
 
 maintainers:
   - Phong LE <ple@baylibre.com>
-  - Neil Armstrong <narmstrong@baylibre.com>
+  - Neil Armstrong <neil.armstrong@linaro.org>
 
 description: |
   The IT66121 is a high-performance and low-power single channel HDMI
index 44e02de..2e75e37 100644 (file)
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: Solomon Goldentek Display GKTW70SDAE4SE 7" WVGA LVDS Display Panel
 
 maintainers:
-  - Neil Armstrong <narmstrong@baylibre.com>
+  - Neil Armstrong <neil.armstrong@linaro.org>
   - Thierry Reding <thierry.reding@gmail.com>
 
 allOf:
index b79f069..8ea97e7 100644 (file)
@@ -48,7 +48,6 @@ required:
   - compatible
   - reg
   - reg-names
-  - intel,vm-map
   - clocks
   - resets
   - "#thermal-sensor-cells"
index 6ecb027..199a354 100644 (file)
@@ -8,7 +8,7 @@ $schema: "http://devicetree.org/meta-schemas/core.yaml#"
 title: Amlogic Meson I2C Controller
 
 maintainers:
-  - Neil Armstrong <narmstrong@baylibre.com>
+  - Neil Armstrong <neil.armstrong@linaro.org>
   - Beniamino Galvani <b.galvani@gmail.com>
 
 allOf:
index 2f31548..d3c0d5c 100644 (file)
@@ -60,6 +60,9 @@ properties:
   power-domains:
     maxItems: 1
 
+  resets:
+    maxItems: 1
+
 required:
   - compatible
   - reg
index b6bbc31..1414ba9 100644 (file)
@@ -24,8 +24,10 @@ properties:
 
   interrupts:
     minItems: 1
+    maxItems: 2
     description:
       Should be configured with type IRQ_TYPE_EDGE_RISING.
+      If two interrupts are provided, expected order is INT1 and INT2.
 
 required:
   - compatible
index 93f2ce3..19ac9da 100644 (file)
@@ -16,6 +16,7 @@ properties:
   compatible:
     enum:
       - goodix,gt1151
+      - goodix,gt1158
       - goodix,gt5663
       - goodix,gt5688
       - goodix,gt911
index 09c8948..fa4f768 100644 (file)
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: Generic i.MX bus frequency device
 
 maintainers:
-  - Leonard Crestez <leonard.crestez@nxp.com>
+  - Peng Fan <peng.fan@nxp.com>
 
 description: |
   The i.MX SoC family has multiple buses for which clock frequency (and
index 85c85b6..e18107e 100644 (file)
@@ -96,7 +96,7 @@ properties:
               Documentation/devicetree/bindings/arm/cpus.yaml).
 
         required:
-          - fiq-index
+          - apple,fiq-index
           - cpus
 
 required:
index ea06976..dfd26b9 100644 (file)
@@ -8,7 +8,7 @@ $schema: "http://devicetree.org/meta-schemas/core.yaml#"
 title: Amlogic Meson Message-Handling-Unit Controller
 
 maintainers:
-  - Neil Armstrong <narmstrong@baylibre.com>
+  - Neil Armstrong <neil.armstrong@linaro.org>
 
 description: |
   The Amlogic's Meson SoCs Message-Handling-Unit (MHU) is a mailbox controller
index bee93bd..e551be5 100644 (file)
@@ -8,7 +8,7 @@ $schema: "http://devicetree.org/meta-schemas/core.yaml#"
 title: Amlogic GE2D Acceleration Unit
 
 maintainers:
-  - Neil Armstrong <narmstrong@baylibre.com>
+  - Neil Armstrong <neil.armstrong@linaro.org>
 
 properties:
   compatible:
index 5044c4b..b827eda 100644 (file)
@@ -8,7 +8,7 @@ $schema: "http://devicetree.org/meta-schemas/core.yaml#"
 title: Amlogic Video Decoder
 
 maintainers:
-  - Neil Armstrong <narmstrong@baylibre.com>
+  - Neil Armstrong <neil.armstrong@linaro.org>
   - Maxime Jourdan <mjourdan@baylibre.com>
 
 description: |
index d93aea6..8d844f4 100644 (file)
@@ -8,7 +8,7 @@ $schema: "http://devicetree.org/meta-schemas/core.yaml#"
 title: Amlogic Meson AO-CEC Controller
 
 maintainers:
-  - Neil Armstrong <narmstrong@baylibre.com>
+  - Neil Armstrong <neil.armstrong@linaro.org>
 
 description: |
   The Amlogic Meson AO-CEC module is present is Amlogic SoCs and its purpose is
index a3b976f..5750cc0 100644 (file)
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: Khadas on-board Microcontroller Device Tree Bindings
 
 maintainers:
-  - Neil Armstrong <narmstrong@baylibre.com>
+  - Neil Armstrong <neil.armstrong@linaro.org>
 
 description: |
   Khadas embeds a microcontroller on their VIM and Edge boards adding some
index 608e1d6..ddd5a07 100644 (file)
@@ -8,7 +8,7 @@ $schema: "http://devicetree.org/meta-schemas/core.yaml#"
 title: Amlogic Meson DWMAC Ethernet controller
 
 maintainers:
-  - Neil Armstrong <narmstrong@baylibre.com>
+  - Neil Armstrong <neil.armstrong@linaro.org>
   - Martin Blumenstingl <martin.blumenstingl@googlemail.com>
 
 # We need a select here so we don't match all nodes with 'snps,dwmac'
index e6cb229..7ae8aa1 100644 (file)
@@ -14,7 +14,7 @@ MAC node:
 - mac-address : The 6-byte MAC address. If present, it is the default
        MAC address.
 - internal-phy : phandle to the internal PHY node
-- phy-handle : phandle the external PHY node
+- phy-handle : phandle to the external PHY node
 
 Internal PHY node:
 - compatible : Should be "qcom,fsm9900-emac-sgmii" or "qcom,qdf2432-emac-sgmii".
index be485f5..5eddaed 100644 (file)
@@ -8,7 +8,7 @@ $schema: "http://devicetree.org/meta-schemas/core.yaml#"
 title: Amlogic AXG MIPI D-PHY
 
 maintainers:
-  - Neil Armstrong <narmstrong@baylibre.com>
+  - Neil Armstrong <neil.armstrong@linaro.org>
 
 properties:
   compatible:
index 399ebde..f3a5fba 100644 (file)
@@ -8,7 +8,7 @@ $schema: "http://devicetree.org/meta-schemas/core.yaml#"
 title: Amlogic G12A USB2 PHY
 
 maintainers:
-  - Neil Armstrong <narmstrong@baylibre.com>
+  - Neil Armstrong <neil.armstrong@linaro.org>
 
 properties:
   compatible:
index 453c083..868b4e6 100644 (file)
@@ -8,7 +8,7 @@ $schema: "http://devicetree.org/meta-schemas/core.yaml#"
 title: Amlogic G12A USB3 + PCIE Combo PHY
 
 maintainers:
-  - Neil Armstrong <narmstrong@baylibre.com>
+  - Neil Armstrong <neil.armstrong@linaro.org>
 
 properties:
   compatible:
index 33d1d37..624e14f 100644 (file)
@@ -8,7 +8,6 @@ title: Qualcomm Technologies, Inc. Low Power Audio SubSystem (LPASS)
   Low Power Island (LPI) TLMM block
 
 maintainers:
-  - Srinivasa Rao Mandadapu <srivasam@codeaurora.org>
   - Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
 
 description: |
index 2d22816..2bd60c4 100644 (file)
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: Qualcomm Technologies, Inc. SC7280 TLMM block
 
 maintainers:
-  - Rajendra Nayak <rnayak@codeaurora.org>
+  - Bjorn Andersson <andersson@kernel.org>
 
 description: |
   This binding describes the Top Level Mode Multiplexer block found in the
index 5390e98..43a9322 100644 (file)
@@ -8,7 +8,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: Amlogic Meson Everything-Else Power Domains
 
 maintainers:
-  - Neil Armstrong <narmstrong@baylibre.com>
+  - Neil Armstrong <neil.armstrong@linaro.org>
 
 description: |+
   The Everything-Else Power Domains node should be the child of a syscon
index 0ccca49..3934a2b 100644 (file)
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: Qualcomm RPM/RPMh Power domains
 
 maintainers:
-  - Rajendra Nayak <rnayak@codeaurora.org>
+  - Bjorn Andersson <andersson@kernel.org>
 
 description:
   For RPM/RPMh Power domains, we communicate a performance state to RPM/RPMh
index b539781..835b533 100644 (file)
@@ -47,12 +47,6 @@ properties:
         description:
           Properties for single LDO regulator.
 
-        properties:
-          regulator-name:
-            pattern: "^LDO[1-5]$"
-            description:
-              should be "LDO1", ..., "LDO5"
-
         unevaluatedProperties: false
 
       "^BUCK[1-6]$":
@@ -62,11 +56,6 @@ properties:
           Properties for single BUCK regulator.
 
         properties:
-          regulator-name:
-            pattern: "^BUCK[1-6]$"
-            description:
-              should be "BUCK1", ..., "BUCK6"
-
           nxp,dvs-run-voltage:
             $ref: "/schemas/types.yaml#/definitions/uint32"
             minimum: 600000
index 8b7c4af..faa4af9 100644 (file)
@@ -35,6 +35,7 @@ patternProperties:
     description: List of regulators and its properties
     type: object
     $ref: regulator.yaml#
+    unevaluatedProperties: false
 
     properties:
       qcom,ocp-max-retries:
@@ -100,8 +101,6 @@ patternProperties:
           SAW controlled gang leader. Will be configured as SAW regulator.
         type: boolean
 
-      unevaluatedProperties: false
-
 required:
   - compatible
 
index 494a454..98db2aa 100644 (file)
@@ -8,7 +8,7 @@ $schema: "http://devicetree.org/meta-schemas/core.yaml#"
 title: Amlogic Meson SoC Reset Controller
 
 maintainers:
-  - Neil Armstrong <narmstrong@baylibre.com>
+  - Neil Armstrong <neil.armstrong@linaro.org>
 
 properties:
   compatible:
index 69cdab1..ca3b9be 100644 (file)
@@ -17,9 +17,6 @@ description:
   acts as directory-based coherency manager.
   All the properties in ePAPR/DeviceTree specification applies for this platform.
 
-allOf:
-  - $ref: /schemas/cache-controller.yaml#
-
 select:
   properties:
     compatible:
@@ -33,11 +30,16 @@ select:
 
 properties:
   compatible:
-    items:
-      - enum:
-          - sifive,fu540-c000-ccache
-          - sifive,fu740-c000-ccache
-      - const: cache
+    oneOf:
+      - items:
+          - enum:
+              - sifive,fu540-c000-ccache
+              - sifive,fu740-c000-ccache
+          - const: cache
+      - items:
+          - const: microchip,mpfs-ccache
+          - const: sifive,fu540-c000-ccache
+          - const: cache
 
   cache-block-size:
     const: 64
@@ -72,29 +74,46 @@ properties:
       The reference to the reserved-memory for the L2 Loosely Integrated Memory region.
       The reserved memory node should be defined as per the bindings in reserved-memory.txt.
 
-if:
-  properties:
-    compatible:
-      contains:
-        const: sifive,fu540-c000-ccache
+allOf:
+  - $ref: /schemas/cache-controller.yaml#
 
-then:
-  properties:
-    interrupts:
-      description: |
-        Must contain entries for DirError, DataError and DataFail signals.
-      maxItems: 3
-    cache-sets:
-      const: 1024
-
-else:
-  properties:
-    interrupts:
-      description: |
-        Must contain entries for DirError, DataError, DataFail, DirFail signals.
-      minItems: 4
-    cache-sets:
-      const: 2048
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - sifive,fu740-c000-ccache
+              - microchip,mpfs-ccache
+
+    then:
+      properties:
+        interrupts:
+          description: |
+            Must contain entries for DirError, DataError, DataFail, DirFail signals.
+          minItems: 4
+
+    else:
+      properties:
+        interrupts:
+          description: |
+            Must contain entries for DirError, DataError and DataFail signals.
+          maxItems: 3
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: sifive,fu740-c000-ccache
+
+    then:
+      properties:
+        cache-sets:
+          const: 2048
+
+    else:
+      properties:
+        cache-sets:
+          const: 1024
 
 additionalProperties: false
 
index 444be32..09c6c90 100644 (file)
@@ -8,7 +8,7 @@ $schema: "http://devicetree.org/meta-schemas/core.yaml#"
 title: Amlogic Meson Random number generator
 
 maintainers:
-  - Neil Armstrong <narmstrong@baylibre.com>
+  - Neil Armstrong <neil.armstrong@linaro.org>
 
 properties:
   compatible:
index 72e8868..7822705 100644 (file)
@@ -8,7 +8,7 @@ $schema: "http://devicetree.org/meta-schemas/core.yaml#"
 title: Amlogic Meson SoC UART Serial Interface
 
 maintainers:
-  - Neil Armstrong <narmstrong@baylibre.com>
+  - Neil Armstrong <neil.armstrong@linaro.org>
 
 description: |
   The Amlogic Meson SoC UART Serial Interface is present on a large range
index 17db87c..c3c5990 100644 (file)
@@ -8,7 +8,7 @@ $schema: "http://devicetree.org/meta-schemas/core.yaml#"
 title: Amlogic Canvas Video Lookup Table
 
 maintainers:
-  - Neil Armstrong <narmstrong@baylibre.com>
+  - Neil Armstrong <neil.armstrong@linaro.org>
   - Maxime Jourdan <mjourdan@baylibre.com>
 
 description: |
index 50de0da..0c10f76 100644 (file)
@@ -8,7 +8,7 @@ $schema: "http://devicetree.org/meta-schemas/core.yaml#"
 title: Amlogic Meson SPI Communication Controller
 
 maintainers:
-  - Neil Armstrong <narmstrong@baylibre.com>
+  - Neil Armstrong <neil.armstrong@linaro.org>
 
 allOf:
   - $ref: "spi-controller.yaml#"
index 8a9d526..ac3b2ec 100644 (file)
@@ -8,7 +8,7 @@ $schema: "http://devicetree.org/meta-schemas/core.yaml#"
 title: Amlogic Meson SPI Flash Controller
 
 maintainers:
-  - Neil Armstrong <narmstrong@baylibre.com>
+  - Neil Armstrong <neil.armstrong@linaro.org>
 
 allOf:
   - $ref: "spi-controller.yaml#"
index 553601a..510b82c 100644 (file)
@@ -10,7 +10,7 @@ description:
   See spi-peripheral-props.yaml for more info.
 
 maintainers:
-  - Pratyush Yadav <p.yadav@ti.com>
+  - Vaishnav Achath <vaishnav.a@ti.com>
 
 properties:
   # cdns,qspi-nor.yaml
index 0a537fa..4707294 100644 (file)
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: Cadence Quad SPI controller
 
 maintainers:
-  - Pratyush Yadav <p.yadav@ti.com>
+  - Vaishnav Achath <vaishnav.a@ti.com>
 
 allOf:
   - $ref: spi-controller.yaml#
index ce048e7..a4abe15 100644 (file)
@@ -16,7 +16,7 @@ description:
   their own separate schema that should be referenced from here.
 
 maintainers:
-  - Pratyush Yadav <p.yadav@ti.com>
+  - Mark Brown <broonie@kernel.org>
 
 properties:
   reg:
index 00dcbdd..119998d 100644 (file)
@@ -42,7 +42,7 @@ properties:
     description:
       Address ranges of the thermal registers. If more then one range is given
       the first one must be the common registers followed by each sensor
-      according the datasheet.
+      according to the datasheet.
     minItems: 1
     maxItems: 4
 
index 2d34f3c..8d2c6d7 100644 (file)
@@ -214,6 +214,7 @@ patternProperties:
       - polling-delay
       - polling-delay-passive
       - thermal-sensors
+      - trips
 
     additionalProperties: false
 
index e349fa5..daf2a85 100644 (file)
@@ -8,7 +8,7 @@ $schema: "http://devicetree.org/meta-schemas/core.yaml#"
 title: Amlogic Meson G12A DWC3 USB SoC Controller Glue
 
 maintainers:
-  - Neil Armstrong <narmstrong@baylibre.com>
+  - Neil Armstrong <neil.armstrong@linaro.org>
 
 description: |
   The Amlogic G12A embeds a DWC3 USB IP Core configured for USB2 and USB3
index e63b665..b019d49 100644 (file)
@@ -24,6 +24,7 @@ properties:
           - mediatek,mt2712-mtu3
           - mediatek,mt8173-mtu3
           - mediatek,mt8183-mtu3
+          - mediatek,mt8188-mtu3
           - mediatek,mt8192-mtu3
           - mediatek,mt8195-mtu3
       - const: mediatek,mtu3
index fea3e70..cd2f7cb 100644 (file)
@@ -33,6 +33,7 @@ properties:
           - qcom,sm6115-dwc3
           - qcom,sm6125-dwc3
           - qcom,sm6350-dwc3
+          - qcom,sm6375-dwc3
           - qcom,sm8150-dwc3
           - qcom,sm8250-dwc3
           - qcom,sm8350-dwc3
@@ -108,12 +109,17 @@ properties:
       HS/FS/LS modes are supported.
     type: boolean
 
+  wakeup-source: true
+
 # Required child node:
 
 patternProperties:
   "^usb@[0-9a-f]+$":
     $ref: snps,dwc3.yaml#
 
+    properties:
+      wakeup-source: false
+
 required:
   - compatible
   - reg
index c7459cf..497d604 100644 (file)
@@ -8,7 +8,7 @@ $schema: "http://devicetree.org/meta-schemas/core.yaml#"
 title: Meson GXBB SoCs Watchdog timer
 
 maintainers:
-  - Neil Armstrong <narmstrong@baylibre.com>
+  - Neil Armstrong <neil.armstrong@linaro.org>
 
 allOf:
   - $ref: watchdog.yaml#
index cc90002..07fe6f6 100644 (file)
@@ -64,7 +64,7 @@ correct address for this module, you could get in big trouble (read:
 crashes, data corruption, etc.). Try this only as a last resort (try BIOS
 updates first, for example), and backup first! An even more dangerous
 option is 'force_addr=<IOPORT>'. This will not only enable the PIIX4 like
-'force' foes, but it will also set a new base I/O port address. The SMBus
+'force' does, but it will also set a new base I/O port address. The SMBus
 parts of the PIIX4 needs a range of 8 of these addresses to function
 correctly. If these addresses are already reserved by some other device,
 you will get into big trouble! DON'T USE THIS IF YOU ARE NOT VERY SURE
@@ -86,15 +86,15 @@ If you own Force CPCI735 motherboard or other OSB4 based systems you may need
 to change the SMBus Interrupt Select register so the SMBus controller uses
 the SMI mode.
 
-1) Use lspci command and locate the PCI device with the SMBus controller:
+1) Use ``lspci`` command and locate the PCI device with the SMBus controller:
    00:0f.0 ISA bridge: ServerWorks OSB4 South Bridge (rev 4f)
    The line may vary for different chipsets. Please consult the driver source
-   for all possible PCI ids (and lspci -n to match them). Lets assume the
+   for all possible PCI ids (and ``lspci -n`` to match them). Let's assume the
    device is located at 00:0f.0.
 2) Now you just need to change the value in 0xD2 register. Get it first with
-   command: lspci -xxx -s 00:0f.0
+   command: ``lspci -xxx -s 00:0f.0``
    If the value is 0x3 then you need to change it to 0x1:
-   setpci  -s 00:0f.0 d2.b=1
+   ``setpci  -s 00:0f.0 d2.b=1``
 
 Please note that you don't need to do that in all cases, just when the SMBus is
 not working properly.
@@ -109,6 +109,3 @@ which can easily get corrupted due to a state machine bug. These are mostly
 Thinkpad laptops, but desktop systems may also be affected. We have no list
 of all affected systems, so the only safe solution was to prevent access to
 the SMBus on all IBM systems (detected using DMI data.)
-
-For additional information, read:
-http://www.lm-sensors.org/browser/lm-sensors/trunk/README
index 7cb5381..48fce0f 100644 (file)
@@ -5,6 +5,8 @@ I2C muxes and complex topologies
 There are a couple of reasons for building more complex I2C topologies
 than a straight-forward I2C bus with one adapter and one or more devices.
 
+Some example use cases are:
+
 1. A mux may be needed on the bus to prevent address collisions.
 
 2. The bus may be accessible from some external bus master, and arbitration
@@ -14,10 +16,10 @@ than a straight-forward I2C bus with one adapter and one or more devices.
    from the I2C bus, at least most of the time, and sits behind a gate
    that has to be operated before the device can be accessed.
 
-Etc
-===
+Several types of hardware components such as I2C muxes, I2C gates and I2C
+arbitrators allow to handle such needs.
 
-These constructs are represented as I2C adapter trees by Linux, where
+These components are represented as I2C adapter trees by Linux, where
 each adapter has a parent adapter (except the root adapter) and zero or
 more child adapters. The root adapter is the actual adapter that issues
 I2C transfers, and all adapters with a parent are part of an "i2c-mux"
@@ -35,46 +37,7 @@ Locking
 =======
 
 There are two variants of locking available to I2C muxes, they can be
-mux-locked or parent-locked muxes. As is evident from below, it can be
-useful to know if a mux is mux-locked or if it is parent-locked. The
-following list was correct at the time of writing:
-
-In drivers/i2c/muxes/:
-
-======================    =============================================
-i2c-arb-gpio-challenge    Parent-locked
-i2c-mux-gpio              Normally parent-locked, mux-locked iff
-                          all involved gpio pins are controlled by the
-                          same I2C root adapter that they mux.
-i2c-mux-gpmux             Normally parent-locked, mux-locked iff
-                          specified in device-tree.
-i2c-mux-ltc4306           Mux-locked
-i2c-mux-mlxcpld           Parent-locked
-i2c-mux-pca9541           Parent-locked
-i2c-mux-pca954x           Parent-locked
-i2c-mux-pinctrl           Normally parent-locked, mux-locked iff
-                          all involved pinctrl devices are controlled
-                          by the same I2C root adapter that they mux.
-i2c-mux-reg               Parent-locked
-======================    =============================================
-
-In drivers/iio/:
-
-======================    =============================================
-gyro/mpu3050              Mux-locked
-imu/inv_mpu6050/          Mux-locked
-======================    =============================================
-
-In drivers/media/:
-
-=======================   =============================================
-dvb-frontends/lgdt3306a   Mux-locked
-dvb-frontends/m88ds3103   Parent-locked
-dvb-frontends/rtl2830     Parent-locked
-dvb-frontends/rtl2832     Mux-locked
-dvb-frontends/si2168      Mux-locked
-usb/cx231xx/              Parent-locked
-=======================   =============================================
+mux-locked or parent-locked muxes.
 
 
 Mux-locked muxes
@@ -89,40 +52,8 @@ full transaction, unrelated I2C transfers may interleave the different
 stages of the transaction. This has the benefit that the mux driver
 may be easier and cleaner to implement, but it has some caveats.
 
-==== =====================================================================
-ML1. If you build a topology with a mux-locked mux being the parent
-     of a parent-locked mux, this might break the expectation from the
-     parent-locked mux that the root adapter is locked during the
-     transaction.
-
-ML2. It is not safe to build arbitrary topologies with two (or more)
-     mux-locked muxes that are not siblings, when there are address
-     collisions between the devices on the child adapters of these
-     non-sibling muxes.
-
-     I.e. the select-transfer-deselect transaction targeting e.g. device
-     address 0x42 behind mux-one may be interleaved with a similar
-     operation targeting device address 0x42 behind mux-two. The
-     intension with such a topology would in this hypothetical example
-     be that mux-one and mux-two should not be selected simultaneously,
-     but mux-locked muxes do not guarantee that in all topologies.
-
-ML3. A mux-locked mux cannot be used by a driver for auto-closing
-     gates/muxes, i.e. something that closes automatically after a given
-     number (one, in most cases) of I2C transfers. Unrelated I2C transfers
-     may creep in and close prematurely.
-
-ML4. If any non-I2C operation in the mux driver changes the I2C mux state,
-     the driver has to lock the root adapter during that operation.
-     Otherwise garbage may appear on the bus as seen from devices
-     behind the mux, when an unrelated I2C transfer is in flight during
-     the non-I2C mux-changing operation.
-==== =====================================================================
-
-
 Mux-locked Example
-------------------
-
+~~~~~~~~~~~~~~~~~~
 
 ::
 
@@ -153,6 +84,43 @@ This means that accesses to D2 are lockout out for the full duration
 of the entire operation. But accesses to D3 are possibly interleaved
 at any point.
 
+Mux-locked caveats
+~~~~~~~~~~~~~~~~~~
+
+When using a mux-locked mux, be aware of the following restrictions:
+
+[ML1]
+  If you build a topology with a mux-locked mux being the parent
+  of a parent-locked mux, this might break the expectation from the
+  parent-locked mux that the root adapter is locked during the
+  transaction.
+
+[ML2]
+  It is not safe to build arbitrary topologies with two (or more)
+  mux-locked muxes that are not siblings, when there are address
+  collisions between the devices on the child adapters of these
+  non-sibling muxes.
+
+  I.e. the select-transfer-deselect transaction targeting e.g. device
+  address 0x42 behind mux-one may be interleaved with a similar
+  operation targeting device address 0x42 behind mux-two. The
+  intent with such a topology would in this hypothetical example
+  be that mux-one and mux-two should not be selected simultaneously,
+  but mux-locked muxes do not guarantee that in all topologies.
+
+[ML3]
+  A mux-locked mux cannot be used by a driver for auto-closing
+  gates/muxes, i.e. something that closes automatically after a given
+  number (one, in most cases) of I2C transfers. Unrelated I2C transfers
+  may creep in and close prematurely.
+
+[ML4]
+  If any non-I2C operation in the mux driver changes the I2C mux state,
+  the driver has to lock the root adapter during that operation.
+  Otherwise garbage may appear on the bus as seen from devices
+  behind the mux, when an unrelated I2C transfer is in flight during
+  the non-I2C mux-changing operation.
+
 
 Parent-locked muxes
 -------------------
@@ -161,28 +129,10 @@ Parent-locked muxes lock the parent adapter during the full select-
 transfer-deselect transaction. The implication is that the mux driver
 has to ensure that any and all I2C transfers through that parent
 adapter during the transaction are unlocked I2C transfers (using e.g.
-__i2c_transfer), or a deadlock will follow. There are a couple of
-caveats.
-
-==== ====================================================================
-PL1. If you build a topology with a parent-locked mux being the child
-     of another mux, this might break a possible assumption from the
-     child mux that the root adapter is unused between its select op
-     and the actual transfer (e.g. if the child mux is auto-closing
-     and the parent mux issues I2C transfers as part of its select).
-     This is especially the case if the parent mux is mux-locked, but
-     it may also happen if the parent mux is parent-locked.
-
-PL2. If select/deselect calls out to other subsystems such as gpio,
-     pinctrl, regmap or iio, it is essential that any I2C transfers
-     caused by these subsystems are unlocked. This can be convoluted to
-     accomplish, maybe even impossible if an acceptably clean solution
-     is sought.
-==== ====================================================================
-
+__i2c_transfer), or a deadlock will follow.
 
 Parent-locked Example
----------------------
+~~~~~~~~~~~~~~~~~~~~~
 
 ::
 
@@ -212,10 +162,30 @@ When there is an access to D1, this happens:
  9.  M1 unlocks its parent adapter.
  10. M1 unlocks muxes on its parent.
 
-
 This means that accesses to both D2 and D3 are locked out for the full
 duration of the entire operation.
 
+Parent-locked Caveats
+~~~~~~~~~~~~~~~~~~~~~
+
+When using a parent-locked mux, be aware of the following restrictions:
+
+[PL1]
+  If you build a topology with a parent-locked mux being the child
+  of another mux, this might break a possible assumption from the
+  child mux that the root adapter is unused between its select op
+  and the actual transfer (e.g. if the child mux is auto-closing
+  and the parent mux issues I2C transfers as part of its select).
+  This is especially the case if the parent mux is mux-locked, but
+  it may also happen if the parent mux is parent-locked.
+
+[PL2]
+  If select/deselect calls out to other subsystems such as gpio,
+  pinctrl, regmap or iio, it is essential that any I2C transfers
+  caused by these subsystems are unlocked. This can be convoluted to
+  accomplish, maybe even impossible if an acceptably clean solution
+  is sought.
+
 
 Complex Examples
 ================
@@ -261,8 +231,10 @@ This is a good topology::
 When device D1 is accessed, accesses to D2 are locked out for the
 full duration of the operation (muxes on the top child adapter of M1
 are locked). But accesses to D3 and D4 are possibly interleaved at
-any point. Accesses to D3 locks out D1 and D2, but accesses to D4
-are still possibly interleaved.
+any point.
+
+Accesses to D3 locks out D1 and D2, but accesses to D4 are still possibly
+interleaved.
 
 
 Mux-locked mux as parent of parent-locked mux
@@ -394,3 +366,47 @@ This is a good topology::
 When D1 or D2 are accessed, accesses to D3 and D4 are locked out while
 accesses to D5 may interleave. When D3 or D4 are accessed, accesses to
 all other devices are locked out.
+
+
+Mux type of existing device drivers
+===================================
+
+Whether a device is mux-locked or parent-locked depends on its
+implementation. The following list was correct at the time of writing:
+
+In drivers/i2c/muxes/:
+
+======================    =============================================
+i2c-arb-gpio-challenge    Parent-locked
+i2c-mux-gpio              Normally parent-locked, mux-locked iff
+                          all involved gpio pins are controlled by the
+                          same I2C root adapter that they mux.
+i2c-mux-gpmux             Normally parent-locked, mux-locked iff
+                          specified in device-tree.
+i2c-mux-ltc4306           Mux-locked
+i2c-mux-mlxcpld           Parent-locked
+i2c-mux-pca9541           Parent-locked
+i2c-mux-pca954x           Parent-locked
+i2c-mux-pinctrl           Normally parent-locked, mux-locked iff
+                          all involved pinctrl devices are controlled
+                          by the same I2C root adapter that they mux.
+i2c-mux-reg               Parent-locked
+======================    =============================================
+
+In drivers/iio/:
+
+======================    =============================================
+gyro/mpu3050              Mux-locked
+imu/inv_mpu6050/          Mux-locked
+======================    =============================================
+
+In drivers/media/:
+
+=======================   =============================================
+dvb-frontends/lgdt3306a   Mux-locked
+dvb-frontends/m88ds3103   Parent-locked
+dvb-frontends/rtl2830     Parent-locked
+dvb-frontends/rtl2832     Mux-locked
+dvb-frontends/si2168      Mux-locked
+usb/cx231xx/              Parent-locked
+=======================   =============================================
index f615906..6d72139 100644 (file)
@@ -517,6 +517,7 @@ All I-Force devices are supported by the iforce module. This includes:
 * AVB Mag Turbo Force
 * AVB Top Shot Pegasus
 * AVB Top Shot Force Feedback Racing Wheel
+* Boeder Force Feedback Wheel
 * Logitech WingMan Force
 * Logitech WingMan Force Wheel
 * Guillemot Race Leader Force Feedback
index 7fb3986..858ed5d 100644 (file)
@@ -525,8 +525,8 @@ followed by a test macro::
 If you need to expose a compiler capability to makefiles and/or C source files,
 `CC_HAS_` is the recommended prefix for the config option::
 
-  config CC_HAS_ASM_GOTO
-       def_bool $(success,$(srctree)/scripts/gcc-goto.sh $(CC))
+  config CC_HAS_FOO
+       def_bool $(success,$(srctree)/scripts/cc-check-foo.sh $(CC))
 
 Build as module only
 ~~~~~~~~~~~~~~~~~~~~
index 8a292fb..ec5e6d7 100644 (file)
@@ -67,7 +67,7 @@ The ``netdevsim`` driver supports rate objects management, which includes:
 - setting tx_share and tx_max rate values for any rate object type;
 - setting parent node for any rate object type.
 
-Rate nodes and it's parameters are exposed in ``netdevsim`` debugfs in RO mode.
+Rate nodes and their parameters are exposed in ``netdevsim`` debugfs in RO mode.
 For example created rate node with name ``some_group``:
 
 .. code:: shell
index c8f59db..64f7236 100644 (file)
@@ -8,7 +8,7 @@ Transmit path guidelines:
 
 1) The ndo_start_xmit method must not return NETDEV_TX_BUSY under
    any normal circumstances.  It is considered a hard error unless
-   there is no way your device can tell ahead of time when it's
+   there is no way your device can tell ahead of time when its
    transmit function will become busy.
 
    Instead it must maintain the queue properly.  For example,
index 56cd4ea..a759872 100644 (file)
@@ -1035,7 +1035,10 @@ tcp_limit_output_bytes - INTEGER
 tcp_challenge_ack_limit - INTEGER
        Limits number of Challenge ACK sent per second, as recommended
        in RFC 5961 (Improving TCP's Robustness to Blind In-Window Attacks)
-       Default: 1000
+       Note that this per netns rate limit can allow some side channel
+       attacks and probably should not be enabled.
+       TCP stack implements per TCP socket limits anyway.
+       Default: INT_MAX (unlimited)
 
 UDP variables
 =============
index 694adcb..0000c1d 100644 (file)
@@ -11,7 +11,7 @@ Initial Release:
 ================
 This is conceptually very similar to the macvlan driver with one major
 exception of using L3 for mux-ing /demux-ing among slaves. This property makes
-the master device share the L2 with it's slave devices. I have developed this
+the master device share the L2 with its slave devices. I have developed this
 driver in conjunction with network namespaces and not sure if there is use case
 outside of it.
 
index 498b382..7f383e9 100644 (file)
@@ -530,7 +530,7 @@ its tunnel close actions. For L2TPIP sockets, the socket's close
 handler initiates the same tunnel close actions. All sessions are
 first closed. Each session drops its tunnel ref. When the tunnel ref
 reaches zero, the tunnel puts its socket ref. When the socket is
-eventually destroyed, it's sk_destruct finally frees the L2TP tunnel
+eventually destroyed, its sk_destruct finally frees the L2TP tunnel
 context.
 
 Sessions
index 39c2249..39494a6 100644 (file)
@@ -1055,17 +1055,6 @@ The kernel interface functions are as follows:
      first function to change.  Note that this must be called in TASK_RUNNING
      state.
 
- (#) Get reply timestamp::
-
-       bool rxrpc_kernel_get_reply_time(struct socket *sock,
-                                        struct rxrpc_call *call,
-                                        ktime_t *_ts)
-
-     This allows the timestamp on the first DATA packet of the reply of a
-     client call to be queried, provided that it is still in the Rx ring.  If
-     successful, the timestamp will be stored into ``*_ts`` and true will be
-     returned; false will be returned otherwise.
-
  (#) Get remote client epoch::
 
        u32 rxrpc_kernel_get_epoch(struct socket *sock,
index f1f4e6a..bbf272e 100644 (file)
@@ -159,7 +159,7 @@ tools such as iproute2.
 
 The switchdev driver can know a particular port's position in the topology by
 monitoring NETDEV_CHANGEUPPER notifications.  For example, a port moved into a
-bond will see it's upper master change.  If that bond is moved into a bridge,
+bond will see its upper master change.  If that bond is moved into a bridge,
 the bond's upper master will change.  And so on.  The driver will track such
 movements to know what position a port is in in the overall topology by
 registering for netdevice events and acting on NETDEV_CHANGEUPPER.
index 2a29cbe..9707e03 100644 (file)
 
 % Translations have Asian (CJK) characters which are only displayed if
 % xeCJK is used
+\usepackage{ifthen}
+\newboolean{enablecjk}
+\setboolean{enablecjk}{false}
 \IfFontExistsTF{Noto Sans CJK SC}{
-    % Load xeCJK when CJK font is available
+    \IfFileExists{xeCJK.sty}{
+       \setboolean{enablecjk}{true}
+    }{}
+}{}
+\ifthenelse{\boolean{enablecjk}}{
+    % Load xeCJK when both the Noto Sans CJK font and xeCJK.sty are available.
     \usepackage{xeCJK}
     % Noto CJK fonts don't provide slant shape. [AutoFakeSlant] permits
     % its emulation.
     % Inactivate CJK after tableofcontents
     \apptocmd{\sphinxtableofcontents}{\kerneldocCJKoff}{}{}
     \xeCJKsetup{CJKspace = true}% For inter-phrase space of Korean TOC
-}{ % No CJK font found
+}{ % Don't enable CJK
     % Custom macros to on/off CJK and switch CJK fonts (Dummy)
     \newcommand{\kerneldocCJKon}{}
     \newcommand{\kerneldocCJKoff}{}
     %% and ignore the argument (#1) in their definitions, whole contents of
     %% CJK chapters can be ignored.
     \newcommand{\kerneldocBeginSC}[1]{%
-       %% Put a note on missing CJK fonts in place of zh_CN translation.
-       \begin{sphinxadmonition}{note}{Note on missing fonts:}
+       %% Put a note on missing CJK fonts or the xecjk package in place of
+       %% zh_CN translation.
+       \begin{sphinxadmonition}{note}{Note on missing fonts and a package:}
            Translations of Simplified Chinese (zh\_CN), Traditional Chinese
            (zh\_TW), Korean (ko\_KR), and Japanese (ja\_JP) were skipped
-           due to the lack of suitable font families.
+           due to the lack of suitable font families and/or the texlive-xecjk
+           package.
 
            If you want them, please install ``Noto Sans CJK'' font families
-           by following instructions from
+           along with the texlive-xecjk package by following instructions from
            \sphinxcode{./scripts/sphinx-pre-install}.
            Having optional ``Noto Serif CJK'' font families will improve
            the looks of those translations.
index e12eae1..6bf7f0c 100644 (file)
@@ -33,7 +33,7 @@ EXAMPLE
 =======
 In the example below, **rtla timerlat hist** is set to run for *10* minutes,
 in the cpus *0-4*, *skipping zero* only lines. Moreover, **rtla timerlat
-hist** will change the priority of the *timelat* threads to run under
+hist** will change the priority of the *timerlat* threads to run under
 *SCHED_DEADLINE* priority, with a *10us* runtime every *1ms* period. The
 *1ms* period is also passed to the *timerlat* tracer::
 
index 66ce0d8..04deb77 100644 (file)
@@ -35,8 +35,7 @@ Linux カーネルに変更を加えたいと思っている個人又は会社
 てもらえやすくする提案を集めたものです。
 
 コードを投稿する前に、Documentation/process/submit-checklist.rst の項目リストに目
-を通してチェックしてください。もしあなたがドライバーを投稿しようとし
-ているなら、Documentation/process/submitting-drivers.rst にも目を通してください。
+を通してチェックしてください。
 
 --------------------------------------------
 セクション1 パッチの作り方と送り方
index 8a5012b..9ae989b 100644 (file)
@@ -1803,7 +1803,7 @@ N:        sun[x456789]i
 N:     sun50i
 
 ARM/Amlogic Meson SoC CLOCK FRAMEWORK
-M:     Neil Armstrong <narmstrong@baylibre.com>
+M:     Neil Armstrong <neil.armstrong@linaro.org>
 M:     Jerome Brunet <jbrunet@baylibre.com>
 L:     linux-amlogic@lists.infradead.org
 S:     Maintained
@@ -1828,7 +1828,7 @@ F:        Documentation/devicetree/bindings/sound/amlogic*
 F:     sound/soc/meson/
 
 ARM/Amlogic Meson SoC support
-M:     Neil Armstrong <narmstrong@baylibre.com>
+M:     Neil Armstrong <neil.armstrong@linaro.org>
 M:     Kevin Hilman <khilman@baylibre.com>
 R:     Jerome Brunet <jbrunet@baylibre.com>
 R:     Martin Blumenstingl <martin.blumenstingl@googlemail.com>
@@ -2178,7 +2178,7 @@ M:        Jean-Marie Verdun <verdun@hpe.com>
 M:     Nick Hawkins <nick.hawkins@hpe.com>
 S:     Maintained
 F:     Documentation/devicetree/bindings/arm/hpe,gxp.yaml
-F:     Documentation/devicetree/bindings/spi/hpe,gxp-spi.yaml
+F:     Documentation/devicetree/bindings/spi/hpe,gxp-spifi.yaml
 F:     Documentation/devicetree/bindings/timer/hpe,gxp-timer.yaml
 F:     arch/arm/boot/dts/hpe-bmc*
 F:     arch/arm/boot/dts/hpe-gxp*
@@ -2531,7 +2531,7 @@ W:        http://www.digriz.org.uk/ts78xx/kernel
 F:     arch/arm/mach-orion5x/ts78xx-*
 
 ARM/OXNAS platform support
-M:     Neil Armstrong <narmstrong@baylibre.com>
+M:     Neil Armstrong <neil.armstrong@linaro.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 L:     linux-oxnas@groups.io (moderated for non-subscribers)
 S:     Maintained
@@ -3612,6 +3612,7 @@ F:        include/linux/find.h
 F:     include/linux/nodemask.h
 F:     lib/bitmap.c
 F:     lib/cpumask.c
+F:     lib/cpumask_kunit.c
 F:     lib/find_bit.c
 F:     lib/find_bit_benchmark.c
 F:     lib/test_bitmap.c
@@ -3679,6 +3680,7 @@ F:        Documentation/networking/bonding.rst
 F:     drivers/net/bonding/
 F:     include/net/bond*
 F:     include/uapi/linux/if_bonding.h
+F:     tools/testing/selftests/drivers/net/bonding/
 
 BOSCH SENSORTEC BMA400 ACCELEROMETER IIO DRIVER
 M:     Dan Robertson <dan@dlrobertson.com>
@@ -5145,6 +5147,7 @@ T:        git git://git.samba.org/sfrench/cifs-2.6.git
 F:     Documentation/admin-guide/cifs/
 F:     fs/cifs/
 F:     fs/smbfs_common/
+F:     include/uapi/linux/cifs
 
 COMPACTPCI HOTPLUG CORE
 M:     Scott Murray <scott@spiteful.org>
@@ -6789,7 +6792,7 @@ F:        Documentation/devicetree/bindings/display/allwinner*
 F:     drivers/gpu/drm/sun4i/
 
 DRM DRIVERS FOR AMLOGIC SOCS
-M:     Neil Armstrong <narmstrong@baylibre.com>
+M:     Neil Armstrong <neil.armstrong@linaro.org>
 L:     dri-devel@lists.freedesktop.org
 L:     linux-amlogic@lists.infradead.org
 S:     Supported
@@ -6811,7 +6814,7 @@ F:        drivers/gpu/drm/atmel-hlcdc/
 
 DRM DRIVERS FOR BRIDGE CHIPS
 M:     Andrzej Hajda <andrzej.hajda@intel.com>
-M:     Neil Armstrong <narmstrong@baylibre.com>
+M:     Neil Armstrong <neil.armstrong@linaro.org>
 M:     Robert Foss <robert.foss@linaro.org>
 R:     Laurent Pinchart <Laurent.pinchart@ideasonboard.com>
 R:     Jonas Karlman <jonas@kwiboo.se>
@@ -9119,7 +9122,7 @@ S:        Maintained
 F:     drivers/dma/hisi_dma.c
 
 HISILICON GPIO DRIVER
-M:     Luo Jiaxing <luojiaxing@huawei.com>
+M:     Jay Fang <f.fangjian@huawei.com>
 L:     linux-gpio@vger.kernel.org
 S:     Maintained
 F:     drivers/gpio/gpio-hisi.c
@@ -9205,8 +9208,8 @@ F:        Documentation/ABI/testing/debugfs-hisi-zip
 F:     drivers/crypto/hisilicon/zip/
 
 HISILICON ROCE DRIVER
+M:     Haoyue Xu <xuhaoyue1@hisilicon.com>
 M:     Wenpeng Liang <liangwenpeng@huawei.com>
-M:     Weihang Li <liweihang@huawei.com>
 L:     linux-rdma@vger.kernel.org
 S:     Maintained
 F:     Documentation/devicetree/bindings/infiniband/hisilicon-hns-roce.txt
@@ -9780,7 +9783,7 @@ M:        Christian Brauner <brauner@kernel.org>
 M:     Seth Forshee <sforshee@kernel.org>
 L:     linux-fsdevel@vger.kernel.org
 S:     Maintained
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux.git
+T:     git://git.kernel.org/pub/scm/linux/kernel/git/vfs/idmapping.git
 F:     Documentation/filesystems/idmappings.rst
 F:     tools/testing/selftests/mount_setattr/
 F:     include/linux/mnt_idmapping.h
@@ -10029,6 +10032,7 @@ F:      Documentation/devicetree/bindings/input/
 F:     Documentation/devicetree/bindings/serio/
 F:     Documentation/input/
 F:     drivers/input/
+F:     include/dt-bindings/input/
 F:     include/linux/input.h
 F:     include/linux/input/
 F:     include/uapi/linux/input-event-codes.h
@@ -10657,6 +10661,7 @@ T:      git git://git.kernel.dk/linux-block
 T:     git git://git.kernel.dk/liburing
 F:     io_uring/
 F:     include/linux/io_uring.h
+F:     include/linux/io_uring_types.h
 F:     include/uapi/linux/io_uring.h
 F:     tools/io_uring/
 
@@ -10823,7 +10828,7 @@ F:      drivers/media/tuners/it913x*
 
 ITE IT66121 HDMI BRIDGE DRIVER
 M:     Phong LE <ple@baylibre.com>
-M:     Neil Armstrong <narmstrong@baylibre.com>
+M:     Neil Armstrong <neil.armstrong@linaro.org>
 S:     Maintained
 T:     git git://anongit.freedesktop.org/drm/drm-misc
 F:     Documentation/devicetree/bindings/display/bridge/ite,it66121.yaml
@@ -11342,7 +11347,7 @@ F:      kernel/debug/
 F:     kernel/module/kdb.c
 
 KHADAS MCU MFD DRIVER
-M:     Neil Armstrong <narmstrong@baylibre.com>
+M:     Neil Armstrong <neil.armstrong@linaro.org>
 L:     linux-amlogic@lists.infradead.org
 S:     Maintained
 F:     Documentation/devicetree/bindings/mfd/khadas,mcu.yaml
@@ -13213,7 +13218,7 @@ S:      Maintained
 F:     drivers/watchdog/menz69_wdt.c
 
 MESON AO CEC DRIVER FOR AMLOGIC SOCS
-M:     Neil Armstrong <narmstrong@baylibre.com>
+M:     Neil Armstrong <neil.armstrong@linaro.org>
 L:     linux-media@vger.kernel.org
 L:     linux-amlogic@lists.infradead.org
 S:     Supported
@@ -13224,7 +13229,7 @@ F:      drivers/media/cec/platform/meson/ao-cec-g12a.c
 F:     drivers/media/cec/platform/meson/ao-cec.c
 
 MESON GE2D DRIVER FOR AMLOGIC SOCS
-M:     Neil Armstrong <narmstrong@baylibre.com>
+M:     Neil Armstrong <neil.armstrong@linaro.org>
 L:     linux-media@vger.kernel.org
 L:     linux-amlogic@lists.infradead.org
 S:     Supported
@@ -13240,7 +13245,7 @@ F:      Documentation/devicetree/bindings/mtd/amlogic,meson-nand.txt
 F:     drivers/mtd/nand/raw/meson_*
 
 MESON VIDEO DECODER DRIVER FOR AMLOGIC SOCS
-M:     Neil Armstrong <narmstrong@baylibre.com>
+M:     Neil Armstrong <neil.armstrong@linaro.org>
 L:     linux-media@vger.kernel.org
 L:     linux-amlogic@lists.infradead.org
 S:     Supported
@@ -17527,9 +17532,19 @@ M:     Conor Dooley <conor.dooley@microchip.com>
 M:     Daire McNamara <daire.mcnamara@microchip.com>
 L:     linux-riscv@lists.infradead.org
 S:     Supported
+F:     Documentation/devicetree/bindings/clock/microchip,mpfs.yaml
+F:     Documentation/devicetree/bindings/gpio/microchip,mpfs-gpio.yaml
+F:     Documentation/devicetree/bindings/i2c/microchip,corei2c.yaml
+F:     Documentation/devicetree/bindings/mailbox/microchip,mpfs-mailbox.yaml
+F:     Documentation/devicetree/bindings/net/can/microchip,mpfs-can.yaml
+F:     Documentation/devicetree/bindings/pwm/microchip,corepwm.yaml
+F:     Documentation/devicetree/bindings/soc/microchip/microchip,mpfs-sys-controller.yaml
+F:     Documentation/devicetree/bindings/spi/microchip,mpfs-spi.yaml
+F:     Documentation/devicetree/bindings/usb/microchip,mpfs-musb.yaml
 F:     arch/riscv/boot/dts/microchip/
 F:     drivers/char/hw_random/mpfs-rng.c
 F:     drivers/clk/microchip/clk-mpfs.c
+F:     drivers/i2c/busses/i2c-microchip-core.c
 F:     drivers/mailbox/mailbox-mpfs.c
 F:     drivers/pci/controller/pcie-microchip-host.c
 F:     drivers/rtc/rtc-mpfs.c
@@ -17730,6 +17745,17 @@ L:     linux-rdma@vger.kernel.org
 S:     Maintained
 F:     drivers/infiniband/ulp/rtrs/
 
+RUNTIME VERIFICATION (RV)
+M:     Daniel Bristot de Oliveira <bristot@kernel.org>
+M:     Steven Rostedt <rostedt@goodmis.org>
+L:     linux-trace-devel@vger.kernel.org
+S:     Maintained
+F:     Documentation/trace/rv/
+F:     include/linux/rv.h
+F:     include/rv/
+F:     kernel/trace/rv/
+F:     tools/verification/
+
 RXRPC SOCKETS (AF_RXRPC)
 M:     David Howells <dhowells@redhat.com>
 M:     Marc Dionne <marc.dionne@auristor.com>
@@ -20596,6 +20622,7 @@ F:      include/*/ftrace.h
 F:     include/linux/trace*.h
 F:     include/trace/
 F:     kernel/trace/
+F:     scripts/tracing/
 F:     tools/testing/selftests/ftrace/
 
 TRACING MMIO ACCESSES (MMIOTRACE)
@@ -20760,6 +20787,7 @@ UBLK USERSPACE BLOCK DRIVER
 M:     Ming Lei <ming.lei@redhat.com>
 L:     linux-block@vger.kernel.org
 S:     Maintained
+F:     Documentation/block/ublk.rst
 F:     drivers/block/ublk_drv.c
 F:     include/uapi/linux/ublk_cmd.h
 
@@ -22301,7 +22329,7 @@ M:      Shubhrajyoti Datta <shubhrajyoti.datta@xilinx.com>
 R:     Srinivas Neeli <srinivas.neeli@xilinx.com>
 R:     Michal Simek <michal.simek@xilinx.com>
 S:     Maintained
-F:     Documentation/devicetree/bindings/gpio/gpio-xilinx.txt
+F:     Documentation/devicetree/bindings/gpio/xlnx,gpio-xilinx.yaml
 F:     Documentation/devicetree/bindings/gpio/gpio-zynq.yaml
 F:     drivers/gpio/gpio-xilinx.c
 F:     drivers/gpio/gpio-zynq.c
index f09673b..298f690 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
 VERSION = 6
 PATCHLEVEL = 0
 SUBLEVEL = 0
-EXTRAVERSION = -rc1
+EXTRAVERSION = -rc6
 NAME = Hurr durr I'ma ninja sloth
 
 # *DOCUMENTATION*
@@ -1113,13 +1113,11 @@ vmlinux-alldirs := $(sort $(vmlinux-dirs) Documentation \
                     $(patsubst %/,%,$(filter %/, $(core-) \
                        $(drivers-) $(libs-))))
 
-subdir-modorder := $(addsuffix modules.order,$(filter %/, \
-                       $(core-y) $(core-m) $(libs-y) $(libs-m) \
-                       $(drivers-y) $(drivers-m)))
-
 build-dirs     := $(vmlinux-dirs)
 clean-dirs     := $(vmlinux-alldirs)
 
+subdir-modorder := $(addsuffix /modules.order, $(build-dirs))
+
 # Externally visible symbols (used by link-vmlinux.sh)
 KBUILD_VMLINUX_OBJS := $(head-y) $(patsubst %/,%/built-in.a, $(core-y))
 KBUILD_VMLINUX_OBJS += $(addsuffix built-in.a, $(filter %/, $(libs-y)))
@@ -1289,8 +1287,7 @@ hdr-inst := -f $(srctree)/scripts/Makefile.headersinst obj
 
 PHONY += headers
 headers: $(version_h) scripts_unifdef uapi-asm-generic archheaders archscripts
-       $(if $(wildcard $(srctree)/arch/$(SRCARCH)/include/uapi/asm/Kbuild),, \
-         $(error Headers not exportable for the $(SRCARCH) architecture))
+       $(if $(filter um, $(SRCARCH)), $(error Headers not exportable for UML))
        $(Q)$(MAKE) $(hdr-inst)=include/uapi
        $(Q)$(MAKE) $(hdr-inst)=arch/$(SRCARCH)/include/uapi
 
index f330410..8b311e4 100644 (file)
@@ -53,7 +53,6 @@ config KPROBES
 config JUMP_LABEL
        bool "Optimize very unlikely/likely branches"
        depends on HAVE_ARCH_JUMP_LABEL
-       depends on CC_HAS_ASM_GOTO
        select OBJTOOL if HAVE_JUMP_LABEL_HACK
        help
         This option enables a transparent branch optimization that
@@ -924,6 +923,9 @@ config HAVE_SOFTIRQ_ON_OWN_STACK
          Architecture provides a function to run __do_softirq() on a
          separate stack.
 
+config SOFTIRQ_ON_OWN_STACK
+       def_bool HAVE_SOFTIRQ_ON_OWN_STACK && !PREEMPT_RT
+
 config ALTERNATE_USER_ADDRESS_SPACE
        bool
        help
@@ -1361,7 +1363,7 @@ config HAVE_PREEMPT_DYNAMIC_CALL
 
 config HAVE_PREEMPT_DYNAMIC_KEY
        bool
-       depends on HAVE_ARCH_JUMP_LABEL && CC_HAS_ASM_GOTO
+       depends on HAVE_ARCH_JUMP_LABEL
        select HAVE_PREEMPT_DYNAMIC
        help
           An architecture should select this if it can handle the preemption
index 492c771..bafb1c1 100644 (file)
@@ -283,11 +283,8 @@ arch___test_and_change_bit(unsigned long nr, volatile unsigned long *addr)
        return (old & mask) != 0;
 }
 
-static __always_inline bool
-arch_test_bit(unsigned long nr, const volatile unsigned long *addr)
-{
-       return (1UL & (((const int *) addr)[nr >> 5] >> (nr & 31))) != 0UL;
-}
+#define arch_test_bit generic_test_bit
+#define arch_test_bit_acquire generic_test_bit_acquire
 
 /*
  * ffz = Find First Zero in word. Undefined if no zero exists,
index 2dfb32b..fbb2258 100644 (file)
                        compatible = "arm,pl022", "arm,primecell";
                        reg = <0x1000d000 0x1000>;
                        clocks = <&sspclk>, <&pclk>;
-                       clock-names = "SSPCLK", "apb_pclk";
+                       clock-names = "sspclk", "apb_pclk";
                };
 
                wdog: watchdog@10010000 {
index 06b8723..efed325 100644 (file)
                        interrupt-parent = <&intc_dc1176>;
                        interrupts = <0 17 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&sspclk>, <&pclk>;
-                       clock-names = "SSPCLK", "apb_pclk";
+                       clock-names = "sspclk", "apb_pclk";
                };
 
                pb1176_serial0: serial@1010c000 {
index 295aef4..89103d5 100644 (file)
                        interrupt-parent = <&intc_pb11mp>;
                        interrupts = <0 11 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&sspclk>, <&pclk>;
-                       clock-names = "SSPCLK", "apb_pclk";
+                       clock-names = "sspclk", "apb_pclk";
                };
 
                watchdog@1000f000 {
index 6f61f96..ec1507c 100644 (file)
                        compatible = "arm,pl022", "arm,primecell";
                        reg = <0x1000d000 0x1000>;
                        clocks = <&sspclk>, <&pclk>;
-                       clock-names = "SSPCLK", "apb_pclk";
+                       clock-names = "sspclk", "apb_pclk";
                };
 
                wdog0: watchdog@1000f000 {
index 76b2025..83bcf9f 100644 (file)
@@ -76,8 +76,8 @@
                regulators {
                        vdd_3v3: VDD_IO {
                                regulator-name = "VDD_IO";
-                               regulator-min-microvolt = <1200000>;
-                               regulator-max-microvolt = <3700000>;
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
                                regulator-initial-mode = <2>;
                                regulator-allowed-modes = <2>, <4>;
                                regulator-always-on;
@@ -95,8 +95,8 @@
 
                        vddio_ddr: VDD_DDR {
                                regulator-name = "VDD_DDR";
-                               regulator-min-microvolt = <600000>;
-                               regulator-max-microvolt = <1850000>;
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <1200000>;
                                regulator-initial-mode = <2>;
                                regulator-allowed-modes = <2>, <4>;
                                regulator-always-on;
 
                        vdd_core: VDD_CORE {
                                regulator-name = "VDD_CORE";
-                               regulator-min-microvolt = <600000>;
-                               regulator-max-microvolt = <1850000>;
+                               regulator-min-microvolt = <1250000>;
+                               regulator-max-microvolt = <1250000>;
                                regulator-initial-mode = <2>;
                                regulator-allowed-modes = <2>, <4>;
                                regulator-always-on;
 
                        LDO1 {
                                regulator-name = "LDO1";
-                               regulator-min-microvolt = <1200000>;
-                               regulator-max-microvolt = <3700000>;
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
                                regulator-always-on;
 
                                regulator-state-standby {
 
                        LDO2 {
                                regulator-name = "LDO2";
-                               regulator-min-microvolt = <1200000>;
-                               regulator-max-microvolt = <3700000>;
-                               regulator-always-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
 
                                regulator-state-standby {
                                        regulator-on-in-suspend;
index 6865be8..dd1dec9 100644 (file)
                        regulators {
                                vdd_io_reg: VDD_IO {
                                        regulator-name = "VDD_IO";
-                                       regulator-min-microvolt = <1200000>;
-                                       regulator-max-microvolt = <3700000>;
+                                       regulator-min-microvolt = <3300000>;
+                                       regulator-max-microvolt = <3300000>;
                                        regulator-initial-mode = <2>;
                                        regulator-allowed-modes = <2>, <4>;
                                        regulator-always-on;
 
                                VDD_DDR {
                                        regulator-name = "VDD_DDR";
-                                       regulator-min-microvolt = <600000>;
-                                       regulator-max-microvolt = <1850000>;
+                                       regulator-min-microvolt = <1350000>;
+                                       regulator-max-microvolt = <1350000>;
                                        regulator-initial-mode = <2>;
                                        regulator-allowed-modes = <2>, <4>;
                                        regulator-always-on;
 
                                VDD_CORE {
                                        regulator-name = "VDD_CORE";
-                                       regulator-min-microvolt = <600000>;
-                                       regulator-max-microvolt = <1850000>;
+                                       regulator-min-microvolt = <1250000>;
+                                       regulator-max-microvolt = <1250000>;
                                        regulator-initial-mode = <2>;
                                        regulator-allowed-modes = <2>, <4>;
                                        regulator-always-on;
                                        regulator-max-microvolt = <1850000>;
                                        regulator-initial-mode = <2>;
                                        regulator-allowed-modes = <2>, <4>;
-                                       regulator-always-on;
 
                                        regulator-state-standby {
                                                regulator-on-in-suspend;
 
                                LDO1 {
                                        regulator-name = "LDO1";
-                                       regulator-min-microvolt = <1200000>;
-                                       regulator-max-microvolt = <3700000>;
+                                       regulator-min-microvolt = <2500000>;
+                                       regulator-max-microvolt = <2500000>;
                                        regulator-always-on;
 
                                        regulator-state-standby {
 
                                LDO2 {
                                        regulator-name = "LDO2";
-                                       regulator-min-microvolt = <1200000>;
-                                       regulator-max-microvolt = <3700000>;
+                                       regulator-min-microvolt = <3300000>;
+                                       regulator-max-microvolt = <3300000>;
                                        regulator-always-on;
 
                                        regulator-state-standby {
index de44da2..3b25c67 100644 (file)
                        regulators {
                                vdd_3v3: VDD_IO {
                                        regulator-name = "VDD_IO";
-                                       regulator-min-microvolt = <1200000>;
-                                       regulator-max-microvolt = <3700000>;
+                                       regulator-min-microvolt = <3300000>;
+                                       regulator-max-microvolt = <3300000>;
                                        regulator-initial-mode = <2>;
                                        regulator-allowed-modes = <2>, <4>;
                                        regulator-always-on;
 
                                vddioddr: VDD_DDR {
                                        regulator-name = "VDD_DDR";
-                                       regulator-min-microvolt = <1300000>;
-                                       regulator-max-microvolt = <1450000>;
+                                       regulator-min-microvolt = <1350000>;
+                                       regulator-max-microvolt = <1350000>;
                                        regulator-initial-mode = <2>;
                                        regulator-allowed-modes = <2>, <4>;
                                        regulator-always-on;
 
                                vddcore: VDD_CORE {
                                        regulator-name = "VDD_CORE";
-                                       regulator-min-microvolt = <1100000>;
-                                       regulator-max-microvolt = <1850000>;
+                                       regulator-min-microvolt = <1150000>;
+                                       regulator-max-microvolt = <1150000>;
                                        regulator-initial-mode = <2>;
                                        regulator-allowed-modes = <2>, <4>;
                                        regulator-always-on;
                                vddcpu: VDD_OTHER {
                                        regulator-name = "VDD_OTHER";
                                        regulator-min-microvolt = <1050000>;
-                                       regulator-max-microvolt = <1850000>;
+                                       regulator-max-microvolt = <1250000>;
                                        regulator-initial-mode = <2>;
                                        regulator-allowed-modes = <2>, <4>;
                                        regulator-ramp-delay = <3125>;
 
                                vldo1: LDO1 {
                                        regulator-name = "LDO1";
-                                       regulator-min-microvolt = <1200000>;
-                                       regulator-max-microvolt = <3700000>;
+                                       regulator-min-microvolt = <1800000>;
+                                       regulator-max-microvolt = <1800000>;
                                        regulator-always-on;
 
                                        regulator-state-standby {
index 5463443..cbd094d 100644 (file)
@@ -32,6 +32,7 @@
                        next-level-cache = <&L2_0>;
                        enable-method = "psci";
                };
+
                CA7_2: cpu@2 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a7";
@@ -39,6 +40,7 @@
                        next-level-cache = <&L2_0>;
                        enable-method = "psci";
                };
+
                L2_0: l2-cache0 {
                        compatible = "cache";
                };
 
        timer {
                compatible = "arm,armv7-timer";
-               interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
-                       <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
-                       <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
-                       <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
+               interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(3) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(3) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(3) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(3) | IRQ_TYPE_LEVEL_LOW)>;
                arm,cpu-registers-not-fw-configured;
        };
 
        psci {
                compatible = "arm,psci-0.2";
                method = "smc";
-               cpu_off = <1>;
-               cpu_on = <2>;
        };
 
        axi@81000000 {
                compatible = "simple-bus";
                #address-cells = <1>;
                #size-cells = <1>;
-               ranges = <0 0x81000000 0x4000>;
+               ranges = <0 0x81000000 0x8000>;
 
                gic: interrupt-controller@1000 {
                        compatible = "arm,cortex-a7-gic";
                        #interrupt-cells = <3>;
-                       #address-cells = <0>;
                        interrupt-controller;
+                       interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(3) | IRQ_TYPE_LEVEL_HIGH)>;
                        reg = <0x1000 0x1000>,
-                               <0x2000 0x2000>;
+                               <0x2000 0x2000>,
+                               <0x4000 0x2000>,
+                               <0x6000 0x2000>;
                };
        };
 
index e610c10..8aa47a2 100644 (file)
 
        timer {
                compatible = "arm,armv7-timer";
-               interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
-                       <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
-                       <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
-                       <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
+               interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>;
                arm,cpu-registers-not-fw-configured;
        };
 
        psci {
                compatible = "arm,psci-0.2";
                method = "smc";
-               cpu_off = <1>;
-               cpu_on = <2>;
        };
 
        axi@81000000 {
                compatible = "simple-bus";
                #address-cells = <1>;
                #size-cells = <1>;
-               ranges = <0 0x81000000 0x4000>;
+               ranges = <0 0x81000000 0x8000>;
 
                gic: interrupt-controller@1000 {
                        compatible = "arm,cortex-a7-gic";
                        #interrupt-cells = <3>;
-                       #address-cells = <0>;
                        interrupt-controller;
+                       interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>;
                        reg = <0x1000 0x1000>,
-                               <0x2000 0x2000>;
+                               <0x2000 0x2000>,
+                               <0x4000 0x2000>,
+                               <0x6000 0x2000>;
                };
        };
 
index a7dff59..1e8b5fa 100644 (file)
@@ -32,6 +32,7 @@
                        next-level-cache = <&L2_0>;
                        enable-method = "psci";
                };
+
                L2_0: l2-cache0 {
                        compatible = "cache";
                };
 
        timer {
                compatible = "arm,armv7-timer";
-               interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
-                       <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
-                       <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
-                       <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
+               interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>;
                arm,cpu-registers-not-fw-configured;
        };
 
index 095c914..6b791d5 100644 (file)
                vin-supply = <&reg_3p3v_s5>;
        };
 
-       reg_3p3v_s0: regulator-3p3v-s0 {
-               compatible = "regulator-fixed";
-               regulator-name = "V_3V3_S0";
-               regulator-min-microvolt = <3300000>;
-               regulator-max-microvolt = <3300000>;
-               regulator-always-on;
-               regulator-boot-on;
-               vin-supply = <&reg_3p3v_s5>;
-       };
-
        reg_3p3v_s5: regulator-3p3v-s5 {
                compatible = "regulator-fixed";
                regulator-name = "V_3V3_S5";
 
        /* default boot source: workaround #1 for errata ERR006282 */
        smarc_flash: flash@0 {
-               compatible = "winbond,w25q16dw", "jedec,spi-nor";
+               compatible = "jedec,spi-nor";
                reg = <0>;
                spi-max-frequency = <20000000>;
        };
index a1676b5..c5a98b0 100644 (file)
@@ -28,7 +28,7 @@
                enable-gpios = <&gpio4 28 GPIO_ACTIVE_HIGH>;
        };
 
-       backlight_led: backlight_led {
+       backlight_led: backlight-led {
                compatible = "pwm-backlight";
                pwms = <&pwm3 0 5000000 0>;
                brightness-levels = <0 16 64 255>;
index d47bfb6..4c22e44 100644 (file)
                clock-names = "uartclk", "apb_pclk";
        };
 
-       ssp@300000 {
+       spi@300000 {
                compatible = "arm,pl022", "arm,primecell";
                reg = <0x00300000 0x1000>;
                interrupts-extended = <&impd1_vic 3>;
                clocks = <&impd1_sspclk>, <&sysclk>;
-               clock-names = "spiclk", "apb_pclk";
+               clock-names = "sspclk", "apb_pclk";
        };
 
        impd1_gpio0: gpio@400000 {
index 79f7cc2..a520615 100644 (file)
                        reg = <0x101f4000 0x1000>;
                        interrupts = <11>;
                        clocks = <&xtal24mhz>, <&pclk>;
-                       clock-names = "SSPCLK", "apb_pclk";
+                       clock-names = "sspclk", "apb_pclk";
                };
 
                fpga {
index da90ce9..e185eee 100644 (file)
@@ -196,7 +196,6 @@ CONFIG_RTC_DRV_AT91SAM9=y
 CONFIG_DMADEVICES=y
 CONFIG_AT_HDMAC=y
 CONFIG_AT_XDMAC=y
-CONFIG_MICROCHIP_PIT64B=y
 # CONFIG_IOMMU_SUPPORT is not set
 CONFIG_IIO=y
 CONFIG_AT91_ADC=y
index 0384030..b2311f0 100644 (file)
@@ -188,7 +188,6 @@ CONFIG_RTC_DRV_AT91SAM9=y
 CONFIG_DMADEVICES=y
 CONFIG_AT_XDMAC=y
 CONFIG_STAGING=y
-CONFIG_MICROCHIP_PIT64B=y
 # CONFIG_IOMMU_SUPPORT is not set
 CONFIG_IIO=y
 CONFIG_IIO_SW_TRIGGER=y
index 034cb48..fe28fc1 100644 (file)
@@ -70,7 +70,7 @@ static void __init init_irq_stacks(void)
        }
 }
 
-#ifndef CONFIG_PREEMPT_RT
+#ifdef CONFIG_SOFTIRQ_ON_OWN_STACK
 static void ____do_softirq(void *arg)
 {
        __do_softirq();
index df6d673..f4501de 100644 (file)
@@ -541,10 +541,42 @@ extern u32 at91_pm_suspend_in_sram_sz;
 
 static int at91_suspend_finish(unsigned long val)
 {
+       unsigned char modified_gray_code[] = {
+               0x00, 0x01, 0x02, 0x03, 0x06, 0x07, 0x04, 0x05, 0x0c, 0x0d,
+               0x0e, 0x0f, 0x0a, 0x0b, 0x08, 0x09, 0x18, 0x19, 0x1a, 0x1b,
+               0x1e, 0x1f, 0x1c, 0x1d, 0x14, 0x15, 0x16, 0x17, 0x12, 0x13,
+               0x10, 0x11,
+       };
+       unsigned int tmp, index;
        int i;
 
        if (soc_pm.data.mode == AT91_PM_BACKUP && soc_pm.data.ramc_phy) {
                /*
+                * Bootloader will perform DDR recalibration and will try to
+                * restore the ZQ0SR0 with the value saved here. But the
+                * calibration is buggy and restoring some values from ZQ0SR0
+                * is forbidden and risky thus we need to provide processed
+                * values for these (modified gray code values).
+                */
+               tmp = readl(soc_pm.data.ramc_phy + DDR3PHY_ZQ0SR0);
+
+               /* Store pull-down output impedance select. */
+               index = (tmp >> DDR3PHY_ZQ0SR0_PDO_OFF) & 0x1f;
+               soc_pm.bu->ddr_phy_calibration[0] = modified_gray_code[index];
+
+               /* Store pull-up output impedance select. */
+               index = (tmp >> DDR3PHY_ZQ0SR0_PUO_OFF) & 0x1f;
+               soc_pm.bu->ddr_phy_calibration[0] |= modified_gray_code[index];
+
+               /* Store pull-down on-die termination impedance select. */
+               index = (tmp >> DDR3PHY_ZQ0SR0_PDODT_OFF) & 0x1f;
+               soc_pm.bu->ddr_phy_calibration[0] |= modified_gray_code[index];
+
+               /* Store pull-up on-die termination impedance select. */
+               index = (tmp >> DDR3PHY_ZQ0SRO_PUODT_OFF) & 0x1f;
+               soc_pm.bu->ddr_phy_calibration[0] |= modified_gray_code[index];
+
+               /*
                 * The 1st 8 words of memory might get corrupted in the process
                 * of DDR PHY recalibration; it is saved here in securam and it
                 * will be restored later, after recalibration, by bootloader
@@ -1066,10 +1098,6 @@ static int __init at91_pm_backup_init(void)
                of_scan_flat_dt(at91_pm_backup_scan_memcs, &located);
                if (!located)
                        goto securam_fail;
-
-               /* DDR3PHY_ZQ0SR0 */
-               soc_pm.bu->ddr_phy_calibration[0] = readl(soc_pm.data.ramc_phy +
-                                                         0x188);
        }
 
        return 0;
index abe4ced..ffed4d9 100644 (file)
@@ -172,9 +172,15 @@ sr_ena_2:
        /* Put DDR PHY's DLL in bypass mode for non-backup modes. */
        cmp     r7, #AT91_PM_BACKUP
        beq     sr_ena_3
-       ldr     tmp1, [r3, #DDR3PHY_PIR]
-       orr     tmp1, tmp1, #DDR3PHY_PIR_DLLBYP
-       str     tmp1, [r3, #DDR3PHY_PIR]
+
+       /* Disable DX DLLs. */
+       ldr     tmp1, [r3, #DDR3PHY_DX0DLLCR]
+       orr     tmp1, tmp1, #DDR3PHY_DXDLLCR_DLLDIS
+       str     tmp1, [r3, #DDR3PHY_DX0DLLCR]
+
+       ldr     tmp1, [r3, #DDR3PHY_DX1DLLCR]
+       orr     tmp1, tmp1, #DDR3PHY_DXDLLCR_DLLDIS
+       str     tmp1, [r3, #DDR3PHY_DX1DLLCR]
 
 sr_ena_3:
        /* Power down DDR PHY data receivers. */
@@ -221,10 +227,14 @@ sr_ena_3:
        bic     tmp1, tmp1, #DDR3PHY_DSGCR_ODTPDD_ODT0
        str     tmp1, [r3, #DDR3PHY_DSGCR]
 
-       /* Take DDR PHY's DLL out of bypass mode. */
-       ldr     tmp1, [r3, #DDR3PHY_PIR]
-       bic     tmp1, tmp1, #DDR3PHY_PIR_DLLBYP
-       str     tmp1, [r3, #DDR3PHY_PIR]
+       /* Enable DX DLLs. */
+       ldr     tmp1, [r3, #DDR3PHY_DX0DLLCR]
+       bic     tmp1, tmp1, #DDR3PHY_DXDLLCR_DLLDIS
+       str     tmp1, [r3, #DDR3PHY_DX0DLLCR]
+
+       ldr     tmp1, [r3, #DDR3PHY_DX1DLLCR]
+       bic     tmp1, tmp1, #DDR3PHY_DXDLLCR_DLLDIS
+       str     tmp1, [r3, #DDR3PHY_DX1DLLCR]
 
        /* Enable quasi-dynamic programming. */
        mov     tmp1, #0
index f990471..f543e2a 100644 (file)
@@ -46,7 +46,7 @@ static void __init ixp4xx_of_map_io(void)
 }
 
 /*
- * We handle 4 differen SoC families. These compatible strings are enough
+ * We handle 4 different SoC families. These compatible strings are enough
  * to provide the core so that different boards can add their more detailed
  * specifics.
  */
index 571cc23..1ce7685 100644 (file)
@@ -917,6 +917,23 @@ config ARM64_ERRATUM_1902691
 
          If unsure, say Y.
 
+config ARM64_ERRATUM_2457168
+       bool "Cortex-A510: 2457168: workaround for AMEVCNTR01 incrementing incorrectly"
+       depends on ARM64_AMU_EXTN
+       default y
+       help
+         This option adds the workaround for ARM Cortex-A510 erratum 2457168.
+
+         The AMU counter AMEVCNTR01 (constant counter) should increment at the same rate
+         as the system counter. On affected Cortex-A510 cores AMEVCNTR01 increments
+         incorrectly giving a significantly higher output value.
+
+         Work around this problem by returning 0 when reading the affected counter in
+         key locations that results in disabling all users of this counter. This effect
+         is the same to firmware disabling affected counters.
+
+         If unsure, say Y.
+
 config CAVIUM_ERRATUM_22375
        bool "Cavium erratum 22375, 24313"
        default y
@@ -1870,6 +1887,8 @@ config ARM64_BTI_KERNEL
        depends on CC_HAS_BRANCH_PROT_PAC_RET_BTI
        # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94697
        depends on !CC_IS_GCC || GCC_VERSION >= 100100
+       # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106671
+       depends on !CC_IS_GCC
        # https://github.com/llvm/llvm-project/commit/a88c722e687e6780dcd6a58718350dc76fcc4cc9
        depends on !CC_IS_CLANG || CLANG_VERSION >= 120000
        depends on (!FUNCTION_GRAPH_TRACER || DYNAMIC_FTRACE_WITH_REGS)
index 8d0d45d..2f27619 100644 (file)
@@ -26,7 +26,8 @@
                compatible = "arm,mhu", "arm,primecell";
                reg = <0x0 0x2b1f0000 0x0 0x1000>;
                interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>,
-                            <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
+                            <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
                #mbox-cells = <1>;
                clocks = <&soc_refclk100mhz>;
                clock-names = "apb_pclk";
index ba88d15..09d2b69 100644 (file)
@@ -67,7 +67,6 @@
                        port@0 {
                                reg = <0>;
                                csys2_funnel_in_port0: endpoint {
-                                       slave-mode;
                                        remote-endpoint = <&etf0_out_port>;
                                };
                        };
@@ -75,7 +74,6 @@
                        port@1 {
                                reg = <1>;
                                csys2_funnel_in_port1: endpoint {
-                                       slave-mode;
                                        remote-endpoint = <&etf1_out_port>;
                                };
                        };
index 40d34c8..b949cac 100644 (file)
@@ -25,7 +25,6 @@
 &enetc_port0 {
        phy-handle = <&slot1_sgmii>;
        phy-mode = "2500base-x";
-       managed = "in-band-status";
        status = "okay";
 };
 
index 35fb929..d3ee6fc 100644 (file)
                        lan1: port@0 {
                                reg = <0>;
                                label = "lan1";
+                               phy-mode = "internal";
                                local-mac-address = [00 00 00 00 00 00];
                        };
 
                        lan2: port@1 {
                                reg = <1>;
                                label = "lan2";
+                               phy-mode = "internal";
                                local-mac-address = [00 00 00 00 00 00];
                        };
 
                        lan3: port@2 {
                                reg = <2>;
                                label = "lan3";
+                               phy-mode = "internal";
                                local-mac-address = [00 00 00 00 00 00];
                        };
 
                        lan4: port@3 {
                                reg = <3>;
                                label = "lan4";
+                               phy-mode = "internal";
                                local-mac-address = [00 00 00 00 00 00];
                        };
 
index d1b4582..b379c46 100644 (file)
        };
 
        /* Fixed clock dedicated to SPI CAN controller */
-       clk20m: oscillator {
+       clk40m: oscillator {
                compatible = "fixed-clock";
                #clock-cells = <0>;
-               clock-frequency = <20000000>;
+               clock-frequency = <40000000>;
        };
 
        gpio-keys {
 
        can1: can@0 {
                compatible = "microchip,mcp251xfd";
-               clocks = <&clk20m>;
-               interrupts-extended = <&gpio1 6 IRQ_TYPE_EDGE_FALLING>;
+               clocks = <&clk40m>;
+               interrupts-extended = <&gpio1 6 IRQ_TYPE_LEVEL_LOW>;
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_can1_int>;
                reg = <0>;
                pinctrl-0 = <&pinctrl_gpio_9_dsi>, <&pinctrl_i2s_2_bclk_touch_reset>;
                reg = <0x4a>;
                /* Verdin I2S_2_BCLK (TOUCH_RESET#, SODIMM 42) */
-               reset-gpios = <&gpio3 23 GPIO_ACTIVE_HIGH>;
+               reset-gpios = <&gpio3 23 GPIO_ACTIVE_LOW>;
                status = "disabled";
        };
 
 };
 
 &usbphynop2 {
+       power-domains = <&pgc_otg2>;
        vcc-supply = <&reg_vdd_3v3>;
 };
 
index a616eb3..0f13ee3 100644 (file)
@@ -70,7 +70,7 @@
 &ecspi1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_ecspi1>;
-       cs-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>;
+       cs-gpios = <&gpio5 17 GPIO_ACTIVE_LOW>;
        status = "disabled";
 };
 
        pinctrl-names = "default", "gpio";
        pinctrl-0 = <&pinctrl_i2c5>;
        pinctrl-1 = <&pinctrl_i2c5_gpio>;
-       scl-gpios = <&gpio5 26 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
-       sda-gpios = <&gpio5 27 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+       scl-gpios = <&gpio3 26 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+       sda-gpios = <&gpio3 27 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
        status = "okay";
 };
 
 
        pinctrl_ecspi1: dhcom-ecspi1-grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_ECSPI1_SCLK__ECSPI1_SCLK           0x44
-                       MX8MP_IOMUXC_ECSPI1_MOSI__ECSPI1_MOSI           0x44
-                       MX8MP_IOMUXC_ECSPI1_MISO__ECSPI1_MISO           0x44
-                       MX8MP_IOMUXC_ECSPI1_SS0__GPIO5_IO09             0x40
+                       MX8MP_IOMUXC_I2C1_SCL__ECSPI1_SCLK              0x44
+                       MX8MP_IOMUXC_I2C1_SDA__ECSPI1_MOSI              0x44
+                       MX8MP_IOMUXC_I2C2_SCL__ECSPI1_MISO              0x44
+                       MX8MP_IOMUXC_I2C2_SDA__GPIO5_IO17               0x40
                >;
        };
 
index 5212155..6630ec5 100644 (file)
 
        pinctrl_sai2: sai2grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_SAI2_TXFS__AUDIOMIX_SAI2_TX_SYNC
-                       MX8MP_IOMUXC_SAI2_TXD0__AUDIOMIX_SAI2_TX_DATA00
-                       MX8MP_IOMUXC_SAI2_TXC__AUDIOMIX_SAI2_TX_BCLK
-                       MX8MP_IOMUXC_SAI2_MCLK__AUDIOMIX_SAI2_MCLK
+                       MX8MP_IOMUXC_SAI2_TXFS__AUDIOMIX_SAI2_TX_SYNC   0xd6
+                       MX8MP_IOMUXC_SAI2_TXD0__AUDIOMIX_SAI2_TX_DATA00 0xd6
+                       MX8MP_IOMUXC_SAI2_TXC__AUDIOMIX_SAI2_TX_BCLK    0xd6
+                       MX8MP_IOMUXC_SAI2_MCLK__AUDIOMIX_SAI2_MCLK      0xd6
                >;
        };
 
index c5987bd..1c74c6a 100644 (file)
                interrupts = <5 IRQ_TYPE_EDGE_FALLING>;
                reg = <0x4a>;
                /* Verdin GPIO_2 (SODIMM 208) */
-               reset-gpios = <&gpio1 1 GPIO_ACTIVE_HIGH>;
+               reset-gpios = <&gpio1 1 GPIO_ACTIVE_LOW>;
                status = "disabled";
        };
 };
                pinctrl-0 = <&pinctrl_gpio_9_dsi>, <&pinctrl_i2s_2_bclk_touch_reset>;
                reg = <0x4a>;
                /* Verdin I2S_2_BCLK (TOUCH_RESET#, SODIMM 42) */
-               reset-gpios = <&gpio5 0 GPIO_ACTIVE_HIGH>;
+               reset-gpios = <&gpio5 0 GPIO_ACTIVE_LOW>;
                status = "disabled";
        };
 
index 899e8e7..802ad6e 100644 (file)
                reg = <0x51>;
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_rtc>;
-               interrupt-names = "irq";
                interrupt-parent = <&gpio1>;
                interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
                quartz-load-femtofarads = <7000>;
index 7cbb0de..1c15726 100644 (file)
@@ -85,7 +85,7 @@
                                     "renesas,rcar-gen4-hscif",
                                     "renesas,hscif";
                        reg = <0 0xe6540000 0 96>;
-                       interrupts = <GIC_SPI 245 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupts = <GIC_SPI 246 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&cpg CPG_MOD 514>,
                                 <&cpg CPG_CORE R8A779G0_CLK_S0D3_PER>,
                                 <&scif_clk>;
index ca9b487..34256bd 100644 (file)
@@ -71,7 +71,7 @@ static __always_inline int icache_is_vpipt(void)
 
 static inline u32 cache_type_cwg(void)
 {
-       return (read_cpuid_cachetype() >> CTR_EL0_CWG_SHIFT) & CTR_EL0_CWG_MASK;
+       return SYS_FIELD_GET(CTR_EL0, CWG, read_cpuid_cachetype());
 }
 
 #define __read_mostly __section(".data..read_mostly")
index 9bb1873..6f86b7a 100644 (file)
@@ -153,7 +153,7 @@ struct vl_info {
 
 #ifdef CONFIG_ARM64_SVE
 
-extern void sve_alloc(struct task_struct *task);
+extern void sve_alloc(struct task_struct *task, bool flush);
 extern void fpsimd_release_task(struct task_struct *task);
 extern void fpsimd_sync_to_sve(struct task_struct *task);
 extern void fpsimd_force_sync_to_sve(struct task_struct *task);
@@ -256,7 +256,7 @@ size_t sve_state_size(struct task_struct const *task);
 
 #else /* ! CONFIG_ARM64_SVE */
 
-static inline void sve_alloc(struct task_struct *task) { }
+static inline void sve_alloc(struct task_struct *task, bool flush) { }
 static inline void fpsimd_release_task(struct task_struct *task) { }
 static inline void sve_sync_to_fpsimd(struct task_struct *task) { }
 static inline void sve_sync_from_fpsimd_zeropad(struct task_struct *task) { }
index 02e59fa..32d14f4 100644 (file)
 #define EARLY_KASLR    (0)
 #endif
 
-#define EARLY_ENTRIES(vstart, vend, shift) \
-       ((((vend) - 1) >> (shift)) - ((vstart) >> (shift)) + 1 + EARLY_KASLR)
+#define EARLY_ENTRIES(vstart, vend, shift, add) \
+       ((((vend) - 1) >> (shift)) - ((vstart) >> (shift)) + 1 + add)
 
-#define EARLY_PGDS(vstart, vend) (EARLY_ENTRIES(vstart, vend, PGDIR_SHIFT))
+#define EARLY_PGDS(vstart, vend, add) (EARLY_ENTRIES(vstart, vend, PGDIR_SHIFT, add))
 
 #if SWAPPER_PGTABLE_LEVELS > 3
-#define EARLY_PUDS(vstart, vend) (EARLY_ENTRIES(vstart, vend, PUD_SHIFT))
+#define EARLY_PUDS(vstart, vend, add) (EARLY_ENTRIES(vstart, vend, PUD_SHIFT, add))
 #else
-#define EARLY_PUDS(vstart, vend) (0)
+#define EARLY_PUDS(vstart, vend, add) (0)
 #endif
 
 #if SWAPPER_PGTABLE_LEVELS > 2
-#define EARLY_PMDS(vstart, vend) (EARLY_ENTRIES(vstart, vend, SWAPPER_TABLE_SHIFT))
+#define EARLY_PMDS(vstart, vend, add) (EARLY_ENTRIES(vstart, vend, SWAPPER_TABLE_SHIFT, add))
 #else
-#define EARLY_PMDS(vstart, vend) (0)
+#define EARLY_PMDS(vstart, vend, add) (0)
 #endif
 
-#define EARLY_PAGES(vstart, vend) ( 1                  /* PGDIR page */                                \
-                       + EARLY_PGDS((vstart), (vend))  /* each PGDIR needs a next level page table */  \
-                       + EARLY_PUDS((vstart), (vend))  /* each PUD needs a next level page table */    \
-                       + EARLY_PMDS((vstart), (vend))) /* each PMD needs a next level page table */
-#define INIT_DIR_SIZE (PAGE_SIZE * EARLY_PAGES(KIMAGE_VADDR, _end))
+#define EARLY_PAGES(vstart, vend, add) ( 1                     /* PGDIR page */                                \
+                       + EARLY_PGDS((vstart), (vend), add)     /* each PGDIR needs a next level page table */  \
+                       + EARLY_PUDS((vstart), (vend), add)     /* each PUD needs a next level page table */    \
+                       + EARLY_PMDS((vstart), (vend), add))    /* each PMD needs a next level page table */
+#define INIT_DIR_SIZE (PAGE_SIZE * EARLY_PAGES(KIMAGE_VADDR, _end, EARLY_KASLR))
 
 /* the initial ID map may need two extra pages if it needs to be extended */
 #if VA_BITS < 48
@@ -93,7 +93,7 @@
 #else
 #define INIT_IDMAP_DIR_SIZE    (INIT_IDMAP_DIR_PAGES * PAGE_SIZE)
 #endif
-#define INIT_IDMAP_DIR_PAGES   EARLY_PAGES(KIMAGE_VADDR, _end + MAX_FDT_SIZE + SWAPPER_BLOCK_SIZE)
+#define INIT_IDMAP_DIR_PAGES   EARLY_PAGES(KIMAGE_VADDR, _end + MAX_FDT_SIZE + SWAPPER_BLOCK_SIZE, 1)
 
 /* Initial memory map size */
 #if ARM64_KERNEL_USES_PMD_MAPS
index f38ef29..e9c9388 100644 (file)
@@ -929,6 +929,10 @@ bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu);
        (system_supports_mte() &&                               \
         test_bit(KVM_ARCH_FLAG_MTE_ENABLED, &(kvm)->arch.flags))
 
+#define kvm_supports_32bit_el0()                               \
+       (system_supports_32bit_el0() &&                         \
+        !static_branch_unlikely(&arm64_mismatched_32bit_el0))
+
 int kvm_trng_call(struct kvm_vcpu *vcpu);
 #ifdef CONFIG_KVM
 extern phys_addr_t hyp_mem_base;
index 6437df6..f4af547 100644 (file)
@@ -3,6 +3,8 @@
 #ifndef __ARM64_ASM_SETUP_H
 #define __ARM64_ASM_SETUP_H
 
+#include <linux/string.h>
+
 #include <uapi/asm/setup.h>
 
 void *get_early_fdt_ptr(void);
@@ -14,4 +16,19 @@ void early_fdt_map(u64 dt_phys);
 extern phys_addr_t __fdt_pointer __initdata;
 extern u64 __cacheline_aligned boot_args[4];
 
+static inline bool arch_parse_debug_rodata(char *arg)
+{
+       extern bool rodata_enabled;
+       extern bool rodata_full;
+
+       if (arg && !strcmp(arg, "full")) {
+               rodata_enabled = true;
+               rodata_full = true;
+               return true;
+       }
+
+       return false;
+}
+#define arch_parse_debug_rodata arch_parse_debug_rodata
+
 #endif
index 7c71358..818df93 100644 (file)
 
 #else
 
+#include <linux/bitfield.h>
 #include <linux/build_bug.h>
 #include <linux/types.h>
 #include <asm/alternative.h>
        par;                                                            \
 })
 
-#endif
-
 #define SYS_FIELD_GET(reg, field, val)         \
                 FIELD_GET(reg##_##field##_MASK, val)
 
 #define SYS_FIELD_PREP_ENUM(reg, field, val)           \
                 FIELD_PREP(reg##_##field##_MASK, reg##_##field##_##val)
 
+#endif
+
 #endif /* __ASM_SYSREG_H */
index 3bb1343..316917b 100644 (file)
@@ -75,9 +75,11 @@ struct kvm_regs {
 
 /* KVM_ARM_SET_DEVICE_ADDR ioctl id encoding */
 #define KVM_ARM_DEVICE_TYPE_SHIFT      0
-#define KVM_ARM_DEVICE_TYPE_MASK       (0xffff << KVM_ARM_DEVICE_TYPE_SHIFT)
+#define KVM_ARM_DEVICE_TYPE_MASK       GENMASK(KVM_ARM_DEVICE_TYPE_SHIFT + 15, \
+                                               KVM_ARM_DEVICE_TYPE_SHIFT)
 #define KVM_ARM_DEVICE_ID_SHIFT                16
-#define KVM_ARM_DEVICE_ID_MASK         (0xffff << KVM_ARM_DEVICE_ID_SHIFT)
+#define KVM_ARM_DEVICE_ID_MASK         GENMASK(KVM_ARM_DEVICE_ID_SHIFT + 15, \
+                                               KVM_ARM_DEVICE_ID_SHIFT)
 
 /* Supported device IDs */
 #define KVM_ARM_DEVICE_VGIC_V2         0
index 587543c..97c42be 100644 (file)
@@ -45,7 +45,8 @@ static void ci_leaf_init(struct cacheinfo *this_leaf,
 
 int init_cache_level(unsigned int cpu)
 {
-       unsigned int ctype, level, leaves, fw_level;
+       unsigned int ctype, level, leaves;
+       int fw_level;
        struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
 
        for (level = 1, leaves = 0; level <= MAX_CACHE_LEVEL; level++) {
@@ -63,6 +64,9 @@ int init_cache_level(unsigned int cpu)
        else
                fw_level = acpi_find_last_cache_level(cpu);
 
+       if (fw_level < 0)
+               return fw_level;
+
        if (level < fw_level) {
                /*
                 * some external caches not specified in CLIDR_EL1
index 7e6289e..53b973b 100644 (file)
@@ -208,6 +208,8 @@ static const struct arm64_cpu_capabilities arm64_repeat_tlbi_list[] = {
 #ifdef CONFIG_ARM64_ERRATUM_1286807
        {
                ERRATA_MIDR_RANGE(MIDR_CORTEX_A76, 0, 0, 3, 0),
+       },
+       {
                /* Kryo4xx Gold (rcpe to rfpe) => (r0p0 to r3p0) */
                ERRATA_MIDR_RANGE(MIDR_QCOM_KRYO_4XX_GOLD, 0xc, 0xe, 0xf, 0xe),
        },
@@ -654,6 +656,16 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
                ERRATA_MIDR_REV_RANGE(MIDR_CORTEX_A510, 0, 0, 2)
        },
 #endif
+#ifdef CONFIG_ARM64_ERRATUM_2457168
+       {
+               .desc = "ARM erratum 2457168",
+               .capability = ARM64_WORKAROUND_2457168,
+               .type = ARM64_CPUCAP_WEAK_LOCAL_CPU_FEATURE,
+
+               /* Cortex-A510 r0p0-r1p1 */
+               CAP_MIDR_RANGE(MIDR_CORTEX_A510, 0, 0, 1, 1)
+       },
+#endif
 #ifdef CONFIG_ARM64_ERRATUM_2038923
        {
                .desc = "ARM erratum 2038923",
index 907401e..af4de81 100644 (file)
@@ -1870,7 +1870,10 @@ static void cpu_amu_enable(struct arm64_cpu_capabilities const *cap)
                pr_info("detected CPU%d: Activity Monitors Unit (AMU)\n",
                        smp_processor_id());
                cpumask_set_cpu(smp_processor_id(), &amu_cpus);
-               update_freq_counters_refs();
+
+               /* 0 reference values signal broken/disabled counters */
+               if (!this_cpu_has_cap(ARM64_WORKAROUND_2457168))
+                       update_freq_counters_refs();
        }
 }
 
index 254fe31..2d73b3e 100644 (file)
@@ -502,7 +502,7 @@ tsk .req    x28             // current thread_info
 SYM_CODE_START(vectors)
        kernel_ventry   1, t, 64, sync          // Synchronous EL1t
        kernel_ventry   1, t, 64, irq           // IRQ EL1t
-       kernel_ventry   1, t, 64, fiq           // FIQ EL1h
+       kernel_ventry   1, t, 64, fiq           // FIQ EL1t
        kernel_ventry   1, t, 64, error         // Error EL1t
 
        kernel_ventry   1, h, 64, sync          // Synchronous EL1h
index dd63ffc..23834d9 100644 (file)
@@ -715,10 +715,12 @@ size_t sve_state_size(struct task_struct const *task)
  * do_sve_acc() case, there is no ABI requirement to hide stale data
  * written previously be task.
  */
-void sve_alloc(struct task_struct *task)
+void sve_alloc(struct task_struct *task, bool flush)
 {
        if (task->thread.sve_state) {
-               memset(task->thread.sve_state, 0, sve_state_size(task));
+               if (flush)
+                       memset(task->thread.sve_state, 0,
+                              sve_state_size(task));
                return;
        }
 
@@ -1388,7 +1390,7 @@ void do_sve_acc(unsigned long esr, struct pt_regs *regs)
                return;
        }
 
-       sve_alloc(current);
+       sve_alloc(current, true);
        if (!current->thread.sve_state) {
                force_sig(SIGKILL);
                return;
@@ -1439,7 +1441,7 @@ void do_sme_acc(unsigned long esr, struct pt_regs *regs)
                return;
        }
 
-       sve_alloc(current);
+       sve_alloc(current, false);
        sme_alloc(current);
        if (!current->thread.sve_state || !current->thread.za_state) {
                force_sig(SIGKILL);
@@ -1460,17 +1462,6 @@ void do_sme_acc(unsigned long esr, struct pt_regs *regs)
                fpsimd_bind_task_to_cpu();
        }
 
-       /*
-        * If SVE was not already active initialise the SVE registers,
-        * any non-shared state between the streaming and regular SVE
-        * registers is architecturally guaranteed to be zeroed when
-        * we enter streaming mode.  We do not need to initialize ZA
-        * since ZA must be disabled at this point and enabling ZA is
-        * architecturally defined to zero ZA.
-        */
-       if (system_supports_sve() && !test_thread_flag(TIF_SVE))
-               sve_init_regs();
-
        put_cpu_fpsimd_context();
 }
 
index cefe6a7..814b658 100644 (file)
@@ -371,7 +371,9 @@ SYM_FUNC_END(create_idmap)
 SYM_FUNC_START_LOCAL(create_kernel_mapping)
        adrp    x0, init_pg_dir
        mov_q   x5, KIMAGE_VADDR                // compile time __va(_text)
+#ifdef CONFIG_RELOCATABLE
        add     x5, x5, x23                     // add KASLR displacement
+#endif
        adrp    x6, _end                        // runtime __pa(_end)
        adrp    x3, _text                       // runtime __pa(_text)
        sub     x6, x6, x3                      // _end - _text
index 8899512..a11a6e1 100644 (file)
@@ -47,7 +47,7 @@ static int prepare_elf_headers(void **addr, unsigned long *sz)
        u64 i;
        phys_addr_t start, end;
 
-       nr_ranges = 1; /* for exclusion of crashkernel region */
+       nr_ranges = 2; /* for exclusion of crashkernel region */
        for_each_mem_range(i, &start, &end)
                nr_ranges++;
 
index 6c3855e..17bff6e 100644 (file)
@@ -94,11 +94,9 @@ asmlinkage u64 kaslr_early_init(void *fdt)
 
        seed = get_kaslr_seed(fdt);
        if (!seed) {
-#ifdef CONFIG_ARCH_RANDOM
-                if (!__early_cpu_has_rndr() ||
-                    !__arm64_rndr((unsigned long *)&seed))
-#endif
-               return 0;
+               if (!__early_cpu_has_rndr() ||
+                   !__arm64_rndr((unsigned long *)&seed))
+                       return 0;
        }
 
        /*
index 21da831..041d2ae 100644 (file)
@@ -882,7 +882,7 @@ static int sve_set_common(struct task_struct *target,
                 * state and ensure there's storage.
                 */
                if (target->thread.svcr != old_svcr)
-                       sve_alloc(target);
+                       sve_alloc(target, true);
        }
 
        /* Registers: FPSIMD-only case */
@@ -912,7 +912,7 @@ static int sve_set_common(struct task_struct *target,
                goto out;
        }
 
-       sve_alloc(target);
+       sve_alloc(target, true);
        if (!target->thread.sve_state) {
                ret = -ENOMEM;
                clear_tsk_thread_flag(target, TIF_SVE);
@@ -1082,9 +1082,8 @@ static int za_set(struct task_struct *target,
 
        /* Ensure there is some SVE storage for streaming mode */
        if (!target->thread.sve_state) {
-               sve_alloc(target);
+               sve_alloc(target, false);
                if (!target->thread.sve_state) {
-                       clear_thread_flag(TIF_SME);
                        ret = -ENOMEM;
                        goto out;
                }
@@ -1094,7 +1093,6 @@ static int za_set(struct task_struct *target,
        sme_alloc(target);
        if (!target->thread.za_state) {
                ret = -ENOMEM;
-               clear_tsk_thread_flag(target, TIF_SME);
                goto out;
        }
 
index 3e6d035..9ad911f 100644 (file)
@@ -91,7 +91,7 @@ static size_t sigframe_size(struct rt_sigframe_user_layout const *user)
  * not taken into account.  This limit is not a guarantee and is
  * NOT ABI.
  */
-#define SIGFRAME_MAXSZ SZ_64K
+#define SIGFRAME_MAXSZ SZ_256K
 
 static int __sigframe_alloc(struct rt_sigframe_user_layout *user,
                            unsigned long *offset, size_t size, bool extend)
@@ -310,7 +310,7 @@ static int restore_sve_fpsimd_context(struct user_ctxs *user)
        fpsimd_flush_task_state(current);
        /* From now, fpsimd_thread_switch() won't touch thread.sve_state */
 
-       sve_alloc(current);
+       sve_alloc(current, true);
        if (!current->thread.sve_state) {
                clear_thread_flag(TIF_SVE);
                return -ENOMEM;
@@ -926,6 +926,16 @@ static void setup_return(struct pt_regs *regs, struct k_sigaction *ka,
 
        /* Signal handlers are invoked with ZA and streaming mode disabled */
        if (system_supports_sme()) {
+               /*
+                * If we were in streaming mode the saved register
+                * state was SVE but we will exit SM and use the
+                * FPSIMD register state - flush the saved FPSIMD
+                * register state in case it gets loaded.
+                */
+               if (current->thread.svcr & SVCR_SM_MASK)
+                       memset(&current->thread.uw.fpsimd_state, 0,
+                              sizeof(current->thread.uw.fpsimd_state));
+
                current->thread.svcr &= ~(SVCR_ZA_MASK |
                                          SVCR_SM_MASK);
                sme_smstop();
index 617f78a..97c9de5 100644 (file)
@@ -101,6 +101,9 @@ SYM_FUNC_END(__cpu_suspend_enter)
 SYM_CODE_START(cpu_resume)
        bl      init_kernel_el
        bl      finalise_el2
+#if VA_BITS > 48
+       ldr_l   x0, vabits_actual
+#endif
        bl      __cpu_setup
        /* enable the MMU early - so we can access sleep_save_stash by va */
        adrp    x1, swapper_pg_dir
index 869ffc4..ad2bfc7 100644 (file)
@@ -296,12 +296,25 @@ core_initcall(init_amu_fie);
 
 static void cpu_read_corecnt(void *val)
 {
+       /*
+        * A value of 0 can be returned if the current CPU does not support AMUs
+        * or if the counter is disabled for this CPU. A return value of 0 at
+        * counter read is properly handled as an error case by the users of the
+        * counter.
+        */
        *(u64 *)val = read_corecnt();
 }
 
 static void cpu_read_constcnt(void *val)
 {
-       *(u64 *)val = read_constcnt();
+       /*
+        * Return 0 if the current CPU is affected by erratum 2457168. A value
+        * of 0 is also returned if the current CPU does not support AMUs or if
+        * the counter is disabled. A return value of 0 at counter read is
+        * properly handled as an error case by the users of the counter.
+        */
+       *(u64 *)val = this_cpu_has_cap(ARM64_WORKAROUND_2457168) ?
+                     0UL : read_constcnt();
 }
 
 static inline
@@ -328,7 +341,22 @@ int counters_read_on_cpu(int cpu, smp_call_func_t func, u64 *val)
  */
 bool cpc_ffh_supported(void)
 {
-       return freq_counters_valid(get_cpu_with_amu_feat());
+       int cpu = get_cpu_with_amu_feat();
+
+       /*
+        * FFH is considered supported if there is at least one present CPU that
+        * supports AMUs. Using FFH to read core and reference counters for CPUs
+        * that do not support AMUs, have counters disabled or that are affected
+        * by errata, will result in a return value of 0.
+        *
+        * This is done to allow any enabled and valid counters to be read
+        * through FFH, knowing that potentially returning 0 as counter value is
+        * properly handled by the users of these counters.
+        */
+       if ((cpu >= nr_cpu_ids) || !cpumask_test_cpu(cpu, cpu_present_mask))
+               return false;
+
+       return true;
 }
 
 int cpc_read_ffh(int cpu, struct cpc_reg *reg, u64 *val)
index 986cee6..2ff0ef6 100644 (file)
@@ -757,8 +757,7 @@ static bool vcpu_mode_is_bad_32bit(struct kvm_vcpu *vcpu)
        if (likely(!vcpu_mode_is_32bit(vcpu)))
                return false;
 
-       return !system_supports_32bit_el0() ||
-               static_branch_unlikely(&arm64_mismatched_32bit_el0);
+       return !kvm_supports_32bit_el0();
 }
 
 /**
index 8c60719..f802a3b 100644 (file)
@@ -242,7 +242,7 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
                u64 mode = (*(u64 *)valp) & PSR_AA32_MODE_MASK;
                switch (mode) {
                case PSR_AA32_MODE_USR:
-                       if (!system_supports_32bit_el0())
+                       if (!kvm_supports_32bit_el0())
                                return -EINVAL;
                        break;
                case PSR_AA32_MODE_FIQ:
index 87f1cd0..c9a13e4 100644 (file)
@@ -993,7 +993,7 @@ transparent_hugepage_adjust(struct kvm *kvm, struct kvm_memory_slot *memslot,
                 * THP doesn't start to split while we are adjusting the
                 * refcounts.
                 *
-                * We are sure this doesn't happen, because mmu_notifier_retry
+                * We are sure this doesn't happen, because mmu_invalidate_retry
                 * was successful and we are holding the mmu_lock, so if this
                 * THP is trying to split, it will be blocked in the mmu
                 * notifier before touching any of the pages, specifically
@@ -1188,9 +1188,9 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
                        return ret;
        }
 
-       mmu_seq = vcpu->kvm->mmu_notifier_seq;
+       mmu_seq = vcpu->kvm->mmu_invalidate_seq;
        /*
-        * Ensure the read of mmu_notifier_seq happens before we call
+        * Ensure the read of mmu_invalidate_seq happens before we call
         * gfn_to_pfn_prot (which calls get_user_pages), so that we don't risk
         * the page we just got a reference to gets unmapped before we have a
         * chance to grab the mmu_lock, which ensure that if the page gets
@@ -1246,7 +1246,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
        else
                write_lock(&kvm->mmu_lock);
        pgt = vcpu->arch.hw_mmu->pgt;
-       if (mmu_notifier_retry(kvm, mmu_seq))
+       if (mmu_invalidate_retry(kvm, mmu_seq))
                goto out_unlock;
 
        /*
index c059b25..3234f50 100644 (file)
@@ -652,7 +652,7 @@ static void reset_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
         */
        val = ((pmcr & ~ARMV8_PMU_PMCR_MASK)
               | (ARMV8_PMU_PMCR_MASK & 0xdecafbad)) & (~ARMV8_PMU_PMCR_E);
-       if (!system_supports_32bit_el0())
+       if (!kvm_supports_32bit_el0())
                val |= ARMV8_PMU_PMCR_LC;
        __vcpu_sys_reg(vcpu, r->reg) = val;
 }
@@ -701,7 +701,7 @@ static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
                val = __vcpu_sys_reg(vcpu, PMCR_EL0);
                val &= ~ARMV8_PMU_PMCR_MASK;
                val |= p->regval & ARMV8_PMU_PMCR_MASK;
-               if (!system_supports_32bit_el0())
+               if (!kvm_supports_32bit_el0())
                        val |= ARMV8_PMU_PMCR_LC;
                __vcpu_sys_reg(vcpu, PMCR_EL0) = val;
                kvm_pmu_handle_pmcr(vcpu, val);
index db7c4e6..e7ad445 100644 (file)
@@ -642,24 +642,6 @@ static void __init map_kernel_segment(pgd_t *pgdp, void *va_start, void *va_end,
        vm_area_add_early(vma);
 }
 
-static int __init parse_rodata(char *arg)
-{
-       int ret = strtobool(arg, &rodata_enabled);
-       if (!ret) {
-               rodata_full = false;
-               return 0;
-       }
-
-       /* permit 'full' in addition to boolean options */
-       if (strcmp(arg, "full"))
-               return -EINVAL;
-
-       rodata_enabled = true;
-       rodata_full = true;
-       return 0;
-}
-early_param("rodata", parse_rodata);
-
 #ifdef CONFIG_UNMAP_KERNEL_AT_EL0
 static int __init map_entry_trampoline(void)
 {
index 7796537..63b2484 100644 (file)
@@ -67,6 +67,7 @@ WORKAROUND_1902691
 WORKAROUND_2038923
 WORKAROUND_2064142
 WORKAROUND_2077057
+WORKAROUND_2457168
 WORKAROUND_TRBE_OVERWRITE_FILL_MODE
 WORKAROUND_TSB_FLUSH_FAILURE
 WORKAROUND_TRBE_WRITE_OUT_OF_RANGE
index da50047..160d8f3 100644 (file)
@@ -179,6 +179,21 @@ arch_test_bit(unsigned long nr, const volatile unsigned long *addr)
        return retval;
 }
 
+static __always_inline bool
+arch_test_bit_acquire(unsigned long nr, const volatile unsigned long *addr)
+{
+       int retval;
+
+       asm volatile(
+       "{P0 = tstbit(%1,%2); if (P0.new) %0 = #1; if (!P0.new) %0 = #0;}\n"
+       : "=&r" (retval)
+       : "r" (addr[BIT_WORD(nr)]), "r" (nr % BITS_PER_LONG)
+       : "p0", "memory"
+       );
+
+       return retval;
+}
+
 /*
  * ffz - find first zero in word.
  * @word: The word to search
index 9f62af7..1accb78 100644 (file)
@@ -331,11 +331,8 @@ arch___test_and_change_bit(unsigned long nr, volatile unsigned long *addr)
        return (old & bit) != 0;
 }
 
-static __always_inline bool
-arch_test_bit(unsigned long nr, const volatile unsigned long *addr)
-{
-       return 1 & (((const volatile __u32 *) addr)[nr >> 5] >> (nr & 31));
-}
+#define arch_test_bit generic_test_bit
+#define arch_test_bit_acquire generic_test_bit_acquire
 
 /**
  * ffz - find the first zero bit in a long word
index 4abc9a2..c7dd6ad 100644 (file)
@@ -39,6 +39,7 @@ config LOONGARCH
        select ARCH_INLINE_SPIN_UNLOCK_BH if !PREEMPTION
        select ARCH_INLINE_SPIN_UNLOCK_IRQ if !PREEMPTION
        select ARCH_INLINE_SPIN_UNLOCK_IRQRESTORE if !PREEMPTION
+       select ARCH_KEEP_MEMBLOCK
        select ARCH_MIGHT_HAVE_PC_PARPORT
        select ARCH_MIGHT_HAVE_PC_SERIO
        select ARCH_SPARSEMEM_ENABLE
@@ -51,6 +52,7 @@ config LOONGARCH
        select ARCH_USE_CMPXCHG_LOCKREF
        select ARCH_USE_QUEUED_RWLOCKS
        select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT
+       select ARCH_WANT_LD_ORPHAN_WARN
        select ARCH_WANTS_NO_INSTR
        select BUILDTIME_TABLE_SORT
        select COMMON_CLK
@@ -111,6 +113,7 @@ config LOONGARCH
        select PCI_ECAM if ACPI
        select PCI_LOONGSON
        select PCI_MSI_ARCH_FALLBACKS
+       select PCI_QUIRKS
        select PERF_USE_VMALLOC
        select RTC_LIB
        select SMP
index c510821..17162f4 100644 (file)
@@ -15,7 +15,7 @@ extern int acpi_pci_disabled;
 extern int acpi_noirq;
 
 #define acpi_os_ioremap acpi_os_ioremap
-void __init __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size);
+void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size);
 
 static inline void disable_acpi(void)
 {
index b91e073..d342935 100644 (file)
@@ -109,4 +109,20 @@ extern unsigned long vm_map_base;
  */
 #define PHYSADDR(a)            ((_ACAST64_(a)) & TO_PHYS_MASK)
 
+/*
+ * On LoongArch, I/O ports mappring is following:
+ *
+ *              |         ....          |
+ *              |-----------------------|
+ *              | pci io ports(16K~32M) |
+ *              |-----------------------|
+ *              | isa io ports(0  ~16K) |
+ * PCI_IOBASE ->|-----------------------|
+ *              |         ....          |
+ */
+#define PCI_IOBASE     ((void __iomem *)(vm_map_base + (2 * PAGE_SIZE)))
+#define PCI_IOSIZE     SZ_32M
+#define ISA_IOSIZE     SZ_16K
+#define IO_SPACE_LIMIT (PCI_IOSIZE - 1)
+
 #endif /* _ASM_ADDRSPACE_H */
index 0a9b0fa..ae19e33 100644 (file)
@@ -5,8 +5,9 @@
 #ifndef __ASM_CMPXCHG_H
 #define __ASM_CMPXCHG_H
 
-#include <asm/barrier.h>
+#include <linux/bits.h>
 #include <linux/build_bug.h>
+#include <asm/barrier.h>
 
 #define __xchg_asm(amswap_db, m, val)          \
 ({                                             \
                __ret;                          \
 })
 
+static inline unsigned int __xchg_small(volatile void *ptr, unsigned int val,
+                                       unsigned int size)
+{
+       unsigned int shift;
+       u32 old32, mask, temp;
+       volatile u32 *ptr32;
+
+       /* Mask value to the correct size. */
+       mask = GENMASK((size * BITS_PER_BYTE) - 1, 0);
+       val &= mask;
+
+       /*
+        * Calculate a shift & mask that correspond to the value we wish to
+        * exchange within the naturally aligned 4 byte integerthat includes
+        * it.
+        */
+       shift = (unsigned long)ptr & 0x3;
+       shift *= BITS_PER_BYTE;
+       mask <<= shift;
+
+       /*
+        * Calculate a pointer to the naturally aligned 4 byte integer that
+        * includes our byte of interest, and load its value.
+        */
+       ptr32 = (volatile u32 *)((unsigned long)ptr & ~0x3);
+
+       asm volatile (
+       "1:     ll.w            %0, %3          \n"
+       "       andn            %1, %0, %z4     \n"
+       "       or              %1, %1, %z5     \n"
+       "       sc.w            %1, %2          \n"
+       "       beqz            %1, 1b          \n"
+       : "=&r" (old32), "=&r" (temp), "=ZC" (*ptr32)
+       : "ZC" (*ptr32), "Jr" (mask), "Jr" (val << shift)
+       : "memory");
+
+       return (old32 & mask) >> shift;
+}
+
 static inline unsigned long __xchg(volatile void *ptr, unsigned long x,
                                   int size)
 {
        switch (size) {
+       case 1:
+       case 2:
+               return __xchg_small(ptr, x, size);
+
        case 4:
                return __xchg_asm("amswap_db.w", (volatile u32 *)ptr, (u32)x);
 
@@ -67,10 +111,62 @@ static inline unsigned long __xchg(volatile void *ptr, unsigned long x,
        __ret;                                                          \
 })
 
+static inline unsigned int __cmpxchg_small(volatile void *ptr, unsigned int old,
+                                          unsigned int new, unsigned int size)
+{
+       unsigned int shift;
+       u32 old32, mask, temp;
+       volatile u32 *ptr32;
+
+       /* Mask inputs to the correct size. */
+       mask = GENMASK((size * BITS_PER_BYTE) - 1, 0);
+       old &= mask;
+       new &= mask;
+
+       /*
+        * Calculate a shift & mask that correspond to the value we wish to
+        * compare & exchange within the naturally aligned 4 byte integer
+        * that includes it.
+        */
+       shift = (unsigned long)ptr & 0x3;
+       shift *= BITS_PER_BYTE;
+       old <<= shift;
+       new <<= shift;
+       mask <<= shift;
+
+       /*
+        * Calculate a pointer to the naturally aligned 4 byte integer that
+        * includes our byte of interest, and load its value.
+        */
+       ptr32 = (volatile u32 *)((unsigned long)ptr & ~0x3);
+
+       asm volatile (
+       "1:     ll.w            %0, %3          \n"
+       "       and             %1, %0, %z4     \n"
+       "       bne             %1, %z5, 2f     \n"
+       "       andn            %1, %0, %z4     \n"
+       "       or              %1, %1, %z6     \n"
+       "       sc.w            %1, %2          \n"
+       "       beqz            %1, 1b          \n"
+       "       b               3f              \n"
+       "2:                                     \n"
+       __WEAK_LLSC_MB
+       "3:                                     \n"
+       : "=&r" (old32), "=&r" (temp), "=ZC" (*ptr32)
+       : "ZC" (*ptr32), "Jr" (mask), "Jr" (old), "Jr" (new)
+       : "memory");
+
+       return (old32 & mask) >> shift;
+}
+
 static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
                                      unsigned long new, unsigned int size)
 {
        switch (size) {
+       case 1:
+       case 2:
+               return __cmpxchg_small(ptr, old, new, size);
+
        case 4:
                return __cmpxchg_asm("ll.w", "sc.w", (volatile u32 *)ptr,
                                     (u32)old, new);
index 8845997..999944e 100644 (file)
@@ -7,35 +7,16 @@
 
 #define ARCH_HAS_IOREMAP_WC
 
-#include <linux/compiler.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 
 #include <asm/addrspace.h>
-#include <asm/bug.h>
-#include <asm/byteorder.h>
 #include <asm/cpu.h>
 #include <asm/page.h>
 #include <asm/pgtable-bits.h>
 #include <asm/string.h>
 
 /*
- * On LoongArch, I/O ports mappring is following:
- *
- *              |         ....          |
- *              |-----------------------|
- *              | pci io ports(64K~32M) |
- *              |-----------------------|
- *              | isa io ports(0  ~16K) |
- * PCI_IOBASE ->|-----------------------|
- *              |         ....          |
- */
-#define PCI_IOBASE     ((void __iomem *)(vm_map_base + (2 * PAGE_SIZE)))
-#define PCI_IOSIZE     SZ_32M
-#define ISA_IOSIZE     SZ_16K
-#define IO_SPACE_LIMIT (PCI_IOSIZE - 1)
-
-/*
  * Change "struct page" to physical address.
  */
 #define page_to_phys(page)     ((phys_addr_t)page_to_pfn(page) << PAGE_SHIFT)
index 4b13019..d06d454 100644 (file)
@@ -81,7 +81,6 @@ extern struct acpi_vector_group msi_group[MAX_IO_PICS];
 #define GSI_MIN_PCH_IRQ                LOONGSON_PCH_IRQ_BASE
 #define GSI_MAX_PCH_IRQ                (LOONGSON_PCH_IRQ_BASE + 256 - 1)
 
-extern int find_pch_pic(u32 gsi);
 struct acpi_madt_lio_pic;
 struct acpi_madt_eio_pic;
 struct acpi_madt_ht_pic;
index a37324a..53f284a 100644 (file)
@@ -95,7 +95,7 @@ static inline int pfn_valid(unsigned long pfn)
 
 #endif
 
-#define virt_to_pfn(kaddr)     PFN_DOWN(virt_to_phys((void *)(kaddr)))
+#define virt_to_pfn(kaddr)     PFN_DOWN(PHYSADDR(kaddr))
 #define virt_to_page(kaddr)    pfn_to_page(virt_to_pfn(kaddr))
 
 extern int __virt_addr_valid(volatile void *kaddr);
index e6569f1..0bd6b01 100644 (file)
@@ -123,6 +123,10 @@ static inline unsigned long __percpu_xchg(void *ptr, unsigned long val,
                                                int size)
 {
        switch (size) {
+       case 1:
+       case 2:
+               return __xchg_small((volatile void *)ptr, val, size);
+
        case 4:
                return __xchg_asm("amswap.w", (volatile u32 *)ptr, (u32)val);
 
@@ -204,9 +208,13 @@ do {                                                                       \
 #define this_cpu_write_4(pcp, val) _percpu_write(pcp, val)
 #define this_cpu_write_8(pcp, val) _percpu_write(pcp, val)
 
+#define this_cpu_xchg_1(pcp, val) _percpu_xchg(pcp, val)
+#define this_cpu_xchg_2(pcp, val) _percpu_xchg(pcp, val)
 #define this_cpu_xchg_4(pcp, val) _percpu_xchg(pcp, val)
 #define this_cpu_xchg_8(pcp, val) _percpu_xchg(pcp, val)
 
+#define this_cpu_cmpxchg_1(ptr, o, n) _protect_cmpxchg_local(ptr, o, n)
+#define this_cpu_cmpxchg_2(ptr, o, n) _protect_cmpxchg_local(ptr, o, n)
 #define this_cpu_cmpxchg_4(ptr, o, n) _protect_cmpxchg_local(ptr, o, n)
 #define this_cpu_cmpxchg_8(ptr, o, n) _protect_cmpxchg_local(ptr, o, n)
 
index e03443a..8ea57e2 100644 (file)
@@ -59,7 +59,6 @@
 #include <linux/mm_types.h>
 #include <linux/mmzone.h>
 #include <asm/fixmap.h>
-#include <asm/io.h>
 
 struct mm_struct;
 struct vm_area_struct;
@@ -145,7 +144,7 @@ static inline void set_p4d(p4d_t *p4d, p4d_t p4dval)
        *p4d = p4dval;
 }
 
-#define p4d_phys(p4d)          virt_to_phys((void *)p4d_val(p4d))
+#define p4d_phys(p4d)          PHYSADDR(p4d_val(p4d))
 #define p4d_page(p4d)          (pfn_to_page(p4d_phys(p4d) >> PAGE_SHIFT))
 
 #endif
@@ -188,7 +187,7 @@ static inline pmd_t *pud_pgtable(pud_t pud)
 
 #define set_pud(pudptr, pudval) do { *(pudptr) = (pudval); } while (0)
 
-#define pud_phys(pud)          virt_to_phys((void *)pud_val(pud))
+#define pud_phys(pud)          PHYSADDR(pud_val(pud))
 #define pud_page(pud)          (pfn_to_page(pud_phys(pud) >> PAGE_SHIFT))
 
 #endif
@@ -221,7 +220,7 @@ static inline void pmd_clear(pmd_t *pmdp)
 
 #define set_pmd(pmdptr, pmdval) do { *(pmdptr) = (pmdval); } while (0)
 
-#define pmd_phys(pmd)          virt_to_phys((void *)pmd_val(pmd))
+#define pmd_phys(pmd)          PHYSADDR(pmd_val(pmd))
 
 #ifndef CONFIG_TRANSPARENT_HUGEPAGE
 #define pmd_page(pmd)          (pfn_to_page(pmd_phys(pmd) >> PAGE_SHIFT))
diff --git a/arch/loongarch/include/asm/reboot.h b/arch/loongarch/include/asm/reboot.h
deleted file mode 100644 (file)
index 5115174..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
- */
-#ifndef _ASM_REBOOT_H
-#define _ASM_REBOOT_H
-
-extern void (*pm_restart)(void);
-
-#endif /* _ASM_REBOOT_H */
index f1c9286..3353984 100644 (file)
@@ -48,7 +48,7 @@ void __init __acpi_unmap_table(void __iomem *map, unsigned long size)
        early_memunmap(map, size);
 }
 
-void __init __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size)
+void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size)
 {
        if (!memblock_is_memory(phys))
                return ioremap(phys, size);
index 800c965..8c82021 100644 (file)
 #include <acpi/reboot.h>
 #include <asm/idle.h>
 #include <asm/loongarch.h>
-#include <asm/reboot.h>
 
-static void default_halt(void)
+void (*pm_power_off)(void);
+EXPORT_SYMBOL(pm_power_off);
+
+void machine_halt(void)
 {
+#ifdef CONFIG_SMP
+       preempt_disable();
+       smp_send_stop();
+#endif
        local_irq_disable();
        clear_csr_ecfg(ECFG0_IM);
 
@@ -30,18 +36,29 @@ static void default_halt(void)
        }
 }
 
-static void default_poweroff(void)
+void machine_power_off(void)
 {
+#ifdef CONFIG_SMP
+       preempt_disable();
+       smp_send_stop();
+#endif
+       do_kernel_power_off();
 #ifdef CONFIG_EFI
        efi.reset_system(EFI_RESET_SHUTDOWN, EFI_SUCCESS, 0, NULL);
 #endif
+
        while (true) {
                __arch_cpu_idle();
        }
 }
 
-static void default_restart(void)
+void machine_restart(char *command)
 {
+#ifdef CONFIG_SMP
+       preempt_disable();
+       smp_send_stop();
+#endif
+       do_kernel_restart(command);
 #ifdef CONFIG_EFI
        if (efi_capsule_pending(NULL))
                efi_reboot(REBOOT_WARM, NULL);
@@ -55,47 +72,3 @@ static void default_restart(void)
                __arch_cpu_idle();
        }
 }
-
-void (*pm_restart)(void);
-EXPORT_SYMBOL(pm_restart);
-
-void (*pm_power_off)(void);
-EXPORT_SYMBOL(pm_power_off);
-
-void machine_halt(void)
-{
-#ifdef CONFIG_SMP
-       preempt_disable();
-       smp_send_stop();
-#endif
-       default_halt();
-}
-
-void machine_power_off(void)
-{
-#ifdef CONFIG_SMP
-       preempt_disable();
-       smp_send_stop();
-#endif
-       pm_power_off();
-}
-
-void machine_restart(char *command)
-{
-#ifdef CONFIG_SMP
-       preempt_disable();
-       smp_send_stop();
-#endif
-       do_kernel_restart(command);
-       pm_restart();
-}
-
-static int __init loongarch_reboot_setup(void)
-{
-       pm_restart = default_restart;
-       pm_power_off = default_poweroff;
-
-       return 0;
-}
-
-arch_initcall(loongarch_reboot_setup);
index 7f4889d..8f5b798 100644 (file)
@@ -529,11 +529,11 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
        signal_setup_done(ret, ksig, 0);
 }
 
-void arch_do_signal_or_restart(struct pt_regs *regs, bool has_signal)
+void arch_do_signal_or_restart(struct pt_regs *regs)
 {
        struct ksignal ksig;
 
-       if (has_signal && get_signal(&ksig)) {
+       if (get_signal(&ksig)) {
                /* Whee!  Actually deliver the signal.  */
                handle_signal(&ksig, regs);
                return;
index 69c76f2..f4831df 100644 (file)
@@ -77,6 +77,8 @@ SECTIONS
        PERCPU_SECTION(1 << CONFIG_L1_CACHE_SHIFT)
 #endif
 
+       .rela.dyn : ALIGN(8) { *(.rela.dyn) *(.rela*) }
+
        .init.bss : {
                *(.init.bss)
        }
index cda2c6b..c2cc7ce 100644 (file)
@@ -18,11 +18,11 @@ void dump_tlb_regs(void)
 {
        const int field = 2 * sizeof(unsigned long);
 
-       pr_info("Index    : %0x\n", read_csr_tlbidx());
-       pr_info("PageSize : %0x\n", read_csr_pagesize());
-       pr_info("EntryHi  : %0*llx\n", field, read_csr_entryhi());
-       pr_info("EntryLo0 : %0*llx\n", field, read_csr_entrylo0());
-       pr_info("EntryLo1 : %0*llx\n", field, read_csr_entrylo1());
+       pr_info("Index    : 0x%0x\n", read_csr_tlbidx());
+       pr_info("PageSize : 0x%0x\n", read_csr_pagesize());
+       pr_info("EntryHi  : 0x%0*llx\n", field, read_csr_entryhi());
+       pr_info("EntryLo0 : 0x%0*llx\n", field, read_csr_entrylo0());
+       pr_info("EntryLo1 : 0x%0*llx\n", field, read_csr_entrylo1());
 }
 
 static void dump_tlb(int first, int last)
@@ -33,8 +33,8 @@ static void dump_tlb(int first, int last)
        unsigned int s_index, s_asid;
        unsigned int pagesize, c0, c1, i;
        unsigned long asidmask = cpu_asid_mask(&current_cpu_data);
-       int pwidth = 11;
-       int vwidth = 11;
+       int pwidth = 16;
+       int vwidth = 16;
        int asidwidth = DIV_ROUND_UP(ilog2(asidmask) + 1, 4);
 
        s_entryhi = read_csr_entryhi();
@@ -64,22 +64,22 @@ static void dump_tlb(int first, int last)
                /*
                 * Only print entries in use
                 */
-               pr_info("Index: %2d pgsize=%x ", i, (1 << pagesize));
+               pr_info("Index: %4d pgsize=0x%x ", i, (1 << pagesize));
 
                c0 = (entrylo0 & ENTRYLO_C) >> ENTRYLO_C_SHIFT;
                c1 = (entrylo1 & ENTRYLO_C) >> ENTRYLO_C_SHIFT;
 
-               pr_cont("va=%0*lx asid=%0*lx",
+               pr_cont("va=0x%0*lx asid=0x%0*lx",
                        vwidth, (entryhi & ~0x1fffUL), asidwidth, asid & asidmask);
 
                /* NR/NX are in awkward places, so mask them off separately */
                pa = entrylo0 & ~(ENTRYLO_NR | ENTRYLO_NX);
                pa = pa & PAGE_MASK;
                pr_cont("\n\t[");
-               pr_cont("ri=%d xi=%d ",
+               pr_cont("nr=%d nx=%d ",
                        (entrylo0 & ENTRYLO_NR) ? 1 : 0,
                        (entrylo0 & ENTRYLO_NX) ? 1 : 0);
-               pr_cont("pa=%0*llx c=%d d=%d v=%d g=%d plv=%lld] [",
+               pr_cont("pa=0x%0*llx c=%d d=%d v=%d g=%d plv=%lld] [",
                        pwidth, pa, c0,
                        (entrylo0 & ENTRYLO_D) ? 1 : 0,
                        (entrylo0 & ENTRYLO_V) ? 1 : 0,
@@ -88,10 +88,10 @@ static void dump_tlb(int first, int last)
                /* NR/NX are in awkward places, so mask them off separately */
                pa = entrylo1 & ~(ENTRYLO_NR | ENTRYLO_NX);
                pa = pa & PAGE_MASK;
-               pr_cont("ri=%d xi=%d ",
+               pr_cont("nr=%d nx=%d ",
                        (entrylo1 & ENTRYLO_NR) ? 1 : 0,
                        (entrylo1 & ENTRYLO_NX) ? 1 : 0);
-               pr_cont("pa=%0*llx c=%d d=%d v=%d g=%d plv=%lld]\n",
+               pr_cont("pa=0x%0*llx c=%d d=%d v=%d g=%d plv=%lld]\n",
                        pwidth, pa, c1,
                        (entrylo1 & ENTRYLO_D) ? 1 : 0,
                        (entrylo1 & ENTRYLO_V) ? 1 : 0,
index 605579b..1ccd536 100644 (file)
@@ -216,6 +216,10 @@ good_area:
                return;
        }
 
+       /* The fault is fully completed (including releasing mmap lock) */
+       if (fault & VM_FAULT_COMPLETED)
+               return;
+
        if (unlikely(fault & VM_FAULT_RETRY)) {
                flags |= FAULT_FLAG_TRIED;
 
index 7094a68..0532ed5 100644 (file)
@@ -131,18 +131,6 @@ int arch_add_memory(int nid, u64 start, u64 size, struct mhp_params *params)
        return ret;
 }
 
-#ifdef CONFIG_NUMA
-int memory_add_physaddr_to_nid(u64 start)
-{
-       int nid;
-
-       nid = pa_to_nid(start);
-       return nid;
-}
-EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
-#endif
-
-#ifdef CONFIG_MEMORY_HOTREMOVE
 void arch_remove_memory(u64 start, u64 size, struct vmem_altmap *altmap)
 {
        unsigned long start_pfn = start >> PAGE_SHIFT;
@@ -154,6 +142,13 @@ void arch_remove_memory(u64 start, u64 size, struct vmem_altmap *altmap)
                page += vmem_altmap_offset(altmap);
        __remove_pages(start_pfn, nr_pages, altmap);
 }
+
+#ifdef CONFIG_NUMA
+int memory_add_physaddr_to_nid(u64 start)
+{
+       return pa_to_nid(start);
+}
+EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
 #endif
 #endif
 
index 52e40f0..381a569 100644 (file)
@@ -2,16 +2,9 @@
 /*
  * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
  */
-#include <linux/compiler.h>
-#include <linux/elf-randomize.h>
-#include <linux/errno.h>
+#include <linux/export.h>
 #include <linux/mm.h>
 #include <linux/mman.h>
-#include <linux/export.h>
-#include <linux/personality.h>
-#include <linux/random.h>
-#include <linux/sched/signal.h>
-#include <linux/sched/mm.h>
 
 unsigned long shm_align_mask = PAGE_SIZE - 1;  /* Sane caches */
 EXPORT_SYMBOL(shm_align_mask);
@@ -120,6 +113,6 @@ int __virt_addr_valid(volatile void *kaddr)
        if ((vaddr < PAGE_OFFSET) || (vaddr >= vm_map_base))
                return 0;
 
-       return pfn_valid(PFN_DOWN(virt_to_phys(kaddr)));
+       return pfn_valid(PFN_DOWN(PHYSADDR(kaddr)));
 }
 EXPORT_SYMBOL_GPL(__virt_addr_valid);
index 43a0078..e02e775 100644 (file)
@@ -24,6 +24,8 @@ static __always_inline const struct vdso_pcpu_data *get_pcpu_data(void)
        return (struct vdso_pcpu_data *)(get_vdso_base() - VDSO_DATA_SIZE);
 }
 
+extern
+int __vdso_getcpu(unsigned int *cpu, unsigned int *node, struct getcpu_cache *unused);
 int __vdso_getcpu(unsigned int *cpu, unsigned int *node, struct getcpu_cache *unused)
 {
        int cpu_id;
index b1f4548..8f22863 100644 (file)
@@ -6,20 +6,23 @@
  */
 #include <linux/types.h>
 
-int __vdso_clock_gettime(clockid_t clock,
-                        struct __kernel_timespec *ts)
+extern
+int __vdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts);
+int __vdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts)
 {
        return __cvdso_clock_gettime(clock, ts);
 }
 
-int __vdso_gettimeofday(struct __kernel_old_timeval *tv,
-                       struct timezone *tz)
+extern
+int __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz);
+int __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz)
 {
        return __cvdso_gettimeofday(tv, tz);
 }
 
-int __vdso_clock_getres(clockid_t clock_id,
-                       struct __kernel_timespec *res)
+extern
+int __vdso_clock_getres(clockid_t clock_id, struct __kernel_timespec *res);
+int __vdso_clock_getres(clockid_t clock_id, struct __kernel_timespec *res)
 {
        return __cvdso_clock_getres(clock_id, res);
 }
index 470aed9..e984af7 100644 (file)
@@ -157,11 +157,8 @@ arch___change_bit(unsigned long nr, volatile unsigned long *addr)
        change_bit(nr, addr);
 }
 
-static __always_inline bool
-arch_test_bit(unsigned long nr, const volatile unsigned long *addr)
-{
-       return (addr[nr >> 5] & (1UL << (nr & 31))) != 0;
-}
+#define arch_test_bit generic_test_bit
+#define arch_test_bit_acquire generic_test_bit_acquire
 
 static inline int bset_reg_test_and_set_bit(int nr,
                                            volatile unsigned long *vaddr)
index ec21f89..25dd4c5 100644 (file)
@@ -2669,7 +2669,6 @@ config ARCH_FLATMEM_ENABLE
 
 config ARCH_SPARSEMEM_ENABLE
        bool
-       select SPARSEMEM_STATIC if !SGI_IP27
 
 config NUMA
        bool "NUMA Support"
index bf13e35..aa7bbf8 100644 (file)
@@ -57,14 +57,11 @@ EXPORT_SYMBOL_GPL(__cvmx_cmd_queue_state_ptr);
 static cvmx_cmd_queue_result_t __cvmx_cmd_queue_init_state_ptr(void)
 {
        char *alloc_name = "cvmx_cmd_queues";
-#if defined(CONFIG_CAVIUM_RESERVE32) && CONFIG_CAVIUM_RESERVE32
        extern uint64_t octeon_reserve32_memory;
-#endif
 
        if (likely(__cvmx_cmd_queue_state_ptr))
                return CVMX_CMD_QUEUE_SUCCESS;
 
-#if defined(CONFIG_CAVIUM_RESERVE32) && CONFIG_CAVIUM_RESERVE32
        if (octeon_reserve32_memory)
                __cvmx_cmd_queue_state_ptr =
                    cvmx_bootmem_alloc_named_range(sizeof(*__cvmx_cmd_queue_state_ptr),
@@ -73,7 +70,6 @@ static cvmx_cmd_queue_result_t __cvmx_cmd_queue_init_state_ptr(void)
                                                   (CONFIG_CAVIUM_RESERVE32 <<
                                                    20) - 1, 128, alloc_name);
        else
-#endif
                __cvmx_cmd_queue_state_ptr =
                    cvmx_bootmem_alloc_named(sizeof(*__cvmx_cmd_queue_state_ptr),
                                            128,
index 9cb9ed4..fd8043f 100644 (file)
@@ -127,6 +127,16 @@ static void octeon_irq_free_cd(struct irq_domain *d, unsigned int irq)
 static int octeon_irq_force_ciu_mapping(struct irq_domain *domain,
                                        int irq, int line, int bit)
 {
+       struct device_node *of_node;
+       int ret;
+
+       of_node = irq_domain_get_of_node(domain);
+       if (!of_node)
+               return -EINVAL;
+       ret = irq_alloc_desc_at(irq, of_node_to_nid(of_node));
+       if (ret < 0)
+               return ret;
+
        return irq_domain_associate(domain, irq, line << 6 | bit);
 }
 
index cbd8320..e7f9943 100644 (file)
@@ -284,10 +284,8 @@ void octeon_crash_smp_send_stop(void)
 
 #endif /* CONFIG_KEXEC */
 
-#ifdef CONFIG_CAVIUM_RESERVE32
 uint64_t octeon_reserve32_memory;
 EXPORT_SYMBOL(octeon_reserve32_memory);
-#endif
 
 #ifdef CONFIG_KEXEC
 /* crashkernel cmdline parameter is parsed _after_ memory setup
@@ -666,9 +664,6 @@ void __init prom_init(void)
        int i;
        u64 t;
        int argc;
-#ifdef CONFIG_CAVIUM_RESERVE32
-       int64_t addr = -1;
-#endif
        /*
         * The bootloader passes a pointer to the boot descriptor in
         * $a3, this is available as fw_arg3.
@@ -783,7 +778,7 @@ void __init prom_init(void)
                cvmx_write_csr(CVMX_LED_UDD_DATX(1), 0);
                cvmx_write_csr(CVMX_LED_EN, 1);
        }
-#ifdef CONFIG_CAVIUM_RESERVE32
+
        /*
         * We need to temporarily allocate all memory in the reserve32
         * region. This makes sure the kernel doesn't allocate this
@@ -794,14 +789,16 @@ void __init prom_init(void)
         * Allocate memory for RESERVED32 aligned on 2MB boundary. This
         * is in case we later use hugetlb entries with it.
         */
-       addr = cvmx_bootmem_phy_named_block_alloc(CONFIG_CAVIUM_RESERVE32 << 20,
-                                               0, 0, 2 << 20,
-                                               "CAVIUM_RESERVE32", 0);
-       if (addr < 0)
-               pr_err("Failed to allocate CAVIUM_RESERVE32 memory area\n");
-       else
-               octeon_reserve32_memory = addr;
-#endif
+       if (CONFIG_CAVIUM_RESERVE32) {
+               int64_t addr =
+                       cvmx_bootmem_phy_named_block_alloc(CONFIG_CAVIUM_RESERVE32 << 20,
+                                                          0, 0, 2 << 20,
+                                                          "CAVIUM_RESERVE32", 0);
+               if (addr < 0)
+                       pr_err("Failed to allocate CAVIUM_RESERVE32 memory area\n");
+               else
+                       octeon_reserve32_memory = addr;
+       }
 
 #ifdef CONFIG_CAVIUM_OCTEON_LOCK_L2
        if (cvmx_read_csr(CVMX_L2D_FUS3) & (3ull << 34)) {
@@ -1079,7 +1076,6 @@ void __init plat_mem_setup(void)
        cvmx_bootmem_unlock();
 #endif /* CONFIG_CRASH_DUMP */
 
-#ifdef CONFIG_CAVIUM_RESERVE32
        /*
         * Now that we've allocated the kernel memory it is safe to
         * free the reserved region. We free it here so that builtin
@@ -1087,7 +1083,6 @@ void __init plat_mem_setup(void)
         */
        if (octeon_reserve32_memory)
                cvmx_bootmem_free_named("CAVIUM_RESERVE32");
-#endif /* CONFIG_CAVIUM_RESERVE32 */
 
        if (total == 0)
                panic("Unable to allocate memory from "
index 717716c..5cedb28 100644 (file)
@@ -84,8 +84,6 @@
 
 
 #define KVM_MAX_VCPUS          16
-/* memory slots that does not exposed to userspace */
-#define KVM_PRIVATE_MEM_SLOTS  0
 
 #define KVM_HALT_POLL_NS_DEFAULT 500000
 
index db17e87..74cd64a 100644 (file)
@@ -615,17 +615,17 @@ retry:
         * Used to check for invalidations in progress, of the pfn that is
         * returned by pfn_to_pfn_prot below.
         */
-       mmu_seq = kvm->mmu_notifier_seq;
+       mmu_seq = kvm->mmu_invalidate_seq;
        /*
-        * Ensure the read of mmu_notifier_seq isn't reordered with PTE reads in
-        * gfn_to_pfn_prot() (which calls get_user_pages()), so that we don't
+        * Ensure the read of mmu_invalidate_seq isn't reordered with PTE reads
+        * in gfn_to_pfn_prot() (which calls get_user_pages()), so that we don't
         * risk the page we get a reference to getting unmapped before we have a
-        * chance to grab the mmu_lock without mmu_notifier_retry() noticing.
+        * chance to grab the mmu_lock without mmu_invalidate_retry() noticing.
         *
         * This smp_rmb() pairs with the effective smp_wmb() of the combination
         * of the pte_unmap_unlock() after the PTE is zapped, and the
         * spin_lock() in kvm_mmu_notifier_invalidate_<page|range_end>() before
-        * mmu_notifier_seq is incremented.
+        * mmu_invalidate_seq is incremented.
         */
        smp_rmb();
 
@@ -638,7 +638,7 @@ retry:
 
        spin_lock(&kvm->mmu_lock);
        /* Check if an invalidation has taken place since we got pfn */
-       if (mmu_notifier_retry(kvm, mmu_seq)) {
+       if (mmu_invalidate_retry(kvm, mmu_seq)) {
                /*
                 * This can happen when mappings are changed asynchronously, but
                 * also synchronously if a COW is triggered by
index 7a62368..2d5a0bc 100644 (file)
@@ -50,6 +50,7 @@ struct clk *clk_get_io(void)
 {
        return &cpu_clk_generic[2];
 }
+EXPORT_SYMBOL_GPL(clk_get_io);
 
 struct clk *clk_get_ppe(void)
 {
index 794c96c..311dc15 100644 (file)
@@ -98,7 +98,7 @@ int ls1x_eth_mux_init(struct platform_device *pdev, void *priv)
        if (plat_dat->bus_id) {
                __raw_writel(__raw_readl(LS1X_MUX_CTRL0) | GMAC1_USE_UART1 |
                             GMAC1_USE_UART0, LS1X_MUX_CTRL0);
-               switch (plat_dat->interface) {
+               switch (plat_dat->phy_interface) {
                case PHY_INTERFACE_MODE_RGMII:
                        val &= ~(GMAC1_USE_TXCLK | GMAC1_USE_PWM23);
                        break;
@@ -107,12 +107,12 @@ int ls1x_eth_mux_init(struct platform_device *pdev, void *priv)
                        break;
                default:
                        pr_err("unsupported mii mode %d\n",
-                              plat_dat->interface);
+                              plat_dat->phy_interface);
                        return -ENOTSUPP;
                }
                val &= ~GMAC1_SHUT;
        } else {
-               switch (plat_dat->interface) {
+               switch (plat_dat->phy_interface) {
                case PHY_INTERFACE_MODE_RGMII:
                        val &= ~(GMAC0_USE_TXCLK | GMAC0_USE_PWM01);
                        break;
@@ -121,7 +121,7 @@ int ls1x_eth_mux_init(struct platform_device *pdev, void *priv)
                        break;
                default:
                        pr_err("unsupported mii mode %d\n",
-                              plat_dat->interface);
+                              plat_dat->phy_interface);
                        return -ENOTSUPP;
                }
                val &= ~GMAC0_SHUT;
@@ -131,7 +131,7 @@ int ls1x_eth_mux_init(struct platform_device *pdev, void *priv)
        plat_dat = dev_get_platdata(&pdev->dev);
 
        val &= ~PHY_INTF_SELI;
-       if (plat_dat->interface == PHY_INTERFACE_MODE_RMII)
+       if (plat_dat->phy_interface == PHY_INTERFACE_MODE_RMII)
                val |= 0x4 << PHY_INTF_SELI_SHIFT;
        __raw_writel(val, LS1X_MUX_CTRL1);
 
@@ -146,9 +146,9 @@ static struct plat_stmmacenet_data ls1x_eth0_pdata = {
        .bus_id                 = 0,
        .phy_addr               = -1,
 #if defined(CONFIG_LOONGSON1_LS1B)
-       .interface              = PHY_INTERFACE_MODE_MII,
+       .phy_interface          = PHY_INTERFACE_MODE_MII,
 #elif defined(CONFIG_LOONGSON1_LS1C)
-       .interface              = PHY_INTERFACE_MODE_RMII,
+       .phy_interface          = PHY_INTERFACE_MODE_RMII,
 #endif
        .mdio_bus_data          = &ls1x_mdio_bus_data,
        .dma_cfg                = &ls1x_eth_dma_cfg,
@@ -186,7 +186,7 @@ struct platform_device ls1x_eth0_pdev = {
 static struct plat_stmmacenet_data ls1x_eth1_pdata = {
        .bus_id                 = 1,
        .phy_addr               = -1,
-       .interface              = PHY_INTERFACE_MODE_MII,
+       .phy_interface          = PHY_INTERFACE_MODE_MII,
        .mdio_bus_data          = &ls1x_mdio_bus_data,
        .dma_cfg                = &ls1x_eth_dma_cfg,
        .has_gmac               = 1,
index e9de6da..9dcfe9d 100644 (file)
@@ -15,7 +15,6 @@ static struct platform_device *ls1c_platform_devices[] __initdata = {
 static int __init ls1c_platform_init(void)
 {
        ls1x_serial_set_uartclk(&ls1x_uart_pdev);
-       ls1x_rtc_set_extclk(&ls1x_rtc_pdev);
 
        return platform_add_devices(ls1c_platform_devices,
                                   ARRAY_SIZE(ls1c_platform_devices));
index cf37f55..bafb7b2 100644 (file)
@@ -50,7 +50,8 @@
        stw     r13, PT_R13(sp)
        stw     r14, PT_R14(sp)
        stw     r15, PT_R15(sp)
-       stw     r2, PT_ORIG_R2(sp)
+       movi    r24, -1
+       stw     r24, PT_ORIG_R2(sp)
        stw     r7, PT_ORIG_R7(sp)
 
        stw     ra, PT_RA(sp)
index 6424621..9da34c3 100644 (file)
@@ -74,6 +74,8 @@ extern void show_regs(struct pt_regs *);
        ((struct pt_regs *)((unsigned long)current_thread_info() + THREAD_SIZE)\
                - 1)
 
+#define force_successful_syscall_return() (current_pt_regs()->orig_r2 = -1)
+
 int do_syscall_trace_enter(void);
 void do_syscall_trace_exit(void);
 #endif /* __ASSEMBLY__ */
index 0794cd7..99f0a65 100644 (file)
@@ -185,6 +185,7 @@ ENTRY(handle_system_call)
        ldw     r5, PT_R5(sp)
 
 local_restart:
+       stw     r2, PT_ORIG_R2(sp)
        /* Check that the requested system call is within limits */
        movui   r1, __NR_syscalls
        bgeu    r2, r1, ret_invsyscall
@@ -192,7 +193,6 @@ local_restart:
        movhi   r11, %hiadj(sys_call_table)
        add     r1, r1, r11
        ldw     r1, %lo(sys_call_table)(r1)
-       beq     r1, r0, ret_invsyscall
 
        /* Check if we are being traced */
        GET_THREAD_INFO r11
@@ -213,6 +213,9 @@ local_restart:
 translate_rc_and_ret:
        movi    r1, 0
        bge     r2, zero, 3f
+       ldw     r1, PT_ORIG_R2(sp)
+       addi    r1, r1, 1
+       beq     r1, zero, 3f
        sub     r2, zero, r2
        movi    r1, 1
 3:
@@ -255,9 +258,9 @@ traced_system_call:
        ldw     r6, PT_R6(sp)
        ldw     r7, PT_R7(sp)
 
-       /* Fetch the syscall function, we don't need to check the boundaries
-        * since this is already done.
-        */
+       /* Fetch the syscall function. */
+       movui   r1, __NR_syscalls
+       bgeu    r2, r1, traced_invsyscall
        slli    r1, r2, 2
        movhi   r11,%hiadj(sys_call_table)
        add     r1, r1, r11
@@ -276,6 +279,9 @@ traced_system_call:
 translate_rc_and_ret2:
        movi    r1, 0
        bge     r2, zero, 4f
+       ldw     r1, PT_ORIG_R2(sp)
+       addi    r1, r1, 1
+       beq     r1, zero, 4f
        sub     r2, zero, r2
        movi    r1, 1
 4:
@@ -287,6 +293,11 @@ end_translate_rc_and_ret2:
        RESTORE_SWITCH_STACK
        br      ret_from_exception
 
+       /* If the syscall number was invalid return ENOSYS */
+traced_invsyscall:
+       movi    r2, -ENOSYS
+       br      translate_rc_and_ret2
+
 Luser_return:
        GET_THREAD_INFO r11                     /* get thread_info pointer */
        ldw     r10, TI_FLAGS(r11)              /* get thread_info->flags */
@@ -336,9 +347,6 @@ external_interrupt:
        /* skip if no interrupt is pending */
        beq     r12, r0, ret_from_interrupt
 
-       movi    r24, -1
-       stw     r24, PT_ORIG_R2(sp)
-
        /*
         * Process an external hardware interrupt.
         */
index cb0b915..a5b93a3 100644 (file)
@@ -242,7 +242,7 @@ static int do_signal(struct pt_regs *regs)
        /*
         * If we were from a system call, check for system call restarting...
         */
-       if (regs->orig_r2 >= 0) {
+       if (regs->orig_r2 >= 0 && regs->r1) {
                continue_addr = regs->ea;
                restart_addr = continue_addr - 4;
                retval = regs->r2;
@@ -264,6 +264,7 @@ static int do_signal(struct pt_regs *regs)
                        regs->ea = restart_addr;
                        break;
                }
+               regs->orig_r2 = -1;
        }
 
        if (get_signal(&ksig)) {
index 6176d63..c2875a6 100644 (file)
@@ -13,5 +13,6 @@
 #define __SYSCALL(nr, call) [nr] = (call),
 
 void *sys_call_table[__NR_syscalls] = {
+       [0 ... __NR_syscalls-1] = sys_ni_syscall,
 #include <asm/unistd.h>
 };
index 7f059cd..a98940e 100644 (file)
@@ -146,10 +146,10 @@ menu "Processor type and features"
 
 choice
        prompt "Processor type"
-       default PA7000
+       default PA7000 if "$(ARCH)" = "parisc"
 
 config PA7000
-       bool "PA7000/PA7100"
+       bool "PA7000/PA7100" if "$(ARCH)" = "parisc"
        help
          This is the processor type of your CPU.  This information is
          used for optimizing purposes.  In order to compile a kernel
@@ -160,21 +160,21 @@ config PA7000
          which is required on some machines.
 
 config PA7100LC
-       bool "PA7100LC"
+       bool "PA7100LC" if "$(ARCH)" = "parisc"
        help
          Select this option for the PCX-L processor, as used in the
          712, 715/64, 715/80, 715/100, 715/100XC, 725/100, 743, 748,
          D200, D210, D300, D310 and E-class
 
 config PA7200
-       bool "PA7200"
+       bool "PA7200" if "$(ARCH)" = "parisc"
        help
          Select this option for the PCX-T' processor, as used in the
          C100, C110, J100, J110, J210XC, D250, D260, D350, D360,
          K100, K200, K210, K220, K400, K410 and K420
 
 config PA7300LC
-       bool "PA7300LC"
+       bool "PA7300LC" if "$(ARCH)" = "parisc"
        help
          Select this option for the PCX-L2 processor, as used in the
          744, A180, B132L, B160L, B180L, C132L, C160L, C180L,
@@ -224,7 +224,8 @@ config MLONGCALLS
          Enabling this option will probably slow down your kernel.
 
 config 64BIT
-       bool "64-bit kernel"
+       def_bool y if "$(ARCH)" = "parisc64"
+       bool "64-bit kernel" if "$(ARCH)" = "parisc"
        depends on PA8X00
        help
          Enable this if you want to support 64bit kernel on PA-RISC platform.
index 56ffd26..0ec9cfc 100644 (file)
 #include <asm/barrier.h>
 #include <linux/atomic.h>
 
-/* compiler build environment sanity checks: */
-#if !defined(CONFIG_64BIT) && defined(__LP64__)
-#error "Please use 'ARCH=parisc' to build the 32-bit kernel."
-#endif
-#if defined(CONFIG_64BIT) && !defined(__LP64__)
-#error "Please use 'ARCH=parisc64' to build the 64-bit kernel."
-#endif
-
 /* See http://marc.theaimsgroup.com/?t=108826637900003 for discussion
  * on use of volatile and __*_bit() (set/clear/change):
  *     *_bit() want use of volatile.
index e0a9e96..fd15fd4 100644 (file)
@@ -22,7 +22,7 @@
 #include <linux/init.h>
 #include <linux/pgtable.h>
 
-       .level  PA_ASM_LEVEL
+       .level  1.1
 
        __INITDATA
 ENTRY(boot_args)
@@ -70,6 +70,47 @@ $bss_loop:
        stw,ma          %arg2,4(%r1)
        stw,ma          %arg3,4(%r1)
 
+#if !defined(CONFIG_64BIT) && defined(CONFIG_PA20)
+       /* This 32-bit kernel was compiled for PA2.0 CPUs. Check current CPU
+        * and halt kernel if we detect a PA1.x CPU. */
+       ldi             32,%r10
+       mtctl           %r10,%cr11
+       .level 2.0
+       mfctl,w         %cr11,%r10
+       .level 1.1
+       comib,<>,n      0,%r10,$cpu_ok
+
+       load32          PA(msg1),%arg0
+       ldi             msg1_end-msg1,%arg1
+$iodc_panic:
+       copy            %arg0, %r10
+       copy            %arg1, %r11
+       load32          PA(init_stack),%sp
+#define MEM_CONS 0x3A0
+       ldw             MEM_CONS+32(%r0),%arg0  // HPA
+       ldi             ENTRY_IO_COUT,%arg1
+       ldw             MEM_CONS+36(%r0),%arg2  // SPA
+       ldw             MEM_CONS+8(%r0),%arg3   // layers
+       load32          PA(__bss_start),%r1
+       stw             %r1,-52(%sp)            // arg4
+       stw             %r0,-56(%sp)            // arg5
+       stw             %r10,-60(%sp)           // arg6 = ptr to text
+       stw             %r11,-64(%sp)           // arg7 = len
+       stw             %r0,-68(%sp)            // arg8
+       load32          PA(.iodc_panic_ret), %rp
+       ldw             MEM_CONS+40(%r0),%r1    // ENTRY_IODC
+       bv,n            (%r1)
+.iodc_panic_ret:
+       b .                             /* wait endless with ... */
+       or              %r10,%r10,%r10  /* qemu idle sleep */
+msg1:  .ascii "Can't boot kernel which was built for PA8x00 CPUs on this machine.\r\n"
+msg1_end:
+
+$cpu_ok:
+#endif
+
+       .level  PA_ASM_LEVEL
+
        /* Initialize startup VM. Just map first 16/32 MB of memory */
        load32          PA(swapper_pg_dir),%r4
        mtctl           %r4,%cr24       /* Initialize kernel root pointer */
index fbb882c..b05055f 100644 (file)
@@ -480,7 +480,7 @@ static void execute_on_irq_stack(void *func, unsigned long param1)
        *irq_stack_in_use = 1;
 }
 
-#ifndef CONFIG_PREEMPT_RT
+#ifdef CONFIG_SOFTIRQ_ON_OWN_STACK
 void do_softirq_own_stack(void)
 {
        execute_on_irq_stack(__do_softirq, 0);
index bac581b..e8a4d77 100644 (file)
@@ -93,7 +93,7 @@
 #define R1(i) (((i)>>21)&0x1f)
 #define R2(i) (((i)>>16)&0x1f)
 #define R3(i) ((i)&0x1f)
-#define FR3(i) ((((i)<<1)&0x1f)|(((i)>>6)&1))
+#define FR3(i) ((((i)&0x1f)<<1)|(((i)>>6)&1))
 #define IM(i,n) (((i)>>1&((1<<(n-1))-1))|((i)&1?((0-1L)<<(n-1)):0))
 #define IM5_2(i) IM((i)>>16,5)
 #define IM5_3(i) IM((i),5)
index 398e0b5..ed6db13 100644 (file)
@@ -83,6 +83,8 @@ enum {
        FW_FEATURE_POWERNV_ALWAYS = 0,
        FW_FEATURE_PS3_POSSIBLE = FW_FEATURE_LPAR | FW_FEATURE_PS3_LV1,
        FW_FEATURE_PS3_ALWAYS = FW_FEATURE_LPAR | FW_FEATURE_PS3_LV1,
+       FW_FEATURE_NATIVE_POSSIBLE = 0,
+       FW_FEATURE_NATIVE_ALWAYS = 0,
        FW_FEATURE_POSSIBLE =
 #ifdef CONFIG_PPC_PSERIES
                FW_FEATURE_PSERIES_POSSIBLE |
@@ -93,6 +95,9 @@ enum {
 #ifdef CONFIG_PPC_PS3
                FW_FEATURE_PS3_POSSIBLE |
 #endif
+#ifdef CONFIG_PPC_HASH_MMU_NATIVE
+               FW_FEATURE_NATIVE_ALWAYS |
+#endif
                0,
        FW_FEATURE_ALWAYS =
 #ifdef CONFIG_PPC_PSERIES
@@ -104,6 +109,9 @@ enum {
 #ifdef CONFIG_PPC_PS3
                FW_FEATURE_PS3_ALWAYS &
 #endif
+#ifdef CONFIG_PPC_HASH_MMU_NATIVE
+               FW_FEATURE_NATIVE_ALWAYS &
+#endif
                FW_FEATURE_POSSIBLE,
 
 #else /* CONFIG_PPC64 */
index 26ede09..9835518 100644 (file)
@@ -113,7 +113,14 @@ static inline void __hard_RI_enable(void)
 
 static inline notrace unsigned long irq_soft_mask_return(void)
 {
-       return READ_ONCE(local_paca->irq_soft_mask);
+       unsigned long flags;
+
+       asm volatile(
+               "lbz %0,%1(13)"
+               : "=r" (flags)
+               : "i" (offsetof(struct paca_struct, irq_soft_mask)));
+
+       return flags;
 }
 
 /*
@@ -140,24 +147,46 @@ static inline notrace void irq_soft_mask_set(unsigned long mask)
        if (IS_ENABLED(CONFIG_PPC_IRQ_SOFT_MASK_DEBUG))
                WARN_ON(mask && !(mask & IRQS_DISABLED));
 
-       WRITE_ONCE(local_paca->irq_soft_mask, mask);
-       barrier();
+       asm volatile(
+               "stb %0,%1(13)"
+               :
+               : "r" (mask),
+                 "i" (offsetof(struct paca_struct, irq_soft_mask))
+               : "memory");
 }
 
 static inline notrace unsigned long irq_soft_mask_set_return(unsigned long mask)
 {
-       unsigned long flags = irq_soft_mask_return();
+       unsigned long flags;
 
-       irq_soft_mask_set(mask);
+#ifdef CONFIG_PPC_IRQ_SOFT_MASK_DEBUG
+       WARN_ON(mask && !(mask & IRQS_DISABLED));
+#endif
+
+       asm volatile(
+               "lbz %0,%1(13); stb %2,%1(13)"
+               : "=&r" (flags)
+               : "i" (offsetof(struct paca_struct, irq_soft_mask)),
+                 "r" (mask)
+               : "memory");
 
        return flags;
 }
 
 static inline notrace unsigned long irq_soft_mask_or_return(unsigned long mask)
 {
-       unsigned long flags = irq_soft_mask_return();
+       unsigned long flags, tmp;
+
+       asm volatile(
+               "lbz %0,%2(13); or %1,%0,%3; stb %1,%2(13)"
+               : "=&r" (flags), "=r" (tmp)
+               : "i" (offsetof(struct paca_struct, irq_soft_mask)),
+                 "r" (mask)
+               : "memory");
 
-       irq_soft_mask_set(flags | mask);
+#ifdef CONFIG_PPC_IRQ_SOFT_MASK_DEBUG
+       WARN_ON((mask | flags) && !((mask | flags) & IRQS_DISABLED));
+#endif
 
        return flags;
 }
@@ -282,7 +311,8 @@ static inline bool pmi_irq_pending(void)
        flags = irq_soft_mask_set_return(IRQS_ALL_DISABLED);            \
        local_paca->irq_happened |= PACA_IRQ_HARD_DIS;                  \
        if (!arch_irqs_disabled_flags(flags)) {                         \
-               WRITE_ONCE(local_paca->saved_r1, current_stack_pointer);\
+               asm volatile("std%X0 %1,%0" : "=m" (local_paca->saved_r1) \
+                                           : "r" (current_stack_pointer)); \
                trace_hardirqs_off();                                   \
        }                                                               \
 } while(0)
index 4def2bd..d49065a 100644 (file)
@@ -666,7 +666,7 @@ static inline pte_t *find_kvm_host_pte(struct kvm *kvm, unsigned long mmu_seq,
        VM_WARN(!spin_is_locked(&kvm->mmu_lock),
                "%s called with kvm mmu_lock not held \n", __func__);
 
-       if (mmu_notifier_retry(kvm, mmu_seq))
+       if (mmu_invalidate_retry(kvm, mmu_seq))
                return NULL;
 
        pte = __find_linux_pte(kvm->mm->pgd, ea, NULL, hshift);
index 0f17268..9ede61a 100644 (file)
@@ -199,7 +199,7 @@ static inline void check_stack_overflow(unsigned long sp)
        }
 }
 
-#ifndef CONFIG_PREEMPT_RT
+#ifdef CONFIG_SOFTIRQ_ON_OWN_STACK
 static __always_inline void call_do_softirq(const void *sp)
 {
        /* Temporarily switch r1 to sp, call __do_softirq() then restore r1. */
@@ -335,7 +335,7 @@ void *mcheckirq_ctx[NR_CPUS] __read_mostly;
 void *softirq_ctx[NR_CPUS] __read_mostly;
 void *hardirq_ctx[NR_CPUS] __read_mostly;
 
-#ifndef CONFIG_PREEMPT_RT
+#ifdef CONFIG_SOFTIRQ_ON_OWN_STACK
 void do_softirq_own_stack(void)
 {
        call_do_softirq(softirq_ctx[smp_processor_id()]);
index bdd3332..31de91c 100644 (file)
@@ -68,10 +68,6 @@ void __init set_pci_dma_ops(const struct dma_map_ops *dma_ops)
        pci_dma_ops = dma_ops;
 }
 
-/*
- * This function should run under locking protection, specifically
- * hose_spinlock.
- */
 static int get_phb_number(struct device_node *dn)
 {
        int ret, phb_id = -1;
@@ -108,15 +104,20 @@ static int get_phb_number(struct device_node *dn)
        if (!ret)
                phb_id = (int)(prop & (MAX_PHBS - 1));
 
+       spin_lock(&hose_spinlock);
+
        /* We need to be sure to not use the same PHB number twice. */
        if ((phb_id >= 0) && !test_and_set_bit(phb_id, phb_bitmap))
-               return phb_id;
+               goto out_unlock;
 
        /* If everything fails then fallback to dynamic PHB numbering. */
        phb_id = find_first_zero_bit(phb_bitmap, MAX_PHBS);
        BUG_ON(phb_id >= MAX_PHBS);
        set_bit(phb_id, phb_bitmap);
 
+out_unlock:
+       spin_unlock(&hose_spinlock);
+
        return phb_id;
 }
 
@@ -127,10 +128,13 @@ struct pci_controller *pcibios_alloc_controller(struct device_node *dev)
        phb = zalloc_maybe_bootmem(sizeof(struct pci_controller), GFP_KERNEL);
        if (phb == NULL)
                return NULL;
-       spin_lock(&hose_spinlock);
+
        phb->global_number = get_phb_number(dev);
+
+       spin_lock(&hose_spinlock);
        list_add_tail(&phb->list_node, &hose_list);
        spin_unlock(&hose_spinlock);
+
        phb->dn = dev;
        phb->is_dynamic = slab_is_available();
 #ifdef CONFIG_PPC64
index 433965b..855b598 100644 (file)
@@ -245,6 +245,15 @@ static int __init pcibios_init(void)
 
        printk(KERN_INFO "PCI: Probing PCI hardware\n");
 
+#ifdef CONFIG_PPC_PCI_BUS_NUM_DOMAIN_DEPENDENT
+       /*
+        * Enable PCI domains in /proc when PCI bus numbers are not unique
+        * across all PCI domains to prevent conflicts. And keep PCI domain 0
+        * backward compatible in /proc for video cards.
+        */
+       pci_add_flags(PCI_ENABLE_PROC_DOMAINS | PCI_COMPAT_DOMAIN_0);
+#endif
+
        if (pci_has_flag(PCI_REASSIGN_ALL_BUS))
                pci_assign_all_buses = 1;
 
index 9a434d4..6ce95dd 100644 (file)
@@ -109,8 +109,12 @@ __enter_rtas:
         * its critical regions (as specified in PAPR+ section 7.2.1). MSR[S]
         * is not impacted by RFI_TO_KERNEL (only urfid can unset it). So if
         * MSR[S] is set, it will remain when entering RTAS.
+        * If we're in HV mode, RTAS must also run in HV mode, so extract MSR_HV
+        * from the saved MSR value and insert into the value RTAS will use.
         */
+       extrdi  r0, r6, 1, 63 - MSR_HV_LG
        LOAD_REG_IMMEDIATE(r6, MSR_ME | MSR_RI)
+       insrdi  r6, r0, 1, 63 - MSR_HV_LG
 
        li      r0,0
        mtmsrd  r0,1                    /* disable RI before using SRR0/1 */
index cb33588..6c1db3b 100644 (file)
@@ -18,6 +18,7 @@
        .p2align        3
 #define __SYSCALL(nr, entry)   .8byte entry
 #else
+       .p2align        2
 #define __SYSCALL(nr, entry)   .long entry
 #endif
 
index 1ae0999..bc6a381 100644 (file)
@@ -90,7 +90,7 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte,
        unsigned long pfn;
 
        /* used to check for invalidations in progress */
-       mmu_seq = kvm->mmu_notifier_seq;
+       mmu_seq = kvm->mmu_invalidate_seq;
        smp_rmb();
 
        /* Get host physical address for gpa */
@@ -151,7 +151,7 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte,
        cpte = kvmppc_mmu_hpte_cache_next(vcpu);
 
        spin_lock(&kvm->mmu_lock);
-       if (!cpte || mmu_notifier_retry(kvm, mmu_seq)) {
+       if (!cpte || mmu_invalidate_retry(kvm, mmu_seq)) {
                r = -EAGAIN;
                goto out_unlock;
        }
index 514fd45..e9744b4 100644 (file)
@@ -578,7 +578,7 @@ int kvmppc_book3s_hv_page_fault(struct kvm_vcpu *vcpu,
                return -EFAULT;
 
        /* used to check for invalidations in progress */
-       mmu_seq = kvm->mmu_notifier_seq;
+       mmu_seq = kvm->mmu_invalidate_seq;
        smp_rmb();
 
        ret = -EFAULT;
@@ -693,7 +693,7 @@ int kvmppc_book3s_hv_page_fault(struct kvm_vcpu *vcpu,
 
        /* Check if we might have been invalidated; let the guest retry if so */
        ret = RESUME_GUEST;
-       if (mmu_notifier_retry(vcpu->kvm, mmu_seq)) {
+       if (mmu_invalidate_retry(vcpu->kvm, mmu_seq)) {
                unlock_rmap(rmap);
                goto out_unlock;
        }
index 9d4b3fe..5d5e12f 100644 (file)
@@ -640,7 +640,7 @@ int kvmppc_create_pte(struct kvm *kvm, pgd_t *pgtable, pte_t pte,
        /* Check if we might have been invalidated; let the guest retry if so */
        spin_lock(&kvm->mmu_lock);
        ret = -EAGAIN;
-       if (mmu_notifier_retry(kvm, mmu_seq))
+       if (mmu_invalidate_retry(kvm, mmu_seq))
                goto out_unlock;
 
        /* Now traverse again under the lock and change the tree */
@@ -830,7 +830,7 @@ int kvmppc_book3s_instantiate_page(struct kvm_vcpu *vcpu,
        bool large_enable;
 
        /* used to check for invalidations in progress */
-       mmu_seq = kvm->mmu_notifier_seq;
+       mmu_seq = kvm->mmu_invalidate_seq;
        smp_rmb();
 
        /*
@@ -1191,7 +1191,7 @@ void kvmppc_radix_flush_memslot(struct kvm *kvm,
         * Increase the mmu notifier sequence number to prevent any page
         * fault that read the memslot earlier from writing a PTE.
         */
-       kvm->mmu_notifier_seq++;
+       kvm->mmu_invalidate_seq++;
        spin_unlock(&kvm->mmu_lock);
 }
 
index be8249c..5a64a13 100644 (file)
@@ -1580,7 +1580,7 @@ static long int __kvmhv_nested_page_fault(struct kvm_vcpu *vcpu,
        /* 2. Find the host pte for this L1 guest real address */
 
        /* Used to check for invalidations in progress */
-       mmu_seq = kvm->mmu_notifier_seq;
+       mmu_seq = kvm->mmu_invalidate_seq;
        smp_rmb();
 
        /* See if can find translation in our partition scoped tables for L1 */
index 2257fb1..5a05953 100644 (file)
@@ -219,7 +219,7 @@ long kvmppc_do_h_enter(struct kvm *kvm, unsigned long flags,
        g_ptel = ptel;
 
        /* used later to detect if we might have been invalidated */
-       mmu_seq = kvm->mmu_notifier_seq;
+       mmu_seq = kvm->mmu_invalidate_seq;
        smp_rmb();
 
        /* Find the memslot (if any) for this address */
@@ -366,7 +366,7 @@ long kvmppc_do_h_enter(struct kvm *kvm, unsigned long flags,
                        rmap = real_vmalloc_addr(rmap);
                lock_rmap(rmap);
                /* Check for pending invalidations under the rmap chain lock */
-               if (mmu_notifier_retry(kvm, mmu_seq)) {
+               if (mmu_invalidate_retry(kvm, mmu_seq)) {
                        /* inval in progress, write a non-present HPTE */
                        pteh |= HPTE_V_ABSENT;
                        pteh &= ~HPTE_V_VALID;
@@ -932,7 +932,7 @@ static long kvmppc_do_h_page_init_zero(struct kvm_vcpu *vcpu,
        int i;
 
        /* Used later to detect if we might have been invalidated */
-       mmu_seq = kvm->mmu_notifier_seq;
+       mmu_seq = kvm->mmu_invalidate_seq;
        smp_rmb();
 
        arch_spin_lock(&kvm->mmu_lock.rlock.raw_lock);
@@ -960,7 +960,7 @@ static long kvmppc_do_h_page_init_copy(struct kvm_vcpu *vcpu,
        long ret = H_SUCCESS;
 
        /* Used later to detect if we might have been invalidated */
-       mmu_seq = kvm->mmu_notifier_seq;
+       mmu_seq = kvm->mmu_invalidate_seq;
        smp_rmb();
 
        arch_spin_lock(&kvm->mmu_lock.rlock.raw_lock);
index 7f16afc..05668e9 100644 (file)
@@ -339,7 +339,7 @@ static inline int kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500,
        unsigned long flags;
 
        /* used to check for invalidations in progress */
-       mmu_seq = kvm->mmu_notifier_seq;
+       mmu_seq = kvm->mmu_invalidate_seq;
        smp_rmb();
 
        /*
@@ -460,7 +460,7 @@ static inline int kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500,
        }
 
        spin_lock(&kvm->mmu_lock);
-       if (mmu_notifier_retry(kvm, mmu_seq)) {
+       if (mmu_invalidate_retry(kvm, mmu_seq)) {
                ret = -EAGAIN;
                goto out;
        }
index 20f6ed8..2f83855 100644 (file)
@@ -124,9 +124,6 @@ struct papr_scm_priv {
 
        /* The bits which needs to be overridden */
        u64 health_bitmap_inject_mask;
-
-       /* array to have event_code and stat_id mappings */
-       u8 *nvdimm_events_map;
 };
 
 static int papr_scm_pmem_flush(struct nd_region *nd_region,
@@ -350,6 +347,25 @@ static ssize_t drc_pmem_query_stats(struct papr_scm_priv *p,
 #ifdef CONFIG_PERF_EVENTS
 #define to_nvdimm_pmu(_pmu)    container_of(_pmu, struct nvdimm_pmu, pmu)
 
+static const char * const nvdimm_events_map[] = {
+       [1] = "CtlResCt",
+       [2] = "CtlResTm",
+       [3] = "PonSecs ",
+       [4] = "MemLife ",
+       [5] = "CritRscU",
+       [6] = "HostLCnt",
+       [7] = "HostSCnt",
+       [8] = "HostSDur",
+       [9] = "HostLDur",
+       [10] = "MedRCnt ",
+       [11] = "MedWCnt ",
+       [12] = "MedRDur ",
+       [13] = "MedWDur ",
+       [14] = "CchRHCnt",
+       [15] = "CchWHCnt",
+       [16] = "FastWCnt",
+};
+
 static int papr_scm_pmu_get_value(struct perf_event *event, struct device *dev, u64 *count)
 {
        struct papr_scm_perf_stat *stat;
@@ -357,11 +373,15 @@ static int papr_scm_pmu_get_value(struct perf_event *event, struct device *dev,
        struct papr_scm_priv *p = dev_get_drvdata(dev);
        int rc, size;
 
+       /* Invalid eventcode */
+       if (event->attr.config == 0 || event->attr.config >= ARRAY_SIZE(nvdimm_events_map))
+               return -EINVAL;
+
        /* Allocate request buffer enough to hold single performance stat */
        size = sizeof(struct papr_scm_perf_stats) +
                sizeof(struct papr_scm_perf_stat);
 
-       if (!p || !p->nvdimm_events_map)
+       if (!p)
                return -EINVAL;
 
        stats = kzalloc(size, GFP_KERNEL);
@@ -370,7 +390,7 @@ static int papr_scm_pmu_get_value(struct perf_event *event, struct device *dev,
 
        stat = &stats->scm_statistic[0];
        memcpy(&stat->stat_id,
-              &p->nvdimm_events_map[event->attr.config * sizeof(stat->stat_id)],
+              nvdimm_events_map[event->attr.config],
                sizeof(stat->stat_id));
        stat->stat_val = 0;
 
@@ -458,56 +478,6 @@ static void papr_scm_pmu_del(struct perf_event *event, int flags)
        papr_scm_pmu_read(event);
 }
 
-static int papr_scm_pmu_check_events(struct papr_scm_priv *p, struct nvdimm_pmu *nd_pmu)
-{
-       struct papr_scm_perf_stat *stat;
-       struct papr_scm_perf_stats *stats;
-       u32 available_events;
-       int index, rc = 0;
-
-       if (!p->stat_buffer_len)
-               return -ENOENT;
-
-       available_events = (p->stat_buffer_len  - sizeof(struct papr_scm_perf_stats))
-                       / sizeof(struct papr_scm_perf_stat);
-       if (available_events == 0)
-               return -EOPNOTSUPP;
-
-       /* Allocate the buffer for phyp where stats are written */
-       stats = kzalloc(p->stat_buffer_len, GFP_KERNEL);
-       if (!stats) {
-               rc = -ENOMEM;
-               return rc;
-       }
-
-       /* Called to get list of events supported */
-       rc = drc_pmem_query_stats(p, stats, 0);
-       if (rc)
-               goto out;
-
-       /*
-        * Allocate memory and populate nvdimm_event_map.
-        * Allocate an extra element for NULL entry
-        */
-       p->nvdimm_events_map = kcalloc(available_events + 1,
-                                      sizeof(stat->stat_id),
-                                      GFP_KERNEL);
-       if (!p->nvdimm_events_map) {
-               rc = -ENOMEM;
-               goto out;
-       }
-
-       /* Copy all stat_ids to event map */
-       for (index = 0, stat = stats->scm_statistic;
-            index < available_events; index++, ++stat) {
-               memcpy(&p->nvdimm_events_map[index * sizeof(stat->stat_id)],
-                      &stat->stat_id, sizeof(stat->stat_id));
-       }
-out:
-       kfree(stats);
-       return rc;
-}
-
 static void papr_scm_pmu_register(struct papr_scm_priv *p)
 {
        struct nvdimm_pmu *nd_pmu;
@@ -519,9 +489,10 @@ static void papr_scm_pmu_register(struct papr_scm_priv *p)
                goto pmu_err_print;
        }
 
-       rc = papr_scm_pmu_check_events(p, nd_pmu);
-       if (rc)
+       if (!p->stat_buffer_len) {
+               rc = -ENOENT;
                goto pmu_check_events_err;
+       }
 
        nd_pmu->pmu.task_ctx_nr = perf_invalid_context;
        nd_pmu->pmu.name = nvdimm_name(p->nvdimm);
@@ -539,7 +510,7 @@ static void papr_scm_pmu_register(struct papr_scm_priv *p)
 
        rc = register_nvdimm_pmu(nd_pmu, p->pdev);
        if (rc)
-               goto pmu_register_err;
+               goto pmu_check_events_err;
 
        /*
         * Set archdata.priv value to nvdimm_pmu structure, to handle the
@@ -548,8 +519,6 @@ static void papr_scm_pmu_register(struct papr_scm_priv *p)
        p->pdev->archdata.priv = nd_pmu;
        return;
 
-pmu_register_err:
-       kfree(p->nvdimm_events_map);
 pmu_check_events_err:
        kfree(nd_pmu);
 pmu_err_print:
@@ -1560,7 +1529,6 @@ static int papr_scm_remove(struct platform_device *pdev)
                unregister_nvdimm_pmu(pdev->archdata.priv);
 
        pdev->archdata.priv = NULL;
-       kfree(p->nvdimm_events_map);
        kfree(p->bus_desc.provider_name);
        kfree(p);
 
index 52aaa28..f4b5b5a 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/string.h>
 #include <linux/types.h>
 #include <asm/hvcall.h>
+#include <asm/machdep.h>
 
 #include "plpks.h"
 
@@ -457,4 +458,4 @@ static __init int pseries_plpks_init(void)
 
        return rc;
 }
-arch_initcall(pseries_plpks_init);
+machine_arch_initcall(pseries, pseries_plpks_init);
index 044982a..f3f87ed 100644 (file)
 
        phy1: ethernet-phy@9 {
                reg = <9>;
-               ti,fifo-depth = <0x1>;
        };
 
        phy0: ethernet-phy@8 {
                reg = <8>;
-               ti,fifo-depth = <0x1>;
        };
 };
 
        disable-wp;
        cap-sd-highspeed;
        cap-mmc-highspeed;
-       card-detect-delay = <200>;
        mmc-ddr-1_8v;
        mmc-hs200-1_8v;
        sd-uhs-sdr12;
index 82c93c8..c87cc2d 100644 (file)
 
        phy1: ethernet-phy@5 {
                reg = <5>;
-               ti,fifo-depth = <0x01>;
        };
 
        phy0: ethernet-phy@4 {
                reg = <4>;
-               ti,fifo-depth = <0x01>;
        };
 };
 
@@ -72,7 +70,6 @@
        disable-wp;
        cap-sd-highspeed;
        cap-mmc-highspeed;
-       card-detect-delay = <200>;
        mmc-ddr-1_8v;
        mmc-hs200-1_8v;
        sd-uhs-sdr12;
index 499c2e6..6d9d455 100644 (file)
                ranges;
 
                cctrllr: cache-controller@2010000 {
-                       compatible = "sifive,fu540-c000-ccache", "cache";
+                       compatible = "microchip,mpfs-ccache", "sifive,fu540-c000-ccache", "cache";
                        reg = <0x0 0x2010000 0x0 0x1000>;
                        cache-block-size = <64>;
                        cache-level = <2>;
                        cache-size = <2097152>;
                        cache-unified;
                        interrupt-parent = <&plic>;
-                       interrupts = <1>, <2>, <3>;
+                       interrupts = <1>, <3>, <4>, <2>;
                };
 
                clint: clint@2000000 {
                        ranges = <0x3000000 0x0 0x8000000 0x20 0x8000000 0x0 0x80000000>;
                        msi-parent = <&pcie>;
                        msi-controller;
-                       microchip,axi-m-atr0 = <0x10 0x0>;
                        status = "disabled";
-                       pcie_intc: legacy-interrupt-controller {
+                       pcie_intc: interrupt-controller {
                                #address-cells = <0>;
                                #interrupt-cells = <1>;
                                interrupt-controller;
index 83d6d4d..26a446a 100644 (file)
@@ -33,4 +33,16 @@ void kvm_riscv_vcpu_sbi_system_reset(struct kvm_vcpu *vcpu,
                                     u32 type, u64 flags);
 const struct kvm_vcpu_sbi_extension *kvm_vcpu_sbi_find_ext(unsigned long extid);
 
+#ifdef CONFIG_RISCV_SBI_V01
+extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_v01;
+#endif
+extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_base;
+extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_time;
+extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_ipi;
+extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_rfence;
+extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_srst;
+extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_hsm;
+extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_experimental;
+extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_vendor;
+
 #endif /* __RISCV_KVM_VCPU_SBI_H__ */
diff --git a/arch/riscv/include/asm/signal.h b/arch/riscv/include/asm/signal.h
new file mode 100644 (file)
index 0000000..532c29e
--- /dev/null
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __ASM_SIGNAL_H
+#define __ASM_SIGNAL_H
+
+#include <uapi/asm/signal.h>
+#include <uapi/asm/ptrace.h>
+
+asmlinkage __visible
+void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags);
+
+#endif
index 78933ac..67322f8 100644 (file)
@@ -42,6 +42,8 @@
 
 #ifndef __ASSEMBLY__
 
+extern long shadow_stack[SHADOW_OVERFLOW_STACK_SIZE / sizeof(long)];
+
 #include <asm/processor.h>
 #include <asm/csr.h>
 
index 553d755..3b5583d 100644 (file)
@@ -28,7 +28,7 @@ unsigned long elf_hwcap __read_mostly;
 /* Host ISA bitmap */
 static DECLARE_BITMAP(riscv_isa, RISCV_ISA_EXT_MAX) __read_mostly;
 
-__ro_after_init DEFINE_STATIC_KEY_ARRAY_FALSE(riscv_isa_ext_keys, RISCV_ISA_EXT_KEY_MAX);
+DEFINE_STATIC_KEY_ARRAY_FALSE(riscv_isa_ext_keys, RISCV_ISA_EXT_KEY_MAX);
 EXPORT_SYMBOL(riscv_isa_ext_keys);
 
 /**
index 38b05ca..5a2de6b 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <asm/ucontext.h>
 #include <asm/vdso.h>
+#include <asm/signal.h>
 #include <asm/signal32.h>
 #include <asm/switch_to.h>
 #include <asm/csr.h>
index 39d0f8b..635e6ec 100644 (file)
 
 #include <asm/asm-prototypes.h>
 #include <asm/bug.h>
+#include <asm/csr.h>
 #include <asm/processor.h>
 #include <asm/ptrace.h>
-#include <asm/csr.h>
+#include <asm/thread_info.h>
 
 int show_unhandled_signals = 1;
 
index 3a35b2d..3620eca 100644 (file)
@@ -666,7 +666,7 @@ int kvm_riscv_gstage_map(struct kvm_vcpu *vcpu,
                return ret;
        }
 
-       mmu_seq = kvm->mmu_notifier_seq;
+       mmu_seq = kvm->mmu_invalidate_seq;
 
        hfn = gfn_to_pfn_prot(kvm, gfn, is_write, &writable);
        if (hfn == KVM_PFN_ERR_HWPOISON) {
@@ -686,7 +686,7 @@ int kvm_riscv_gstage_map(struct kvm_vcpu *vcpu,
 
        spin_lock(&kvm->mmu_lock);
 
-       if (mmu_notifier_retry(kvm, mmu_seq))
+       if (mmu_invalidate_retry(kvm, mmu_seq))
                goto out_unlock;
 
        if (writable) {
index d45e7da..f96991d 100644 (file)
@@ -32,23 +32,13 @@ static int kvm_linux_err_map_sbi(int err)
        };
 }
 
-#ifdef CONFIG_RISCV_SBI_V01
-extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_v01;
-#else
+#ifndef CONFIG_RISCV_SBI_V01
 static const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_v01 = {
        .extid_start = -1UL,
        .extid_end = -1UL,
        .handler = NULL,
 };
 #endif
-extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_base;
-extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_time;
-extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_ipi;
-extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_rfence;
-extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_srst;
-extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_hsm;
-extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_experimental;
-extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_vendor;
 
 static const struct kvm_vcpu_sbi_extension *sbi_ext[] = {
        &vcpu_sbi_ext_v01,
index 16f50c4..185f238 100644 (file)
@@ -299,7 +299,6 @@ static void kvm_riscv_vcpu_update_timedelta(struct kvm_vcpu *vcpu)
 
 void kvm_riscv_vcpu_timer_restore(struct kvm_vcpu *vcpu)
 {
-       struct kvm_vcpu_csr *csr;
        struct kvm_vcpu_timer *t = &vcpu->arch.timer;
 
        kvm_riscv_vcpu_update_timedelta(vcpu);
@@ -307,7 +306,6 @@ void kvm_riscv_vcpu_timer_restore(struct kvm_vcpu *vcpu)
        if (!t->sstc_enabled)
                return;
 
-       csr = &vcpu->arch.guest_csr;
 #if defined(CONFIG_32BIT)
        csr_write(CSR_VSTIMECMP, (u32)t->next_cycles);
        csr_write(CSR_VSTIMECMPH, (u32)(t->next_cycles >> 32));
@@ -324,13 +322,11 @@ void kvm_riscv_vcpu_timer_restore(struct kvm_vcpu *vcpu)
 
 void kvm_riscv_vcpu_timer_save(struct kvm_vcpu *vcpu)
 {
-       struct kvm_vcpu_csr *csr;
        struct kvm_vcpu_timer *t = &vcpu->arch.timer;
 
        if (!t->sstc_enabled)
                return;
 
-       csr = &vcpu->arch.guest_csr;
        t = &vcpu->arch.timer;
 #if defined(CONFIG_32BIT)
        t->next_cycles = csr_read(CSR_VSTIMECMP);
index 5e49e4b..86c5661 100644 (file)
@@ -118,10 +118,10 @@ static int __set_memory(unsigned long addr, int numpages, pgprot_t set_mask,
        if (!numpages)
                return 0;
 
-       mmap_read_lock(&init_mm);
+       mmap_write_lock(&init_mm);
        ret =  walk_page_range_novma(&init_mm, start, end, &pageattr_ops, NULL,
                                     &masks);
-       mmap_read_unlock(&init_mm);
+       mmap_write_unlock(&init_mm);
 
        flush_tlb_kernel_range(start, end);
 
index f6dfde5..2a82700 100644 (file)
@@ -40,8 +40,6 @@ CONFIG_CHECKPOINT_RESTORE=y
 CONFIG_SCHED_AUTOGROUP=y
 CONFIG_EXPERT=y
 # CONFIG_SYSFS_SYSCALL is not set
-CONFIG_USERFAULTFD=y
-# CONFIG_COMPAT_BRK is not set
 CONFIG_PROFILING=y
 CONFIG_LIVEPATCH=y
 CONFIG_MARCH_ZEC12=y
@@ -74,6 +72,7 @@ CONFIG_MODULES=y
 CONFIG_MODULE_FORCE_LOAD=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODULE_UNLOAD_TAINT_TRACKING=y
 CONFIG_MODVERSIONS=y
 CONFIG_MODULE_SRCVERSION_ALL=y
 CONFIG_MODULE_SIG_SHA256=y
@@ -93,6 +92,10 @@ CONFIG_UNIXWARE_DISKLABEL=y
 CONFIG_IOSCHED_BFQ=y
 CONFIG_BFQ_GROUP_IOSCHED=y
 CONFIG_BINFMT_MISC=m
+CONFIG_ZSWAP=y
+CONFIG_ZSMALLOC_STAT=y
+CONFIG_SLUB_STATS=y
+# CONFIG_COMPAT_BRK is not set
 CONFIG_MEMORY_HOTPLUG=y
 CONFIG_MEMORY_HOTREMOVE=y
 CONFIG_KSM=y
@@ -102,14 +105,12 @@ CONFIG_CMA_DEBUGFS=y
 CONFIG_CMA_SYSFS=y
 CONFIG_CMA_AREAS=7
 CONFIG_MEM_SOFT_DIRTY=y
-CONFIG_ZSWAP=y
-CONFIG_ZSMALLOC=y
-CONFIG_ZSMALLOC_STAT=y
 CONFIG_DEFERRED_STRUCT_PAGE_INIT=y
 CONFIG_IDLE_PAGE_TRACKING=y
 CONFIG_PERCPU_STATS=y
 CONFIG_GUP_TEST=y
 CONFIG_ANON_VMA_NAME=y
+CONFIG_USERFAULTFD=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_PACKET_DIAG=m
@@ -167,6 +168,7 @@ CONFIG_BRIDGE_NETFILTER=m
 CONFIG_NETFILTER_NETLINK_HOOK=m
 CONFIG_NF_CONNTRACK=m
 CONFIG_NF_CONNTRACK_SECMARK=y
+CONFIG_NF_CONNTRACK_PROCFS=y
 CONFIG_NF_CONNTRACK_EVENTS=y
 CONFIG_NF_CONNTRACK_TIMEOUT=y
 CONFIG_NF_CONNTRACK_TIMESTAMP=y
@@ -493,7 +495,6 @@ CONFIG_NLMON=m
 # CONFIG_NET_VENDOR_ASIX is not set
 # CONFIG_NET_VENDOR_ATHEROS is not set
 # CONFIG_NET_VENDOR_BROADCOM is not set
-# CONFIG_NET_VENDOR_BROCADE is not set
 # CONFIG_NET_VENDOR_CADENCE is not set
 # CONFIG_NET_VENDOR_CAVIUM is not set
 # CONFIG_NET_VENDOR_CHELSIO is not set
@@ -509,7 +510,7 @@ CONFIG_NLMON=m
 # CONFIG_NET_VENDOR_GOOGLE is not set
 # CONFIG_NET_VENDOR_HUAWEI is not set
 # CONFIG_NET_VENDOR_INTEL is not set
-# CONFIG_NET_VENDOR_MICROSOFT is not set
+# CONFIG_NET_VENDOR_WANGXUN is not set
 # CONFIG_NET_VENDOR_LITEX is not set
 # CONFIG_NET_VENDOR_MARVELL is not set
 CONFIG_MLX4_EN=m
@@ -518,16 +519,18 @@ CONFIG_MLX5_CORE_EN=y
 # CONFIG_NET_VENDOR_MICREL is not set
 # CONFIG_NET_VENDOR_MICROCHIP is not set
 # CONFIG_NET_VENDOR_MICROSEMI is not set
+# CONFIG_NET_VENDOR_MICROSOFT is not set
 # CONFIG_NET_VENDOR_MYRI is not set
+# CONFIG_NET_VENDOR_NI is not set
 # CONFIG_NET_VENDOR_NATSEMI is not set
 # CONFIG_NET_VENDOR_NETERION is not set
 # CONFIG_NET_VENDOR_NETRONOME is not set
-# CONFIG_NET_VENDOR_NI is not set
 # CONFIG_NET_VENDOR_NVIDIA is not set
 # CONFIG_NET_VENDOR_OKI is not set
 # CONFIG_NET_VENDOR_PACKET_ENGINES is not set
 # CONFIG_NET_VENDOR_PENSANDO is not set
 # CONFIG_NET_VENDOR_QLOGIC is not set
+# CONFIG_NET_VENDOR_BROCADE is not set
 # CONFIG_NET_VENDOR_QUALCOMM is not set
 # CONFIG_NET_VENDOR_RDC is not set
 # CONFIG_NET_VENDOR_REALTEK is not set
@@ -535,9 +538,9 @@ CONFIG_MLX5_CORE_EN=y
 # CONFIG_NET_VENDOR_ROCKER is not set
 # CONFIG_NET_VENDOR_SAMSUNG is not set
 # CONFIG_NET_VENDOR_SEEQ is not set
-# CONFIG_NET_VENDOR_SOLARFLARE is not set
 # CONFIG_NET_VENDOR_SILAN is not set
 # CONFIG_NET_VENDOR_SIS is not set
+# CONFIG_NET_VENDOR_SOLARFLARE is not set
 # CONFIG_NET_VENDOR_SMSC is not set
 # CONFIG_NET_VENDOR_SOCIONEXT is not set
 # CONFIG_NET_VENDOR_STMICRO is not set
@@ -570,6 +573,8 @@ CONFIG_VIRTIO_CONSOLE=m
 CONFIG_HW_RANDOM_VIRTIO=m
 CONFIG_HANGCHECK_TIMER=m
 CONFIG_TN3270_FS=y
+# CONFIG_RANDOM_TRUST_CPU is not set
+# CONFIG_RANDOM_TRUST_BOOTLOADER is not set
 CONFIG_PPS=m
 # CONFIG_PTP_1588_CLOCK is not set
 # CONFIG_HWMON is not set
@@ -727,18 +732,26 @@ CONFIG_CRYPTO_LRW=m
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_KEYWRAP=m
 CONFIG_CRYPTO_ADIANTUM=m
+CONFIG_CRYPTO_HCTR2=m
 CONFIG_CRYPTO_XCBC=m
 CONFIG_CRYPTO_VMAC=m
 CONFIG_CRYPTO_CRC32=m
-CONFIG_CRYPTO_BLAKE2S=m
+CONFIG_CRYPTO_CRC32_S390=y
 CONFIG_CRYPTO_MD4=m
 CONFIG_CRYPTO_MD5=y
 CONFIG_CRYPTO_MICHAEL_MIC=m
 CONFIG_CRYPTO_RMD160=m
+CONFIG_CRYPTO_SHA512_S390=m
+CONFIG_CRYPTO_SHA1_S390=m
+CONFIG_CRYPTO_SHA256_S390=m
 CONFIG_CRYPTO_SHA3=m
-CONFIG_CRYPTO_SM3=m
+CONFIG_CRYPTO_SHA3_256_S390=m
+CONFIG_CRYPTO_SHA3_512_S390=m
+CONFIG_CRYPTO_SM3_GENERIC=m
 CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_GHASH_S390=m
 CONFIG_CRYPTO_AES_TI=m
+CONFIG_CRYPTO_AES_S390=m
 CONFIG_CRYPTO_ANUBIS=m
 CONFIG_CRYPTO_ARC4=m
 CONFIG_CRYPTO_BLOWFISH=m
@@ -746,11 +759,14 @@ CONFIG_CRYPTO_CAMELLIA=m
 CONFIG_CRYPTO_CAST5=m
 CONFIG_CRYPTO_CAST6=m
 CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_DES_S390=m
 CONFIG_CRYPTO_FCRYPT=m
 CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_CHACHA_S390=m
 CONFIG_CRYPTO_SEED=m
+CONFIG_CRYPTO_ARIA=m
 CONFIG_CRYPTO_SERPENT=m
-CONFIG_CRYPTO_SM4=m
+CONFIG_CRYPTO_SM4_GENERIC=m
 CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_TWOFISH=m
 CONFIG_CRYPTO_842=m
@@ -766,16 +782,6 @@ CONFIG_CRYPTO_STATS=y
 CONFIG_ZCRYPT=m
 CONFIG_PKEY=m
 CONFIG_CRYPTO_PAES_S390=m
-CONFIG_CRYPTO_SHA1_S390=m
-CONFIG_CRYPTO_SHA256_S390=m
-CONFIG_CRYPTO_SHA512_S390=m
-CONFIG_CRYPTO_SHA3_256_S390=m
-CONFIG_CRYPTO_SHA3_512_S390=m
-CONFIG_CRYPTO_DES_S390=m
-CONFIG_CRYPTO_AES_S390=m
-CONFIG_CRYPTO_CHACHA_S390=m
-CONFIG_CRYPTO_GHASH_S390=m
-CONFIG_CRYPTO_CRC32_S390=y
 CONFIG_CRYPTO_DEV_VIRTIO=m
 CONFIG_CORDIC=m
 CONFIG_CRYPTO_LIB_CURVE25519=m
@@ -797,6 +803,7 @@ CONFIG_HEADERS_INSTALL=y
 CONFIG_DEBUG_SECTION_MISMATCH=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_PAGEALLOC=y
+CONFIG_SLUB_DEBUG_ON=y
 CONFIG_PAGE_OWNER=y
 CONFIG_DEBUG_RODATA_TEST=y
 CONFIG_DEBUG_WX=y
@@ -808,8 +815,6 @@ CONFIG_DEBUG_OBJECTS_TIMERS=y
 CONFIG_DEBUG_OBJECTS_WORK=y
 CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
 CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y
-CONFIG_SLUB_DEBUG_ON=y
-CONFIG_SLUB_STATS=y
 CONFIG_DEBUG_STACK_USAGE=y
 CONFIG_DEBUG_VM=y
 CONFIG_DEBUG_VM_PGFLAGS=y
index 706df3a..fb780e8 100644 (file)
@@ -38,8 +38,6 @@ CONFIG_CHECKPOINT_RESTORE=y
 CONFIG_SCHED_AUTOGROUP=y
 CONFIG_EXPERT=y
 # CONFIG_SYSFS_SYSCALL is not set
-CONFIG_USERFAULTFD=y
-# CONFIG_COMPAT_BRK is not set
 CONFIG_PROFILING=y
 CONFIG_LIVEPATCH=y
 CONFIG_MARCH_ZEC12=y
@@ -69,6 +67,7 @@ CONFIG_MODULES=y
 CONFIG_MODULE_FORCE_LOAD=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODULE_UNLOAD_TAINT_TRACKING=y
 CONFIG_MODVERSIONS=y
 CONFIG_MODULE_SRCVERSION_ALL=y
 CONFIG_MODULE_SIG_SHA256=y
@@ -88,6 +87,9 @@ CONFIG_UNIXWARE_DISKLABEL=y
 CONFIG_IOSCHED_BFQ=y
 CONFIG_BFQ_GROUP_IOSCHED=y
 CONFIG_BINFMT_MISC=m
+CONFIG_ZSWAP=y
+CONFIG_ZSMALLOC_STAT=y
+# CONFIG_COMPAT_BRK is not set
 CONFIG_MEMORY_HOTPLUG=y
 CONFIG_MEMORY_HOTREMOVE=y
 CONFIG_KSM=y
@@ -95,13 +97,11 @@ CONFIG_TRANSPARENT_HUGEPAGE=y
 CONFIG_CMA_SYSFS=y
 CONFIG_CMA_AREAS=7
 CONFIG_MEM_SOFT_DIRTY=y
-CONFIG_ZSWAP=y
-CONFIG_ZSMALLOC=y
-CONFIG_ZSMALLOC_STAT=y
 CONFIG_DEFERRED_STRUCT_PAGE_INIT=y
 CONFIG_IDLE_PAGE_TRACKING=y
 CONFIG_PERCPU_STATS=y
 CONFIG_ANON_VMA_NAME=y
+CONFIG_USERFAULTFD=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_PACKET_DIAG=m
@@ -159,6 +159,7 @@ CONFIG_BRIDGE_NETFILTER=m
 CONFIG_NETFILTER_NETLINK_HOOK=m
 CONFIG_NF_CONNTRACK=m
 CONFIG_NF_CONNTRACK_SECMARK=y
+CONFIG_NF_CONNTRACK_PROCFS=y
 CONFIG_NF_CONNTRACK_EVENTS=y
 CONFIG_NF_CONNTRACK_TIMEOUT=y
 CONFIG_NF_CONNTRACK_TIMESTAMP=y
@@ -484,7 +485,6 @@ CONFIG_NLMON=m
 # CONFIG_NET_VENDOR_ASIX is not set
 # CONFIG_NET_VENDOR_ATHEROS is not set
 # CONFIG_NET_VENDOR_BROADCOM is not set
-# CONFIG_NET_VENDOR_BROCADE is not set
 # CONFIG_NET_VENDOR_CADENCE is not set
 # CONFIG_NET_VENDOR_CAVIUM is not set
 # CONFIG_NET_VENDOR_CHELSIO is not set
@@ -500,7 +500,7 @@ CONFIG_NLMON=m
 # CONFIG_NET_VENDOR_GOOGLE is not set
 # CONFIG_NET_VENDOR_HUAWEI is not set
 # CONFIG_NET_VENDOR_INTEL is not set
-# CONFIG_NET_VENDOR_MICROSOFT is not set
+# CONFIG_NET_VENDOR_WANGXUN is not set
 # CONFIG_NET_VENDOR_LITEX is not set
 # CONFIG_NET_VENDOR_MARVELL is not set
 CONFIG_MLX4_EN=m
@@ -509,16 +509,18 @@ CONFIG_MLX5_CORE_EN=y
 # CONFIG_NET_VENDOR_MICREL is not set
 # CONFIG_NET_VENDOR_MICROCHIP is not set
 # CONFIG_NET_VENDOR_MICROSEMI is not set
+# CONFIG_NET_VENDOR_MICROSOFT is not set
 # CONFIG_NET_VENDOR_MYRI is not set
+# CONFIG_NET_VENDOR_NI is not set
 # CONFIG_NET_VENDOR_NATSEMI is not set
 # CONFIG_NET_VENDOR_NETERION is not set
 # CONFIG_NET_VENDOR_NETRONOME is not set
-# CONFIG_NET_VENDOR_NI is not set
 # CONFIG_NET_VENDOR_NVIDIA is not set
 # CONFIG_NET_VENDOR_OKI is not set
 # CONFIG_NET_VENDOR_PACKET_ENGINES is not set
 # CONFIG_NET_VENDOR_PENSANDO is not set
 # CONFIG_NET_VENDOR_QLOGIC is not set
+# CONFIG_NET_VENDOR_BROCADE is not set
 # CONFIG_NET_VENDOR_QUALCOMM is not set
 # CONFIG_NET_VENDOR_RDC is not set
 # CONFIG_NET_VENDOR_REALTEK is not set
@@ -526,9 +528,9 @@ CONFIG_MLX5_CORE_EN=y
 # CONFIG_NET_VENDOR_ROCKER is not set
 # CONFIG_NET_VENDOR_SAMSUNG is not set
 # CONFIG_NET_VENDOR_SEEQ is not set
-# CONFIG_NET_VENDOR_SOLARFLARE is not set
 # CONFIG_NET_VENDOR_SILAN is not set
 # CONFIG_NET_VENDOR_SIS is not set
+# CONFIG_NET_VENDOR_SOLARFLARE is not set
 # CONFIG_NET_VENDOR_SMSC is not set
 # CONFIG_NET_VENDOR_SOCIONEXT is not set
 # CONFIG_NET_VENDOR_STMICRO is not set
@@ -561,6 +563,8 @@ CONFIG_VIRTIO_CONSOLE=m
 CONFIG_HW_RANDOM_VIRTIO=m
 CONFIG_HANGCHECK_TIMER=m
 CONFIG_TN3270_FS=y
+# CONFIG_RANDOM_TRUST_CPU is not set
+# CONFIG_RANDOM_TRUST_BOOTLOADER is not set
 # CONFIG_PTP_1588_CLOCK is not set
 # CONFIG_HWMON is not set
 CONFIG_WATCHDOG=y
@@ -713,18 +717,26 @@ CONFIG_CRYPTO_OFB=m
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_KEYWRAP=m
 CONFIG_CRYPTO_ADIANTUM=m
+CONFIG_CRYPTO_HCTR2=m
 CONFIG_CRYPTO_XCBC=m
 CONFIG_CRYPTO_VMAC=m
 CONFIG_CRYPTO_CRC32=m
-CONFIG_CRYPTO_BLAKE2S=m
+CONFIG_CRYPTO_CRC32_S390=y
 CONFIG_CRYPTO_MD4=m
 CONFIG_CRYPTO_MD5=y
 CONFIG_CRYPTO_MICHAEL_MIC=m
 CONFIG_CRYPTO_RMD160=m
+CONFIG_CRYPTO_SHA512_S390=m
+CONFIG_CRYPTO_SHA1_S390=m
+CONFIG_CRYPTO_SHA256_S390=m
 CONFIG_CRYPTO_SHA3=m
-CONFIG_CRYPTO_SM3=m
+CONFIG_CRYPTO_SHA3_256_S390=m
+CONFIG_CRYPTO_SHA3_512_S390=m
+CONFIG_CRYPTO_SM3_GENERIC=m
 CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_GHASH_S390=m
 CONFIG_CRYPTO_AES_TI=m
+CONFIG_CRYPTO_AES_S390=m
 CONFIG_CRYPTO_ANUBIS=m
 CONFIG_CRYPTO_ARC4=m
 CONFIG_CRYPTO_BLOWFISH=m
@@ -732,11 +744,14 @@ CONFIG_CRYPTO_CAMELLIA=m
 CONFIG_CRYPTO_CAST5=m
 CONFIG_CRYPTO_CAST6=m
 CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_DES_S390=m
 CONFIG_CRYPTO_FCRYPT=m
 CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_CHACHA_S390=m
 CONFIG_CRYPTO_SEED=m
+CONFIG_CRYPTO_ARIA=m
 CONFIG_CRYPTO_SERPENT=m
-CONFIG_CRYPTO_SM4=m
+CONFIG_CRYPTO_SM4_GENERIC=m
 CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_TWOFISH=m
 CONFIG_CRYPTO_842=m
@@ -752,16 +767,6 @@ CONFIG_CRYPTO_STATS=y
 CONFIG_ZCRYPT=m
 CONFIG_PKEY=m
 CONFIG_CRYPTO_PAES_S390=m
-CONFIG_CRYPTO_SHA1_S390=m
-CONFIG_CRYPTO_SHA256_S390=m
-CONFIG_CRYPTO_SHA512_S390=m
-CONFIG_CRYPTO_SHA3_256_S390=m
-CONFIG_CRYPTO_SHA3_512_S390=m
-CONFIG_CRYPTO_DES_S390=m
-CONFIG_CRYPTO_AES_S390=m
-CONFIG_CRYPTO_CHACHA_S390=m
-CONFIG_CRYPTO_GHASH_S390=m
-CONFIG_CRYPTO_CRC32_S390=y
 CONFIG_CRYPTO_DEV_VIRTIO=m
 CONFIG_CORDIC=m
 CONFIG_PRIME_NUMBERS=m
index f4976f6..a5576b8 100644 (file)
@@ -1,4 +1,3 @@
-# CONFIG_SWAP is not set
 CONFIG_NO_HZ_IDLE=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_BPF_SYSCALL=y
@@ -9,7 +8,6 @@ CONFIG_BPF_SYSCALL=y
 # CONFIG_NET_NS is not set
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-# CONFIG_COMPAT_BRK is not set
 CONFIG_MARCH_ZEC12=y
 CONFIG_TUNE_ZEC12=y
 # CONFIG_COMPAT is not set
@@ -28,6 +26,8 @@ CONFIG_CRASH_DUMP=y
 # CONFIG_BLOCK_LEGACY_AUTOLOAD is not set
 CONFIG_PARTITION_ADVANCED=y
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_SWAP is not set
+# CONFIG_COMPAT_BRK is not set
 # CONFIG_COMPACTION is not set
 # CONFIG_MIGRATION is not set
 CONFIG_NET=y
@@ -53,10 +53,12 @@ CONFIG_ZFCP=y
 # CONFIG_HVC_IUCV is not set
 # CONFIG_HW_RANDOM_S390 is not set
 # CONFIG_HMC_DRV is not set
+# CONFIG_S390_UV_UAPI is not set
 # CONFIG_S390_TAPE is not set
 # CONFIG_VMCP is not set
 # CONFIG_MONWRITER is not set
 # CONFIG_S390_VMUR is not set
+# CONFIG_RANDOM_TRUST_BOOTLOADER is not set
 # CONFIG_HID is not set
 # CONFIG_VIRTIO_MENU is not set
 # CONFIG_VHOST_MENU is not set
index f0bc4dc..6511d15 100644 (file)
@@ -437,7 +437,7 @@ __init int hypfs_diag_init(void)
        int rc;
 
        if (diag204_probe()) {
-               pr_err("The hardware system does not support hypfs\n");
+               pr_info("The hardware system does not support hypfs\n");
                return -ENODATA;
        }
 
index 5c97f48..ee919bf 100644 (file)
@@ -496,9 +496,9 @@ fail_hypfs_sprp_exit:
        hypfs_vm_exit();
 fail_hypfs_diag_exit:
        hypfs_diag_exit();
+       pr_err("Initialization of hypfs failed with rc=%i\n", rc);
 fail_dbfs_exit:
        hypfs_dbfs_exit();
-       pr_err("Initialization of hypfs failed with rc=%i\n", rc);
        return rc;
 }
 device_initcall(hypfs_init)
index 9a7d15d..2de74fc 100644 (file)
@@ -176,14 +176,8 @@ arch___test_and_change_bit(unsigned long nr, volatile unsigned long *addr)
        return old & mask;
 }
 
-static __always_inline bool
-arch_test_bit(unsigned long nr, const volatile unsigned long *addr)
-{
-       const volatile unsigned long *p = __bitops_word(nr, addr);
-       unsigned long mask = __bitops_mask(nr);
-
-       return *p & mask;
-}
+#define arch_test_bit generic_test_bit
+#define arch_test_bit_acquire generic_test_bit_acquire
 
 static inline bool arch_test_and_set_bit_lock(unsigned long nr,
                                              volatile unsigned long *ptr)
index f22beda..ccdbccf 100644 (file)
@@ -28,9 +28,11 @@ pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
 static inline int prepare_hugepage_range(struct file *file,
                        unsigned long addr, unsigned long len)
 {
-       if (len & ~HPAGE_MASK)
+       struct hstate *h = hstate_file(file);
+
+       if (len & ~huge_page_mask(h))
                return -EINVAL;
-       if (addr & ~HPAGE_MASK)
+       if (addr & ~huge_page_mask(h))
                return -EINVAL;
        return 0;
 }
index f39092e..b1e98a9 100644 (file)
@@ -1038,16 +1038,11 @@ static inline void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu) {}
 #define __KVM_HAVE_ARCH_VM_FREE
 void kvm_arch_free_vm(struct kvm *kvm);
 
-#ifdef CONFIG_VFIO_PCI_ZDEV_KVM
-int kvm_s390_pci_register_kvm(struct zpci_dev *zdev, struct kvm *kvm);
-void kvm_s390_pci_unregister_kvm(struct zpci_dev *zdev);
-#else
-static inline int kvm_s390_pci_register_kvm(struct zpci_dev *dev,
-                                           struct kvm *kvm)
-{
-       return -EPERM;
-}
-static inline void kvm_s390_pci_unregister_kvm(struct zpci_dev *dev) {}
-#endif
+struct zpci_kvm_hook {
+       int (*kvm_register)(void *opaque, struct kvm *kvm);
+       void (*kvm_unregister)(void *opaque);
+};
+
+extern struct zpci_kvm_hook zpci_kvm_hook;
 
 #endif
index af68d6c..1ac5115 100644 (file)
@@ -5,7 +5,7 @@
 #include <asm/lowcore.h>
 #include <asm/stacktrace.h>
 
-#ifndef CONFIG_PREEMPT_RT
+#ifdef CONFIG_SOFTIRQ_ON_OWN_STACK
 static inline void do_softirq_own_stack(void)
 {
        call_on_stack(0, S390_lowcore.async_stack, void, __do_softirq);
index 60ac66a..31cb9b0 100644 (file)
@@ -64,7 +64,7 @@ static inline unsigned long nmi_get_mcesa_size(void)
  * structure. The structure is required for machine check happening
  * early in the boot process.
  */
-static struct mcesa boot_mcesa __initdata __aligned(MCESA_MAX_SIZE);
+static struct mcesa boot_mcesa __aligned(MCESA_MAX_SIZE);
 
 void __init nmi_alloc_mcesa_early(u64 *mcesad)
 {
index 89949b9..d5119e0 100644 (file)
@@ -91,6 +91,18 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 
        memcpy(dst, src, arch_task_struct_size);
        dst->thread.fpu.regs = dst->thread.fpu.fprs;
+
+       /*
+        * Don't transfer over the runtime instrumentation or the guarded
+        * storage control block pointers. These fields are cleared here instead
+        * of in copy_thread() to avoid premature freeing of associated memory
+        * on fork() failure. Wait to clear the RI flag because ->stack still
+        * refers to the source thread.
+        */
+       dst->thread.ri_cb = NULL;
+       dst->thread.gs_cb = NULL;
+       dst->thread.gs_bc_cb = NULL;
+
        return 0;
 }
 
@@ -150,13 +162,11 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
        frame->childregs.flags = 0;
        if (new_stackp)
                frame->childregs.gprs[15] = new_stackp;
-
-       /* Don't copy runtime instrumentation info */
-       p->thread.ri_cb = NULL;
+       /*
+        * Clear the runtime instrumentation flag after the above childregs
+        * copy. The CB pointer was already cleared in arch_dup_task_struct().
+        */
        frame->childregs.psw.mask &= ~PSW_MASK_RI;
-       /* Don't copy guarded storage control block */
-       p->thread.gs_cb = NULL;
-       p->thread.gs_bc_cb = NULL;
 
        /* Set a new TLS ?  */
        if (clone_flags & CLONE_SETTLS) {
index ed4fbbb..bbd4bde 100644 (file)
@@ -479,6 +479,7 @@ static void __init setup_lowcore_dat_off(void)
        put_abs_lowcore(restart_data, lc->restart_data);
        put_abs_lowcore(restart_source, lc->restart_source);
        put_abs_lowcore(restart_psw, lc->restart_psw);
+       put_abs_lowcore(mcesad, lc->mcesad);
 
        mcck_stack = (unsigned long)memblock_alloc(THREAD_SIZE, THREAD_SIZE);
        if (!mcck_stack)
@@ -507,8 +508,8 @@ static void __init setup_lowcore_dat_on(void)
        S390_lowcore.svc_new_psw.mask |= PSW_MASK_DAT;
        S390_lowcore.program_new_psw.mask |= PSW_MASK_DAT;
        S390_lowcore.io_new_psw.mask |= PSW_MASK_DAT;
-       __ctl_store(S390_lowcore.cregs_save_area, 0, 15);
        __ctl_set_bit(0, 28);
+       __ctl_store(S390_lowcore.cregs_save_area, 0, 15);
        put_abs_lowcore(restart_flags, RESTART_FLAG_CTLREGS);
        put_abs_lowcore(program_new_psw, lc->program_new_psw);
        for (cr = 0; cr < ARRAY_SIZE(lc->cregs_save_area); cr++)
index 2e526f1..5ea3830 100644 (file)
@@ -131,6 +131,7 @@ SECTIONS
        /*
         * Table with the patch locations to undo expolines
        */
+       . = ALIGN(4);
        .nospec_call_table : {
                __nospec_call_start = . ;
                *(.s390_indirect*)
index 4946fb7..bb8c335 100644 (file)
@@ -431,8 +431,9 @@ static void kvm_s390_pci_dev_release(struct zpci_dev *zdev)
  * available, enable them and let userspace indicate whether or not they will
  * be used (specify SHM bit to disable).
  */
-int kvm_s390_pci_register_kvm(struct zpci_dev *zdev, struct kvm *kvm)
+static int kvm_s390_pci_register_kvm(void *opaque, struct kvm *kvm)
 {
+       struct zpci_dev *zdev = opaque;
        int rc;
 
        if (!zdev)
@@ -510,10 +511,10 @@ err:
        kvm_put_kvm(kvm);
        return rc;
 }
-EXPORT_SYMBOL_GPL(kvm_s390_pci_register_kvm);
 
-void kvm_s390_pci_unregister_kvm(struct zpci_dev *zdev)
+static void kvm_s390_pci_unregister_kvm(void *opaque)
 {
+       struct zpci_dev *zdev = opaque;
        struct kvm *kvm;
 
        if (!zdev)
@@ -566,7 +567,6 @@ out:
 
        kvm_put_kvm(kvm);
 }
-EXPORT_SYMBOL_GPL(kvm_s390_pci_unregister_kvm);
 
 void kvm_s390_pci_init_list(struct kvm *kvm)
 {
@@ -678,6 +678,8 @@ int kvm_s390_pci_init(void)
 
        spin_lock_init(&aift->gait_lock);
        mutex_init(&aift->aift_lock);
+       zpci_kvm_hook.kvm_register = kvm_s390_pci_register_kvm;
+       zpci_kvm_hook.kvm_unregister = kvm_s390_pci_unregister_kvm;
 
        return 0;
 }
@@ -685,6 +687,8 @@ int kvm_s390_pci_init(void)
 void kvm_s390_pci_exit(void)
 {
        mutex_destroy(&aift->aift_lock);
+       zpci_kvm_hook.kvm_register = NULL;
+       zpci_kvm_hook.kvm_unregister = NULL;
 
        kfree(aift);
 }
index 1344994..9ab6ca6 100644 (file)
@@ -379,7 +379,9 @@ static inline vm_fault_t do_exception(struct pt_regs *regs, int access)
        flags = FAULT_FLAG_DEFAULT;
        if (user_mode(regs))
                flags |= FAULT_FLAG_USER;
-       if (access == VM_WRITE || is_write)
+       if (is_write)
+               access = VM_WRITE;
+       if (access == VM_WRITE)
                flags |= FAULT_FLAG_WRITE;
        mmap_read_lock(mm);
 
@@ -419,8 +421,6 @@ retry:
        if (unlikely(!(vma->vm_flags & access)))
                goto out_up;
 
-       if (is_vm_hugetlb_page(vma))
-               address &= HPAGE_MASK;
        /*
         * If for any reason at all we couldn't handle the fault,
         * make sure we exit gracefully rather than endlessly redo
index bf557a1..5ae31ca 100644 (file)
@@ -5,5 +5,5 @@
 
 obj-$(CONFIG_PCI)      += pci.o pci_irq.o pci_dma.o pci_clp.o pci_sysfs.o \
                           pci_event.o pci_debug.o pci_insn.o pci_mmio.o \
-                          pci_bus.o
+                          pci_bus.o pci_kvm_hook.o
 obj-$(CONFIG_PCI_IOV)  += pci_iov.o
diff --git a/arch/s390/pci/pci_kvm_hook.c b/arch/s390/pci/pci_kvm_hook.c
new file mode 100644 (file)
index 0000000..ff34baf
--- /dev/null
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * VFIO ZPCI devices support
+ *
+ * Copyright (C) IBM Corp. 2022.  All rights reserved.
+ *     Author(s): Pierre Morel <pmorel@linux.ibm.com>
+ */
+#include <linux/kvm_host.h>
+
+struct zpci_kvm_hook zpci_kvm_hook;
+EXPORT_SYMBOL_GPL(zpci_kvm_hook);
index 565a85d..5ace89b 100644 (file)
@@ -135,16 +135,8 @@ arch___test_and_change_bit(unsigned long nr, volatile unsigned long *addr)
        return (old & mask) != 0;
 }
 
-/**
- * arch_test_bit - Determine whether a bit is set
- * @nr: bit number to test
- * @addr: Address to start counting from
- */
-static __always_inline bool
-arch_test_bit(unsigned long nr, const volatile unsigned long *addr)
-{
-       return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1)));
-}
+#define arch_test_bit generic_test_bit
+#define arch_test_bit_acquire generic_test_bit_acquire
 
 #include <asm-generic/bitops/non-instrumented-non-atomic.h>
 
index 9092767..4e6835d 100644 (file)
@@ -149,7 +149,7 @@ void irq_ctx_exit(int cpu)
        hardirq_ctx[cpu] = NULL;
 }
 
-#ifndef CONFIG_PREEMPT_RT
+#ifdef CONFIG_SOFTIRQ_ON_OWN_STACK
 void do_softirq_own_stack(void)
 {
        struct thread_info *curctx;
index 41fa1be..72da2e1 100644 (file)
@@ -855,7 +855,7 @@ void __irq_entry handler_irq(int pil, struct pt_regs *regs)
        set_irq_regs(old_regs);
 }
 
-#ifndef CONFIG_PREEMPT_RT
+#ifdef CONFIG_SOFTIRQ_ON_OWN_STACK
 void do_softirq_own_stack(void)
 {
        void *orig_sp, *sp = softirq_stack[smp_processor_id()];
index f2fe63b..f1d4d67 100644 (file)
@@ -132,10 +132,18 @@ export LDS_ELF_FORMAT := $(ELF_FORMAT)
 # The wrappers will select whether using "malloc" or the kernel allocator.
 LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc
 
+# Avoid binutils 2.39+ warnings by marking the stack non-executable and
+# ignorning warnings for the kallsyms sections.
+LDFLAGS_EXECSTACK = -z noexecstack
+ifeq ($(CONFIG_LD_IS_BFD),y)
+LDFLAGS_EXECSTACK += $(call ld-option,--no-warn-rwx-segments)
+endif
+
 LD_FLAGS_CMDLINE = $(foreach opt,$(KBUILD_LDFLAGS),-Wl,$(opt))
 
 # Used by link-vmlinux.sh which has special support for um link
 export CFLAGS_vmlinux := $(LINK-y) $(LINK_WRAPS) $(LD_FLAGS_CMDLINE)
+export LDFLAGS_vmlinux := $(LDFLAGS_EXECSTACK)
 
 # When cleaning we don't include .config, so we don't include
 # TT or skas makefiles and don't clean skas_ptregs.h.
index 79e38af..e719af8 100644 (file)
@@ -1011,7 +1011,7 @@ error_kzalloc:
 
 static int vu_find_vqs(struct virtio_device *vdev, unsigned nvqs,
                       struct virtqueue *vqs[], vq_callback_t *callbacks[],
-                      const char * const names[], u32 sizes[], const bool *ctx,
+                      const char * const names[], const bool *ctx,
                       struct irq_affinity *desc)
 {
        struct virtio_uml_device *vu_dev = to_virtio_uml_device(vdev);
index 19cd7ed..4b6d1b5 100644 (file)
@@ -65,20 +65,6 @@ extern void setup_clear_cpu_cap(unsigned int bit);
 
 #define setup_force_cpu_bug(bit) setup_force_cpu_cap(bit)
 
-#if defined(__clang__) && !defined(CONFIG_CC_HAS_ASM_GOTO)
-
-/*
- * Workaround for the sake of BPF compilation which utilizes kernel
- * headers, but clang does not support ASM GOTO and fails the build.
- */
-#ifndef __BPF_TRACING__
-#warning "Compiler lacks ASM_GOTO support. Add -D __BPF_TRACING__ to your compiler arguments"
-#endif
-
-#define static_cpu_has(bit)            boot_cpu_has(bit)
-
-#else
-
 /*
  * Static testing of CPU features. Used the same as boot_cpu_has(). It
  * statically patches the target code for additional performance. Use
@@ -137,7 +123,6 @@ t_no:
                boot_cpu_has(bit) :                             \
                _static_cpu_has(bit)                            \
 )
-#endif
 
 #define cpu_has_bug(c, bit)            cpu_has(c, (bit))
 #define set_cpu_bug(c, bit)            set_cpu_cap(c, (bit))
index 7452f70..7467153 100644 (file)
@@ -48,7 +48,8 @@ void show_stack(struct task_struct *task, unsigned long *stack,
                        break;
                if (i && ((i % STACKSLOTS_PER_LINE) == 0))
                        pr_cont("\n");
-               pr_cont(" %08lx", *stack++);
+               pr_cont(" %08lx", READ_ONCE_NOCHECK(*stack));
+               stack++;
        }
 
        printk("%sCall Trace:\n", loglvl);
index e0de60e..d9e023c 100644 (file)
@@ -33,7 +33,7 @@
 #include "um_arch.h"
 
 #define DEFAULT_COMMAND_LINE_ROOT "root=98:0"
-#define DEFAULT_COMMAND_LINE_CONSOLE "console=tty"
+#define DEFAULT_COMMAND_LINE_CONSOLE "console=tty0"
 
 /* Changed in add_arg and setup_arch, which run before SMP is started */
 static char __initdata command_line[COMMAND_LINE_SIZE] = { 0 };
index 7854685..bafbd90 100644 (file)
@@ -286,10 +286,6 @@ vdso_install:
 
 archprepare: checkbin
 checkbin:
-ifndef CONFIG_CC_HAS_ASM_GOTO
-       @echo Compiler lacks asm-goto support.
-       @exit 1
-endif
 ifdef CONFIG_RETPOLINE
 ifeq ($(RETPOLINE_CFLAGS),)
        @echo "You are building kernel with non-retpoline compiler." >&2
index 4910bf2..62208ec 100644 (file)
@@ -132,7 +132,17 @@ void snp_set_page_private(unsigned long paddr);
 void snp_set_page_shared(unsigned long paddr);
 void sev_prep_identity_maps(unsigned long top_level_pgt);
 #else
-static inline void sev_enable(struct boot_params *bp) { }
+static inline void sev_enable(struct boot_params *bp)
+{
+       /*
+        * bp->cc_blob_address should only be set by boot/compressed kernel.
+        * Initialize it to 0 unconditionally (thus here in this stub too) to
+        * ensure that uninitialized values from buggy bootloaders aren't
+        * propagated.
+        */
+       if (bp)
+               bp->cc_blob_address = 0;
+}
 static inline void sev_es_shutdown_ghcb(void) { }
 static inline bool sev_es_check_ghcb_fault(unsigned long address)
 {
index 52f989f..c93930d 100644 (file)
@@ -277,6 +277,14 @@ void sev_enable(struct boot_params *bp)
        bool snp;
 
        /*
+        * bp->cc_blob_address should only be set by boot/compressed kernel.
+        * Initialize it to 0 to ensure that uninitialized values from
+        * buggy bootloaders aren't propagated.
+        */
+       if (bp)
+               bp->cc_blob_address = 0;
+
+       /*
         * Setup/preliminary detection of SNP. This will be sanity-checked
         * against CPUID/MSR values later.
         */
index d9fc713..5812962 100644 (file)
@@ -14,7 +14,6 @@ CONFIG_CPU_FREQ=y
 
 # x86 xen specific config options
 CONFIG_XEN_PVH=y
-CONFIG_XEN_MAX_DOMAIN_MEMORY=500
 CONFIG_XEN_SAVE_RESTORE=y
 # CONFIG_XEN_DEBUG_FS is not set
 CONFIG_XEN_MCE_LOG=y
index 682338e..4dd1981 100644 (file)
@@ -311,7 +311,7 @@ SYM_CODE_START(entry_INT80_compat)
         * Interrupts are off on entry.
         */
        ASM_CLAC                        /* Do this early to minimize exposure */
-       SWAPGS
+       ALTERNATIVE "swapgs", "", X86_FEATURE_XENPV
 
        /*
         * User tracing code (ptrace or signal handlers) might assume that
index 2db9349..c601939 100644 (file)
@@ -4052,8 +4052,9 @@ static struct perf_guest_switch_msr *intel_guest_get_msrs(int *nr, void *data)
                /* Disable guest PEBS if host PEBS is enabled. */
                arr[pebs_enable].guest = 0;
        } else {
-               /* Disable guest PEBS for cross-mapped PEBS counters. */
+               /* Disable guest PEBS thoroughly for cross-mapped PEBS counters. */
                arr[pebs_enable].guest &= ~kvm_pmu->host_cross_mapped_mask;
+               arr[global_ctrl].guest &= ~kvm_pmu->host_cross_mapped_mask;
                /* Set hw GLOBAL_CTRL bits for PEBS counter when it runs for guest */
                arr[global_ctrl].guest |= arr[pebs_enable].guest;
        }
@@ -6291,10 +6292,8 @@ __init int intel_pmu_init(void)
                x86_pmu.pebs_aliases = NULL;
                x86_pmu.pebs_prec_dist = true;
                x86_pmu.pebs_block = true;
-               x86_pmu.pebs_capable = ~0ULL;
                x86_pmu.flags |= PMU_FL_HAS_RSP_1;
                x86_pmu.flags |= PMU_FL_NO_HT_SHARING;
-               x86_pmu.flags |= PMU_FL_PEBS_ALL;
                x86_pmu.flags |= PMU_FL_INSTR_LATENCY;
                x86_pmu.flags |= PMU_FL_MEM_LOADS_AUX;
 
@@ -6337,10 +6336,8 @@ __init int intel_pmu_init(void)
                x86_pmu.pebs_aliases = NULL;
                x86_pmu.pebs_prec_dist = true;
                x86_pmu.pebs_block = true;
-               x86_pmu.pebs_capable = ~0ULL;
                x86_pmu.flags |= PMU_FL_HAS_RSP_1;
                x86_pmu.flags |= PMU_FL_NO_HT_SHARING;
-               x86_pmu.flags |= PMU_FL_PEBS_ALL;
                x86_pmu.flags |= PMU_FL_INSTR_LATENCY;
                x86_pmu.flags |= PMU_FL_MEM_LOADS_AUX;
                x86_pmu.lbr_pt_coexist = true;
index ba60427..de1f55d 100644 (file)
@@ -291,6 +291,7 @@ static u64 load_latency_data(struct perf_event *event, u64 status)
 static u64 store_latency_data(struct perf_event *event, u64 status)
 {
        union intel_x86_pebs_dse dse;
+       union perf_mem_data_src src;
        u64 val;
 
        dse.val = status;
@@ -304,7 +305,14 @@ static u64 store_latency_data(struct perf_event *event, u64 status)
 
        val |= P(BLK, NA);
 
-       return val;
+       /*
+        * the pebs_data_source table is only for loads
+        * so override the mem_op to say STORE instead
+        */
+       src.val = val;
+       src.mem_op = P(OP,STORE);
+
+       return src.val;
 }
 
 struct pebs_record_core {
@@ -822,7 +830,7 @@ struct event_constraint intel_glm_pebs_event_constraints[] = {
 
 struct event_constraint intel_grt_pebs_event_constraints[] = {
        /* Allow all events as PEBS with no flags */
-       INTEL_HYBRID_LAT_CONSTRAINT(0x5d0, 0xf),
+       INTEL_HYBRID_LAT_CONSTRAINT(0x5d0, 0x3),
        INTEL_HYBRID_LAT_CONSTRAINT(0x6d0, 0xf),
        EVENT_CONSTRAINT_END
 };
@@ -2262,6 +2270,7 @@ void __init intel_ds_init(void)
                                        PERF_SAMPLE_BRANCH_STACK |
                                        PERF_SAMPLE_TIME;
                                x86_pmu.flags |= PMU_FL_PEBS_ALL;
+                               x86_pmu.pebs_capable = ~0ULL;
                                pebs_qual = "-baseline";
                                x86_get_pmu(smp_processor_id())->capabilities |= PERF_PMU_CAP_EXTENDED_REGS;
                        } else {
index 4f70fb6..47fca6a 100644 (file)
@@ -1097,6 +1097,14 @@ static int intel_pmu_setup_hw_lbr_filter(struct perf_event *event)
 
        if (static_cpu_has(X86_FEATURE_ARCH_LBR)) {
                reg->config = mask;
+
+               /*
+                * The Arch LBR HW can retrieve the common branch types
+                * from the LBR_INFO. It doesn't require the high overhead
+                * SW disassemble.
+                * Enable the branch type by default for the Arch LBR.
+                */
+               reg->reg |= X86_BR_TYPE_SAVE;
                return 0;
        }
 
index ce44001..1ef4f78 100644 (file)
@@ -841,6 +841,22 @@ int snb_pci2phy_map_init(int devid)
        return 0;
 }
 
+static u64 snb_uncore_imc_read_counter(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+
+       /*
+        * SNB IMC counters are 32-bit and are laid out back to back
+        * in MMIO space. Therefore we must use a 32-bit accessor function
+        * using readq() from uncore_mmio_read_counter() causes problems
+        * because it is reading 64-bit at a time. This is okay for the
+        * uncore_perf_event_update() function because it drops the upper
+        * 32-bits but not okay for plain uncore_read_counter() as invoked
+        * in uncore_pmu_event_start().
+        */
+       return (u64)readl(box->io_addr + hwc->event_base);
+}
+
 static struct pmu snb_uncore_imc_pmu = {
        .task_ctx_nr    = perf_invalid_context,
        .event_init     = snb_uncore_imc_event_init,
@@ -860,7 +876,7 @@ static struct intel_uncore_ops snb_uncore_imc_ops = {
        .disable_event  = snb_uncore_imc_disable_event,
        .enable_event   = snb_uncore_imc_enable_event,
        .hw_config      = snb_uncore_imc_hw_config,
-       .read_counter   = uncore_mmio_read_counter,
+       .read_counter   = snb_uncore_imc_read_counter,
 };
 
 static struct intel_uncore_type snb_uncore_imc = {
index 973c6bd..0fe9de5 100644 (file)
@@ -207,6 +207,20 @@ static __always_inline bool constant_test_bit(long nr, const volatile unsigned l
                (addr[nr >> _BITOPS_LONG_SHIFT])) != 0;
 }
 
+static __always_inline bool constant_test_bit_acquire(long nr, const volatile unsigned long *addr)
+{
+       bool oldbit;
+
+       asm volatile("testb %2,%1"
+                    CC_SET(nz)
+                    : CC_OUT(nz) (oldbit)
+                    : "m" (((unsigned char *)addr)[nr >> 3]),
+                      "i" (1 << (nr & 7))
+                    :"memory");
+
+       return oldbit;
+}
+
 static __always_inline bool variable_test_bit(long nr, volatile const unsigned long *addr)
 {
        bool oldbit;
@@ -226,6 +240,13 @@ arch_test_bit(unsigned long nr, const volatile unsigned long *addr)
                                          variable_test_bit(nr, addr);
 }
 
+static __always_inline bool
+arch_test_bit_acquire(unsigned long nr, const volatile unsigned long *addr)
+{
+       return __builtin_constant_p(nr) ? constant_test_bit_acquire(nr, addr) :
+                                         variable_test_bit(nr, addr);
+}
+
 /**
  * __ffs - find first set bit in word
  * @word: The word to search
index ea34cc3..1a85e1f 100644 (file)
@@ -155,20 +155,6 @@ extern void clear_cpu_cap(struct cpuinfo_x86 *c, unsigned int bit);
 
 #define setup_force_cpu_bug(bit) setup_force_cpu_cap(bit)
 
-#if defined(__clang__) && !defined(CONFIG_CC_HAS_ASM_GOTO)
-
-/*
- * Workaround for the sake of BPF compilation which utilizes kernel
- * headers, but clang does not support ASM GOTO and fails the build.
- */
-#ifndef __BPF_TRACING__
-#warning "Compiler lacks ASM_GOTO support. Add -D __BPF_TRACING__ to your compiler arguments"
-#endif
-
-#define static_cpu_has(bit)            boot_cpu_has(bit)
-
-#else
-
 /*
  * Static testing of CPU features. Used the same as boot_cpu_has(). It
  * statically patches the target code for additional performance. Use
@@ -208,7 +194,6 @@ t_no:
                boot_cpu_has(bit) :                             \
                _static_cpu_has(bit)                            \
 )
-#endif
 
 #define cpu_has_bug(c, bit)            cpu_has(c, (bit))
 #define set_cpu_bug(c, bit)            set_cpu_cap(c, (bit))
index 235dc85..ef4775c 100644 (file)
 #define X86_BUG_ITLB_MULTIHIT          X86_BUG(23) /* CPU may incur MCE during certain page attribute changes */
 #define X86_BUG_SRBDS                  X86_BUG(24) /* CPU may leak RNG bits if not mitigated */
 #define X86_BUG_MMIO_STALE_DATA                X86_BUG(25) /* CPU is affected by Processor MMIO Stale Data vulnerabilities */
-#define X86_BUG_RETBLEED               X86_BUG(26) /* CPU is affected by RETBleed */
-#define X86_BUG_EIBRS_PBRSB            X86_BUG(27) /* EIBRS is vulnerable to Post Barrier RSB Predictions */
+#define X86_BUG_MMIO_UNKNOWN           X86_BUG(26) /* CPU is too old and its MMIO Stale Data status is unknown */
+#define X86_BUG_RETBLEED               X86_BUG(27) /* CPU is affected by RETBleed */
+#define X86_BUG_EIBRS_PBRSB            X86_BUG(28) /* EIBRS is vulnerable to Post Barrier RSB Predictions */
 
 #endif /* _ASM_X86_CPUFEATURES_H */
index 5036226..991e31c 100644 (file)
@@ -64,4 +64,6 @@
 #define        EX_TYPE_UCOPY_LEN4              (EX_TYPE_UCOPY_LEN | EX_DATA_IMM(4))
 #define        EX_TYPE_UCOPY_LEN8              (EX_TYPE_UCOPY_LEN | EX_DATA_IMM(8))
 
+#define EX_TYPE_ZEROPAD                        20 /* longword load with zeropad on fault */
+
 #endif
index 689880e..9b08082 100644 (file)
 
 #define __noendbr      __attribute__((nocf_check))
 
+/*
+ * Create a dummy function pointer reference to prevent objtool from marking
+ * the function as needing to be "sealed" (i.e. ENDBR converted to NOP by
+ * apply_ibt_endbr()).
+ */
+#define IBT_NOSEAL(fname)                              \
+       ".pushsection .discard.ibt_endbr_noseal\n\t"    \
+       _ASM_PTR fname "\n\t"                           \
+       ".popsection\n\t"
+
 static inline __attribute_const__ u32 gen_endbr(void)
 {
        u32 endbr;
@@ -84,6 +94,7 @@ extern __noendbr void ibt_restore(u64 save);
 #ifndef __ASSEMBLY__
 
 #define ASM_ENDBR
+#define IBT_NOSEAL(name)
 
 #define __noendbr
 
index def6ca1..aeb3802 100644 (file)
@@ -27,6 +27,7 @@
  *             _X      - regular server parts
  *             _D      - micro server parts
  *             _N,_P   - other mobile parts
+ *             _S      - other client parts
  *
  *             Historical OPTDIFFs:
  *
 
 #define INTEL_FAM6_RAPTORLAKE          0xB7
 #define INTEL_FAM6_RAPTORLAKE_P                0xBA
+#define INTEL_FAM6_RAPTORLAKE_S                0xBF
 
 /* "Small Core" Processors (Atom) */
 
index 63f818a..147cb8f 100644 (file)
                              IRQ_CONSTRAINTS, regs, vector);           \
 }
 
-#ifndef CONFIG_PREEMPT_RT
+#ifdef CONFIG_SOFTIRQ_ON_OWN_STACK
 /*
  * Macro to invoke __do_softirq on the irq stack. This is only called from
  * task context when bottom halves are about to be reenabled and soft
index 5ffa578..2c96c43 100644 (file)
@@ -53,7 +53,7 @@
 #define KVM_MAX_VCPU_IDS (KVM_MAX_VCPUS * KVM_VCPU_ID_RATIO)
 
 /* memory slots that are not exposed to userspace */
-#define KVM_PRIVATE_MEM_SLOTS 3
+#define KVM_INTERNAL_MEM_SLOTS 3
 
 #define KVM_HALT_POLL_NS_DEFAULT 200000
 
index e64fd20..c936ce9 100644 (file)
 #define RSB_CLEAR_LOOPS                32      /* To forcibly overwrite all entries */
 
 /*
+ * Common helper for __FILL_RETURN_BUFFER and __FILL_ONE_RETURN.
+ */
+#define __FILL_RETURN_SLOT                     \
+       ANNOTATE_INTRA_FUNCTION_CALL;           \
+       call    772f;                           \
+       int3;                                   \
+772:
+
+/*
+ * Stuff the entire RSB.
+ *
  * Google experimented with loop-unrolling and this turned out to be
  * the optimal version - two calls, each with their own speculation
  * trap should their return address end up getting used, in a loop.
  */
-#define __FILL_RETURN_BUFFER(reg, nr, sp)      \
-       mov     $(nr/2), reg;                   \
-771:                                           \
-       ANNOTATE_INTRA_FUNCTION_CALL;           \
-       call    772f;                           \
-773:   /* speculation trap */                  \
-       UNWIND_HINT_EMPTY;                      \
-       pause;                                  \
-       lfence;                                 \
-       jmp     773b;                           \
-772:                                           \
-       ANNOTATE_INTRA_FUNCTION_CALL;           \
-       call    774f;                           \
-775:   /* speculation trap */                  \
-       UNWIND_HINT_EMPTY;                      \
-       pause;                                  \
-       lfence;                                 \
-       jmp     775b;                           \
-774:                                           \
-       add     $(BITS_PER_LONG/8) * 2, sp;     \
-       dec     reg;                            \
-       jnz     771b;                           \
-       /* barrier for jnz misprediction */     \
+#ifdef CONFIG_X86_64
+#define __FILL_RETURN_BUFFER(reg, nr)                  \
+       mov     $(nr/2), reg;                           \
+771:                                                   \
+       __FILL_RETURN_SLOT                              \
+       __FILL_RETURN_SLOT                              \
+       add     $(BITS_PER_LONG/8) * 2, %_ASM_SP;       \
+       dec     reg;                                    \
+       jnz     771b;                                   \
+       /* barrier for jnz misprediction */             \
+       lfence;
+#else
+/*
+ * i386 doesn't unconditionally have LFENCE, as such it can't
+ * do a loop.
+ */
+#define __FILL_RETURN_BUFFER(reg, nr)                  \
+       .rept nr;                                       \
+       __FILL_RETURN_SLOT;                             \
+       .endr;                                          \
+       add     $(BITS_PER_LONG/8) * nr, %_ASM_SP;
+#endif
+
+/*
+ * Stuff a single RSB slot.
+ *
+ * To mitigate Post-Barrier RSB speculation, one CALL instruction must be
+ * forced to retire before letting a RET instruction execute.
+ *
+ * On PBRSB-vulnerable CPUs, it is not safe for a RET to be executed
+ * before this point.
+ */
+#define __FILL_ONE_RETURN                              \
+       __FILL_RETURN_SLOT                              \
+       add     $(BITS_PER_LONG/8), %_ASM_SP;           \
        lfence;
 
 #ifdef __ASSEMBLY__
 #endif
 .endm
 
-.macro ISSUE_UNBALANCED_RET_GUARD
-       ANNOTATE_INTRA_FUNCTION_CALL
-       call .Lunbalanced_ret_guard_\@
-       int3
-.Lunbalanced_ret_guard_\@:
-       add $(BITS_PER_LONG/8), %_ASM_SP
-       lfence
-.endm
-
  /*
   * A simpler FILL_RETURN_BUFFER macro. Don't make people use the CPP
   * monstrosity above, manually.
   */
-.macro FILL_RETURN_BUFFER reg:req nr:req ftr:req ftr2
-.ifb \ftr2
-       ALTERNATIVE "jmp .Lskip_rsb_\@", "", \ftr
-.else
-       ALTERNATIVE_2 "jmp .Lskip_rsb_\@", "", \ftr, "jmp .Lunbalanced_\@", \ftr2
-.endif
-       __FILL_RETURN_BUFFER(\reg,\nr,%_ASM_SP)
-.Lunbalanced_\@:
-       ISSUE_UNBALANCED_RET_GUARD
+.macro FILL_RETURN_BUFFER reg:req nr:req ftr:req ftr2=ALT_NOT(X86_FEATURE_ALWAYS)
+       ALTERNATIVE_2 "jmp .Lskip_rsb_\@", \
+               __stringify(__FILL_RETURN_BUFFER(\reg,\nr)), \ftr, \
+               __stringify(__FILL_ONE_RETURN), \ftr2
+
 .Lskip_rsb_\@:
 .endm
 
index 8a9eba1..7fa6112 100644 (file)
@@ -11,7 +11,7 @@
 
 #define __CLOBBERS_MEM(clb...) "memory", ## clb
 
-#if !defined(__GCC_ASM_FLAG_OUTPUTS__) && defined(CONFIG_CC_HAS_ASM_GOTO)
+#ifndef __GCC_ASM_FLAG_OUTPUTS__
 
 /* Use asm goto */
 
@@ -27,7 +27,7 @@ cc_label:     c = true;                                               \
        c;                                                              \
 })
 
-#else /* defined(__GCC_ASM_FLAG_OUTPUTS__) || !defined(CONFIG_CC_HAS_ASM_GOTO) */
+#else /* defined(__GCC_ASM_FLAG_OUTPUTS__) */
 
 /* Use flags output or a set instruction */
 
@@ -40,7 +40,7 @@ cc_label:     c = true;                                               \
        c;                                                              \
 })
 
-#endif /* defined(__GCC_ASM_FLAG_OUTPUTS__) || !defined(CONFIG_CC_HAS_ASM_GOTO) */
+#endif /* defined(__GCC_ASM_FLAG_OUTPUTS__) */
 
 #define GEN_UNARY_RMWcc_4(op, var, cc, arg0)                           \
        __GEN_RMWcc(op " " arg0, var, cc, __CLOBBERS_MEM())
index 4a23e52..ebc271b 100644 (file)
@@ -195,7 +195,7 @@ void snp_set_memory_shared(unsigned long vaddr, unsigned int npages);
 void snp_set_memory_private(unsigned long vaddr, unsigned int npages);
 void snp_set_wakeup_secondary_cpu(void);
 bool snp_init(struct boot_params *bp);
-void snp_abort(void);
+void __init __noreturn snp_abort(void);
 int snp_issue_guest_request(u64 exit_code, struct snp_req_data *input, unsigned long *fw_err);
 #else
 static inline void sev_es_ist_enter(struct pt_regs *regs) { }
index 8338b04..46b4f1f 100644 (file)
@@ -77,58 +77,18 @@ static inline unsigned long find_zero(unsigned long mask)
  * and the next page not being mapped, take the exception and
  * return zeroes in the non-existing part.
  */
-#ifdef CONFIG_CC_HAS_ASM_GOTO_OUTPUT
-
 static inline unsigned long load_unaligned_zeropad(const void *addr)
 {
-       unsigned long offset, data;
        unsigned long ret;
 
-       asm_volatile_goto(
+       asm volatile(
                "1:     mov %[mem], %[ret]\n"
-
-               _ASM_EXTABLE(1b, %l[do_exception])
-
-               : [ret] "=r" (ret)
-               : [mem] "m" (*(unsigned long *)addr)
-               : : do_exception);
-
-       return ret;
-
-do_exception:
-       offset = (unsigned long)addr & (sizeof(long) - 1);
-       addr = (void *)((unsigned long)addr & ~(sizeof(long) - 1));
-       data = *(unsigned long *)addr;
-       ret = data >> offset * 8;
-
-       return ret;
-}
-
-#else /* !CONFIG_CC_HAS_ASM_GOTO_OUTPUT */
-
-static inline unsigned long load_unaligned_zeropad(const void *addr)
-{
-       unsigned long offset, data;
-       unsigned long ret, err = 0;
-
-       asm(    "1:     mov %[mem], %[ret]\n"
                "2:\n"
-
-               _ASM_EXTABLE_FAULT(1b, 2b)
-
-               : [ret] "=&r" (ret), "+a" (err)
+               _ASM_EXTABLE_TYPE(1b, 2b, EX_TYPE_ZEROPAD)
+               : [ret] "=r" (ret)
                : [mem] "m" (*(unsigned long *)addr));
 
-       if (unlikely(err)) {
-               offset = (unsigned long)addr & (sizeof(long) - 1);
-               addr = (void *)((unsigned long)addr & ~(sizeof(long) - 1));
-               data = *(unsigned long *)addr;
-               ret = data >> offset * 8;
-       }
-
        return ret;
 }
 
-#endif /* CONFIG_CC_HAS_ASM_GOTO_OUTPUT */
-
 #endif /* _ASM_WORD_AT_A_TIME_H */
index 510d852..da7c361 100644 (file)
@@ -433,7 +433,8 @@ static void __init mmio_select_mitigation(void)
        u64 ia32_cap;
 
        if (!boot_cpu_has_bug(X86_BUG_MMIO_STALE_DATA) ||
-           cpu_mitigations_off()) {
+            boot_cpu_has_bug(X86_BUG_MMIO_UNKNOWN) ||
+            cpu_mitigations_off()) {
                mmio_mitigation = MMIO_MITIGATION_OFF;
                return;
        }
@@ -538,6 +539,8 @@ out:
                pr_info("TAA: %s\n", taa_strings[taa_mitigation]);
        if (boot_cpu_has_bug(X86_BUG_MMIO_STALE_DATA))
                pr_info("MMIO Stale Data: %s\n", mmio_strings[mmio_mitigation]);
+       else if (boot_cpu_has_bug(X86_BUG_MMIO_UNKNOWN))
+               pr_info("MMIO Stale Data: Unknown: No mitigations\n");
 }
 
 static void __init md_clear_select_mitigation(void)
@@ -2275,6 +2278,9 @@ static ssize_t tsx_async_abort_show_state(char *buf)
 
 static ssize_t mmio_stale_data_show_state(char *buf)
 {
+       if (boot_cpu_has_bug(X86_BUG_MMIO_UNKNOWN))
+               return sysfs_emit(buf, "Unknown: No mitigations\n");
+
        if (mmio_mitigation == MMIO_MITIGATION_OFF)
                return sysfs_emit(buf, "%s\n", mmio_strings[mmio_mitigation]);
 
@@ -2421,6 +2427,7 @@ static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr
                return srbds_show_state(buf);
 
        case X86_BUG_MMIO_STALE_DATA:
+       case X86_BUG_MMIO_UNKNOWN:
                return mmio_stale_data_show_state(buf);
 
        case X86_BUG_RETBLEED:
@@ -2480,7 +2487,10 @@ ssize_t cpu_show_srbds(struct device *dev, struct device_attribute *attr, char *
 
 ssize_t cpu_show_mmio_stale_data(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       return cpu_show_common(dev, attr, buf, X86_BUG_MMIO_STALE_DATA);
+       if (boot_cpu_has_bug(X86_BUG_MMIO_UNKNOWN))
+               return cpu_show_common(dev, attr, buf, X86_BUG_MMIO_UNKNOWN);
+       else
+               return cpu_show_common(dev, attr, buf, X86_BUG_MMIO_STALE_DATA);
 }
 
 ssize_t cpu_show_retbleed(struct device *dev, struct device_attribute *attr, char *buf)
index 64a73f4..3e508f2 100644 (file)
@@ -1135,7 +1135,8 @@ static void identify_cpu_without_cpuid(struct cpuinfo_x86 *c)
 #define NO_SWAPGS              BIT(6)
 #define NO_ITLB_MULTIHIT       BIT(7)
 #define NO_SPECTRE_V2          BIT(8)
-#define NO_EIBRS_PBRSB         BIT(9)
+#define NO_MMIO                        BIT(9)
+#define NO_EIBRS_PBRSB         BIT(10)
 
 #define VULNWL(vendor, family, model, whitelist)       \
        X86_MATCH_VENDOR_FAM_MODEL(vendor, family, model, whitelist)
@@ -1158,6 +1159,11 @@ static const __initconst struct x86_cpu_id cpu_vuln_whitelist[] = {
        VULNWL(VORTEX,  6, X86_MODEL_ANY,       NO_SPECULATION),
 
        /* Intel Family 6 */
+       VULNWL_INTEL(TIGERLAKE,                 NO_MMIO),
+       VULNWL_INTEL(TIGERLAKE_L,               NO_MMIO),
+       VULNWL_INTEL(ALDERLAKE,                 NO_MMIO),
+       VULNWL_INTEL(ALDERLAKE_L,               NO_MMIO),
+
        VULNWL_INTEL(ATOM_SALTWELL,             NO_SPECULATION | NO_ITLB_MULTIHIT),
        VULNWL_INTEL(ATOM_SALTWELL_TABLET,      NO_SPECULATION | NO_ITLB_MULTIHIT),
        VULNWL_INTEL(ATOM_SALTWELL_MID,         NO_SPECULATION | NO_ITLB_MULTIHIT),
@@ -1176,9 +1182,9 @@ static const __initconst struct x86_cpu_id cpu_vuln_whitelist[] = {
        VULNWL_INTEL(ATOM_AIRMONT_MID,          NO_L1TF | MSBDS_ONLY | NO_SWAPGS | NO_ITLB_MULTIHIT),
        VULNWL_INTEL(ATOM_AIRMONT_NP,           NO_L1TF | NO_SWAPGS | NO_ITLB_MULTIHIT),
 
-       VULNWL_INTEL(ATOM_GOLDMONT,             NO_MDS | NO_L1TF | NO_SWAPGS | NO_ITLB_MULTIHIT),
-       VULNWL_INTEL(ATOM_GOLDMONT_D,           NO_MDS | NO_L1TF | NO_SWAPGS | NO_ITLB_MULTIHIT),
-       VULNWL_INTEL(ATOM_GOLDMONT_PLUS,        NO_MDS | NO_L1TF | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_EIBRS_PBRSB),
+       VULNWL_INTEL(ATOM_GOLDMONT,             NO_MDS | NO_L1TF | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_MMIO),
+       VULNWL_INTEL(ATOM_GOLDMONT_D,           NO_MDS | NO_L1TF | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_MMIO),
+       VULNWL_INTEL(ATOM_GOLDMONT_PLUS,        NO_MDS | NO_L1TF | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_MMIO | NO_EIBRS_PBRSB),
 
        /*
         * Technically, swapgs isn't serializing on AMD (despite it previously
@@ -1193,18 +1199,18 @@ static const __initconst struct x86_cpu_id cpu_vuln_whitelist[] = {
        VULNWL_INTEL(ATOM_TREMONT_D,            NO_ITLB_MULTIHIT | NO_EIBRS_PBRSB),
 
        /* AMD Family 0xf - 0x12 */
-       VULNWL_AMD(0x0f,        NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT),
-       VULNWL_AMD(0x10,        NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT),
-       VULNWL_AMD(0x11,        NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT),
-       VULNWL_AMD(0x12,        NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT),
+       VULNWL_AMD(0x0f,        NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_MMIO),
+       VULNWL_AMD(0x10,        NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_MMIO),
+       VULNWL_AMD(0x11,        NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_MMIO),
+       VULNWL_AMD(0x12,        NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_MMIO),
 
        /* FAMILY_ANY must be last, otherwise 0x0f - 0x12 matches won't work */
-       VULNWL_AMD(X86_FAMILY_ANY,      NO_MELTDOWN | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT),
-       VULNWL_HYGON(X86_FAMILY_ANY,    NO_MELTDOWN | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT),
+       VULNWL_AMD(X86_FAMILY_ANY,      NO_MELTDOWN | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_MMIO),
+       VULNWL_HYGON(X86_FAMILY_ANY,    NO_MELTDOWN | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_MMIO),
 
        /* Zhaoxin Family 7 */
-       VULNWL(CENTAUR, 7, X86_MODEL_ANY,       NO_SPECTRE_V2 | NO_SWAPGS),
-       VULNWL(ZHAOXIN, 7, X86_MODEL_ANY,       NO_SPECTRE_V2 | NO_SWAPGS),
+       VULNWL(CENTAUR, 7, X86_MODEL_ANY,       NO_SPECTRE_V2 | NO_SWAPGS | NO_MMIO),
+       VULNWL(ZHAOXIN, 7, X86_MODEL_ANY,       NO_SPECTRE_V2 | NO_SWAPGS | NO_MMIO),
        {}
 };
 
@@ -1358,10 +1364,16 @@ static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c)
         * Affected CPU list is generally enough to enumerate the vulnerability,
         * but for virtualization case check for ARCH_CAP MSR bits also, VMM may
         * not want the guest to enumerate the bug.
+        *
+        * Set X86_BUG_MMIO_UNKNOWN for CPUs that are neither in the blacklist,
+        * nor in the whitelist and also don't enumerate MSR ARCH_CAP MMIO bits.
         */
-       if (cpu_matches(cpu_vuln_blacklist, MMIO) &&
-           !arch_cap_mmio_immune(ia32_cap))
-               setup_force_cpu_bug(X86_BUG_MMIO_STALE_DATA);
+       if (!arch_cap_mmio_immune(ia32_cap)) {
+               if (cpu_matches(cpu_vuln_blacklist, MMIO))
+                       setup_force_cpu_bug(X86_BUG_MMIO_STALE_DATA);
+               else if (!cpu_matches(cpu_vuln_whitelist, NO_MMIO))
+                       setup_force_cpu_bug(X86_BUG_MMIO_UNKNOWN);
+       }
 
        if (!cpu_has(c, X86_FEATURE_BTC_NO)) {
                if (cpu_matches(cpu_vuln_blacklist, RETBLEED) || (ia32_cap & ARCH_CAP_RSBA))
index e5dd6da..01833eb 100644 (file)
@@ -132,7 +132,7 @@ int irq_init_percpu_irqstack(unsigned int cpu)
        return 0;
 }
 
-#ifndef CONFIG_PREEMPT_RT
+#ifdef CONFIG_SOFTIRQ_ON_OWN_STACK
 void do_softirq_own_stack(void)
 {
        struct irq_stack *irqstk;
index 74167dc..4c3c27b 100644 (file)
@@ -505,7 +505,7 @@ static void kprobe_emulate_jcc(struct kprobe *p, struct pt_regs *regs)
                match = ((regs->flags & X86_EFLAGS_SF) >> X86_EFLAGS_SF_BIT) ^
                        ((regs->flags & X86_EFLAGS_OF) >> X86_EFLAGS_OF_BIT);
                if (p->ainsn.jcc.type >= 0xe)
-                       match = match && (regs->flags & X86_EFLAGS_ZF);
+                       match = match || (regs->flags & X86_EFLAGS_ZF);
        }
        __kprobe_emulate_jmp(p, regs, (match && !invert) || (!match && invert));
 }
index 63dc626..a428c62 100644 (file)
@@ -701,7 +701,13 @@ e_term:
 void __init early_snp_set_memory_private(unsigned long vaddr, unsigned long paddr,
                                         unsigned int npages)
 {
-       if (!cc_platform_has(CC_ATTR_GUEST_SEV_SNP))
+       /*
+        * This can be invoked in early boot while running identity mapped, so
+        * use an open coded check for SNP instead of using cc_platform_has().
+        * This eliminates worries about jump tables or checking boot_cpu_data
+        * in the cc_platform_has() function.
+        */
+       if (!(sev_status & MSR_AMD64_SEV_SNP_ENABLED))
                return;
 
         /*
@@ -717,7 +723,13 @@ void __init early_snp_set_memory_private(unsigned long vaddr, unsigned long padd
 void __init early_snp_set_memory_shared(unsigned long vaddr, unsigned long paddr,
                                        unsigned int npages)
 {
-       if (!cc_platform_has(CC_ATTR_GUEST_SEV_SNP))
+       /*
+        * This can be invoked in early boot while running identity mapped, so
+        * use an open coded check for SNP instead of using cc_platform_has().
+        * This eliminates worries about jump tables or checking boot_cpu_data
+        * in the cc_platform_has() function.
+        */
+       if (!(sev_status & MSR_AMD64_SEV_SNP_ENABLED))
                return;
 
        /* Invalidate the memory pages before they are marked shared in the RMP table. */
@@ -2100,7 +2112,7 @@ bool __init snp_init(struct boot_params *bp)
        return true;
 }
 
-void __init snp_abort(void)
+void __init __noreturn snp_abort(void)
 {
        sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SNP_UNSUPPORTED);
 }
index 38185ae..0ea57da 100644 (file)
@@ -93,22 +93,27 @@ static struct orc_entry *orc_find(unsigned long ip);
 static struct orc_entry *orc_ftrace_find(unsigned long ip)
 {
        struct ftrace_ops *ops;
-       unsigned long caller;
+       unsigned long tramp_addr, offset;
 
        ops = ftrace_ops_trampoline(ip);
        if (!ops)
                return NULL;
 
+       /* Set tramp_addr to the start of the code copied by the trampoline */
        if (ops->flags & FTRACE_OPS_FL_SAVE_REGS)
-               caller = (unsigned long)ftrace_regs_call;
+               tramp_addr = (unsigned long)ftrace_regs_caller;
        else
-               caller = (unsigned long)ftrace_call;
+               tramp_addr = (unsigned long)ftrace_caller;
+
+       /* Now place tramp_addr to the location within the trampoline ip is at */
+       offset = ip - ops->trampoline;
+       tramp_addr += offset;
 
        /* Prevent unlikely recursion */
-       if (ip == caller)
+       if (ip == tramp_addr)
                return NULL;
 
-       return orc_find(caller);
+       return orc_find(tramp_addr);
 }
 #else
 static struct orc_entry *orc_ftrace_find(unsigned long ip)
index b4eeb7c..d5ec3a2 100644 (file)
@@ -326,7 +326,8 @@ static int fastop(struct x86_emulate_ctxt *ctxt, fastop_t fop);
        ".align " __stringify(FASTOP_SIZE) " \n\t" \
        ".type " name ", @function \n\t" \
        name ":\n\t" \
-       ASM_ENDBR
+       ASM_ENDBR \
+       IBT_NOSEAL(name)
 
 #define FOP_FUNC(name) \
        __FOP_FUNC(#name)
@@ -446,27 +447,12 @@ static int fastop(struct x86_emulate_ctxt *ctxt, fastop_t fop);
        FOP_END
 
 /* Special case for SETcc - 1 instruction per cc */
-
-/*
- * Depending on .config the SETcc functions look like:
- *
- * ENDBR                       [4 bytes; CONFIG_X86_KERNEL_IBT]
- * SETcc %al                   [3 bytes]
- * RET | JMP __x86_return_thunk        [1,5 bytes; CONFIG_RETHUNK]
- * INT3                                [1 byte; CONFIG_SLS]
- */
-#define SETCC_ALIGN    16
-
 #define FOP_SETCC(op) \
-       ".align " __stringify(SETCC_ALIGN) " \n\t" \
-       ".type " #op ", @function \n\t" \
-       #op ": \n\t" \
-       ASM_ENDBR \
+       FOP_FUNC(op) \
        #op " %al \n\t" \
-       __FOP_RET(#op) \
-       ".skip " __stringify(SETCC_ALIGN) " - (.-" #op "), 0xcc \n\t"
+       FOP_RET(op)
 
-__FOP_START(setcc, SETCC_ALIGN)
+FOP_START(setcc)
 FOP_SETCC(seto)
 FOP_SETCC(setno)
 FOP_SETCC(setc)
@@ -493,7 +479,7 @@ FOP_END;
 
 /*
  * XXX: inoutclob user must know where the argument is being expanded.
- *      Relying on CONFIG_CC_HAS_ASM_GOTO would allow us to remove _fault.
+ *      Using asm goto would allow us to remove _fault.
  */
 #define asm_safe(insn, inoutclob...) \
 ({ \
@@ -1079,7 +1065,7 @@ static int em_bsr_c(struct x86_emulate_ctxt *ctxt)
 static __always_inline u8 test_cc(unsigned int condition, unsigned long flags)
 {
        u8 rc;
-       void (*fop)(void) = (void *)em_setcc + SETCC_ALIGN * (condition & 0xf);
+       void (*fop)(void) = (void *)em_setcc + FASTOP_SIZE * (condition & 0xf);
 
        flags = (flags & EFLAGS_MASK) | X86_EFLAGS_IF;
        asm("push %[flags]; popf; " CALL_NOSPEC
index eccddb1..e418ef3 100644 (file)
@@ -2914,7 +2914,7 @@ static void direct_pte_prefetch(struct kvm_vcpu *vcpu, u64 *sptep)
         * If addresses are being invalidated, skip prefetching to avoid
         * accidentally prefetching those addresses.
         */
-       if (unlikely(vcpu->kvm->mmu_notifier_count))
+       if (unlikely(vcpu->kvm->mmu_invalidate_in_progress))
                return;
 
        __direct_pte_prefetch(vcpu, sp, sptep);
@@ -2928,7 +2928,7 @@ static void direct_pte_prefetch(struct kvm_vcpu *vcpu, u64 *sptep)
  *
  * There are several ways to safely use this helper:
  *
- * - Check mmu_notifier_retry_hva() after grabbing the mapping level, before
+ * - Check mmu_invalidate_retry_hva() after grabbing the mapping level, before
  *   consuming it.  In this case, mmu_lock doesn't need to be held during the
  *   lookup, but it does need to be held while checking the MMU notifier.
  *
@@ -3056,7 +3056,7 @@ void kvm_mmu_hugepage_adjust(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault
                return;
 
        /*
-        * mmu_notifier_retry() was successful and mmu_lock is held, so
+        * mmu_invalidate_retry() was successful and mmu_lock is held, so
         * the pmd can't be split from under us.
         */
        fault->goal_level = fault->req_level;
@@ -4203,7 +4203,7 @@ static bool is_page_fault_stale(struct kvm_vcpu *vcpu,
                return true;
 
        return fault->slot &&
-              mmu_notifier_retry_hva(vcpu->kvm, mmu_seq, fault->hva);
+              mmu_invalidate_retry_hva(vcpu->kvm, mmu_seq, fault->hva);
 }
 
 static int direct_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault)
@@ -4227,7 +4227,7 @@ static int direct_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault
        if (r)
                return r;
 
-       mmu_seq = vcpu->kvm->mmu_notifier_seq;
+       mmu_seq = vcpu->kvm->mmu_invalidate_seq;
        smp_rmb();
 
        r = kvm_faultin_pfn(vcpu, fault);
@@ -5361,19 +5361,6 @@ void kvm_mmu_free_obsolete_roots(struct kvm_vcpu *vcpu)
        __kvm_mmu_free_obsolete_roots(vcpu->kvm, &vcpu->arch.guest_mmu);
 }
 
-static bool need_remote_flush(u64 old, u64 new)
-{
-       if (!is_shadow_present_pte(old))
-               return false;
-       if (!is_shadow_present_pte(new))
-               return true;
-       if ((old ^ new) & SPTE_BASE_ADDR_MASK)
-               return true;
-       old ^= shadow_nx_mask;
-       new ^= shadow_nx_mask;
-       return (old & ~new & SPTE_PERM_MASK) != 0;
-}
-
 static u64 mmu_pte_write_fetch_gpte(struct kvm_vcpu *vcpu, gpa_t *gpa,
                                    int *bytes)
 {
@@ -5519,7 +5506,7 @@ static void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
                        mmu_page_zap_pte(vcpu->kvm, sp, spte, NULL);
                        if (gentry && sp->role.level != PG_LEVEL_4K)
                                ++vcpu->kvm->stat.mmu_pde_zapped;
-                       if (need_remote_flush(entry, *spte))
+                       if (is_shadow_present_pte(entry))
                                flush = true;
                        ++spte;
                }
@@ -6055,7 +6042,7 @@ void kvm_zap_gfn_range(struct kvm *kvm, gfn_t gfn_start, gfn_t gfn_end)
 
        write_lock(&kvm->mmu_lock);
 
-       kvm_inc_notifier_count(kvm, gfn_start, gfn_end);
+       kvm_mmu_invalidate_begin(kvm, gfn_start, gfn_end);
 
        flush = kvm_rmap_zap_gfn_range(kvm, gfn_start, gfn_end);
 
@@ -6069,7 +6056,7 @@ void kvm_zap_gfn_range(struct kvm *kvm, gfn_t gfn_start, gfn_t gfn_end)
                kvm_flush_remote_tlbs_with_address(kvm, gfn_start,
                                                   gfn_end - gfn_start);
 
-       kvm_dec_notifier_count(kvm, gfn_start, gfn_end);
+       kvm_mmu_invalidate_end(kvm, gfn_start, gfn_end);
 
        write_unlock(&kvm->mmu_lock);
 }
@@ -6085,47 +6072,18 @@ void kvm_mmu_slot_remove_write_access(struct kvm *kvm,
                                      const struct kvm_memory_slot *memslot,
                                      int start_level)
 {
-       bool flush = false;
-
        if (kvm_memslots_have_rmaps(kvm)) {
                write_lock(&kvm->mmu_lock);
-               flush = slot_handle_level(kvm, memslot, slot_rmap_write_protect,
-                                         start_level, KVM_MAX_HUGEPAGE_LEVEL,
-                                         false);
+               slot_handle_level(kvm, memslot, slot_rmap_write_protect,
+                                 start_level, KVM_MAX_HUGEPAGE_LEVEL, false);
                write_unlock(&kvm->mmu_lock);
        }
 
        if (is_tdp_mmu_enabled(kvm)) {
                read_lock(&kvm->mmu_lock);
-               flush |= kvm_tdp_mmu_wrprot_slot(kvm, memslot, start_level);
+               kvm_tdp_mmu_wrprot_slot(kvm, memslot, start_level);
                read_unlock(&kvm->mmu_lock);
        }
-
-       /*
-        * Flush TLBs if any SPTEs had to be write-protected to ensure that
-        * guest writes are reflected in the dirty bitmap before the memslot
-        * update completes, i.e. before enabling dirty logging is visible to
-        * userspace.
-        *
-        * Perform the TLB flush outside the mmu_lock to reduce the amount of
-        * time the lock is held. However, this does mean that another CPU can
-        * now grab mmu_lock and encounter a write-protected SPTE while CPUs
-        * still have a writable mapping for the associated GFN in their TLB.
-        *
-        * This is safe but requires KVM to be careful when making decisions
-        * based on the write-protection status of an SPTE. Specifically, KVM
-        * also write-protects SPTEs to monitor changes to guest page tables
-        * during shadow paging, and must guarantee no CPUs can write to those
-        * page before the lock is dropped. As mentioned in the previous
-        * paragraph, a write-protected SPTE is no guarantee that CPU cannot
-        * perform writes. So to determine if a TLB flush is truly required, KVM
-        * will clear a separate software-only bit (MMU-writable) and skip the
-        * flush if-and-only-if this bit was already clear.
-        *
-        * See is_writable_pte() for more details.
-        */
-       if (flush)
-               kvm_arch_flush_remote_tlbs_memslot(kvm, memslot);
 }
 
 static inline bool need_topup(struct kvm_mmu_memory_cache *cache, int min)
@@ -6493,32 +6451,30 @@ void kvm_arch_flush_remote_tlbs_memslot(struct kvm *kvm,
 void kvm_mmu_slot_leaf_clear_dirty(struct kvm *kvm,
                                   const struct kvm_memory_slot *memslot)
 {
-       bool flush = false;
-
        if (kvm_memslots_have_rmaps(kvm)) {
                write_lock(&kvm->mmu_lock);
                /*
                 * Clear dirty bits only on 4k SPTEs since the legacy MMU only
                 * support dirty logging at a 4k granularity.
                 */
-               flush = slot_handle_level_4k(kvm, memslot, __rmap_clear_dirty, false);
+               slot_handle_level_4k(kvm, memslot, __rmap_clear_dirty, false);
                write_unlock(&kvm->mmu_lock);
        }
 
        if (is_tdp_mmu_enabled(kvm)) {
                read_lock(&kvm->mmu_lock);
-               flush |= kvm_tdp_mmu_clear_dirty_slot(kvm, memslot);
+               kvm_tdp_mmu_clear_dirty_slot(kvm, memslot);
                read_unlock(&kvm->mmu_lock);
        }
 
        /*
+        * The caller will flush the TLBs after this function returns.
+        *
         * It's also safe to flush TLBs out of mmu lock here as currently this
         * function is only used for dirty logging, in which case flushing TLB
         * out of mmu lock also guarantees no dirty pages will be lost in
         * dirty_bitmap.
         */
-       if (flush)
-               kvm_arch_flush_remote_tlbs_memslot(kvm, memslot);
 }
 
 void kvm_mmu_zap_all(struct kvm *kvm)
index f595807..39e0205 100644 (file)
@@ -589,7 +589,7 @@ static void FNAME(pte_prefetch)(struct kvm_vcpu *vcpu, struct guest_walker *gw,
         * If addresses are being invalidated, skip prefetching to avoid
         * accidentally prefetching those addresses.
         */
-       if (unlikely(vcpu->kvm->mmu_notifier_count))
+       if (unlikely(vcpu->kvm->mmu_invalidate_in_progress))
                return;
 
        if (sp->role.direct)
@@ -838,7 +838,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault
        else
                fault->max_level = walker.level;
 
-       mmu_seq = vcpu->kvm->mmu_notifier_seq;
+       mmu_seq = vcpu->kvm->mmu_invalidate_seq;
        smp_rmb();
 
        r = kvm_faultin_pfn(vcpu, fault);
index f3744ee..7670c13 100644 (file)
@@ -343,7 +343,7 @@ static __always_inline bool is_rsvd_spte(struct rsvd_bits_validate *rsvd_check,
 }
 
 /*
- * An shadow-present leaf SPTE may be non-writable for 3 possible reasons:
+ * A shadow-present leaf SPTE may be non-writable for 4 possible reasons:
  *
  *  1. To intercept writes for dirty logging. KVM write-protects huge pages
  *     so that they can be split be split down into the dirty logging
@@ -361,8 +361,13 @@ static __always_inline bool is_rsvd_spte(struct rsvd_bits_validate *rsvd_check,
  *     read-only memslot or guest memory backed by a read-only VMA. Writes to
  *     such pages are disallowed entirely.
  *
- * To keep track of why a given SPTE is write-protected, KVM uses 2
- * software-only bits in the SPTE:
+ *  4. To emulate the Accessed bit for SPTEs without A/D bits.  Note, in this
+ *     case, the SPTE is access-protected, not just write-protected!
+ *
+ * For cases #1 and #4, KVM can safely make such SPTEs writable without taking
+ * mmu_lock as capturing the Accessed/Dirty state doesn't require taking it.
+ * To differentiate #1 and #4 from #2 and #3, KVM uses two software-only bits
+ * in the SPTE:
  *
  *  shadow_mmu_writable_mask, aka MMU-writable -
  *    Cleared on SPTEs that KVM is currently write-protecting for shadow paging
@@ -391,7 +396,8 @@ static __always_inline bool is_rsvd_spte(struct rsvd_bits_validate *rsvd_check,
  * shadow page tables between vCPUs. Write-protecting an SPTE for dirty logging
  * (which does not clear the MMU-writable bit), does not flush TLBs before
  * dropping the lock, as it only needs to synchronize guest writes with the
- * dirty bitmap.
+ * dirty bitmap. Similarly, making the SPTE inaccessible (and non-writable) for
+ * access-tracking via the clear_young() MMU notifier also does not flush TLBs.
  *
  * So, there is the problem: clearing the MMU-writable bit can encounter a
  * write-protected SPTE while CPUs still have writable mappings for that SPTE
index d7f8331..c9b49a0 100644 (file)
@@ -843,8 +843,7 @@ static bool msr_write_intercepted(struct vcpu_vmx *vmx, u32 msr)
        if (!(exec_controls_get(vmx) & CPU_BASED_USE_MSR_BITMAPS))
                return true;
 
-       return vmx_test_msr_bitmap_write(vmx->loaded_vmcs->msr_bitmap,
-                                        MSR_IA32_SPEC_CTRL);
+       return vmx_test_msr_bitmap_write(vmx->loaded_vmcs->msr_bitmap, msr);
 }
 
 unsigned int __vmx_vcpu_run_flags(struct vcpu_vmx *vmx)
index 205ebdc..43a6a7e 100644 (file)
@@ -1557,12 +1557,32 @@ static const u32 msr_based_features_all[] = {
 static u32 msr_based_features[ARRAY_SIZE(msr_based_features_all)];
 static unsigned int num_msr_based_features;
 
+/*
+ * Some IA32_ARCH_CAPABILITIES bits have dependencies on MSRs that KVM
+ * does not yet virtualize. These include:
+ *   10 - MISC_PACKAGE_CTRLS
+ *   11 - ENERGY_FILTERING_CTL
+ *   12 - DOITM
+ *   18 - FB_CLEAR_CTRL
+ *   21 - XAPIC_DISABLE_STATUS
+ *   23 - OVERCLOCKING_STATUS
+ */
+
+#define KVM_SUPPORTED_ARCH_CAP \
+       (ARCH_CAP_RDCL_NO | ARCH_CAP_IBRS_ALL | ARCH_CAP_RSBA | \
+        ARCH_CAP_SKIP_VMENTRY_L1DFLUSH | ARCH_CAP_SSB_NO | ARCH_CAP_MDS_NO | \
+        ARCH_CAP_PSCHANGE_MC_NO | ARCH_CAP_TSX_CTRL_MSR | ARCH_CAP_TAA_NO | \
+        ARCH_CAP_SBDR_SSDP_NO | ARCH_CAP_FBSDP_NO | ARCH_CAP_PSDP_NO | \
+        ARCH_CAP_FB_CLEAR | ARCH_CAP_RRSBA | ARCH_CAP_PBRSB_NO)
+
 static u64 kvm_get_arch_capabilities(void)
 {
        u64 data = 0;
 
-       if (boot_cpu_has(X86_FEATURE_ARCH_CAPABILITIES))
+       if (boot_cpu_has(X86_FEATURE_ARCH_CAPABILITIES)) {
                rdmsrl(MSR_IA32_ARCH_CAPABILITIES, data);
+               data &= KVM_SUPPORTED_ARCH_CAP;
+       }
 
        /*
         * If nx_huge_pages is enabled, KVM's shadow paging will ensure that
@@ -1610,9 +1630,6 @@ static u64 kvm_get_arch_capabilities(void)
                 */
        }
 
-       /* Guests don't need to know "Fill buffer clear control" exists */
-       data &= ~ARCH_CAP_FB_CLEAR_CTRL;
-
        return data;
 }
 
@@ -10652,7 +10669,8 @@ static inline int vcpu_block(struct kvm_vcpu *vcpu)
        case KVM_MP_STATE_INIT_RECEIVED:
                break;
        default:
-               return -EINTR;
+               WARN_ON_ONCE(1);
+               break;
        }
        return 1;
 }
@@ -11093,9 +11111,22 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
 
        vcpu_load(vcpu);
 
-       if (!lapic_in_kernel(vcpu) &&
-           mp_state->mp_state != KVM_MP_STATE_RUNNABLE)
+       switch (mp_state->mp_state) {
+       case KVM_MP_STATE_UNINITIALIZED:
+       case KVM_MP_STATE_HALTED:
+       case KVM_MP_STATE_AP_RESET_HOLD:
+       case KVM_MP_STATE_INIT_RECEIVED:
+       case KVM_MP_STATE_SIPI_RECEIVED:
+               if (!lapic_in_kernel(vcpu))
+                       goto out;
+               break;
+
+       case KVM_MP_STATE_RUNNABLE:
+               break;
+
+       default:
                goto out;
+       }
 
        /*
         * KVM_MP_STATE_INIT_RECEIVED means the processor is in
@@ -11563,7 +11594,7 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
        vcpu->arch.mci_ctl2_banks = kcalloc(KVM_MAX_MCE_BANKS, sizeof(u64),
                                            GFP_KERNEL_ACCOUNT);
        if (!vcpu->arch.mce_banks || !vcpu->arch.mci_ctl2_banks)
-               goto fail_free_pio_data;
+               goto fail_free_mce_banks;
        vcpu->arch.mcg_cap = KVM_MAX_MCE_BANKS;
 
        if (!zalloc_cpumask_var(&vcpu->arch.wbinvd_dirty_mask,
@@ -11617,7 +11648,6 @@ free_wbinvd_dirty_mask:
 fail_free_mce_banks:
        kfree(vcpu->arch.mce_banks);
        kfree(vcpu->arch.mci_ctl2_banks);
-fail_free_pio_data:
        free_page((unsigned long)vcpu->arch.pio_data);
 fail_free_lapic:
        kvm_free_lapic(vcpu);
@@ -12473,6 +12503,50 @@ static void kvm_mmu_slot_apply_flags(struct kvm *kvm,
                } else {
                        kvm_mmu_slot_remove_write_access(kvm, new, PG_LEVEL_4K);
                }
+
+               /*
+                * Unconditionally flush the TLBs after enabling dirty logging.
+                * A flush is almost always going to be necessary (see below),
+                * and unconditionally flushing allows the helpers to omit
+                * the subtly complex checks when removing write access.
+                *
+                * Do the flush outside of mmu_lock to reduce the amount of
+                * time mmu_lock is held.  Flushing after dropping mmu_lock is
+                * safe as KVM only needs to guarantee the slot is fully
+                * write-protected before returning to userspace, i.e. before
+                * userspace can consume the dirty status.
+                *
+                * Flushing outside of mmu_lock requires KVM to be careful when
+                * making decisions based on writable status of an SPTE, e.g. a
+                * !writable SPTE doesn't guarantee a CPU can't perform writes.
+                *
+                * Specifically, KVM also write-protects guest page tables to
+                * monitor changes when using shadow paging, and must guarantee
+                * no CPUs can write to those page before mmu_lock is dropped.
+                * Because CPUs may have stale TLB entries at this point, a
+                * !writable SPTE doesn't guarantee CPUs can't perform writes.
+                *
+                * KVM also allows making SPTES writable outside of mmu_lock,
+                * e.g. to allow dirty logging without taking mmu_lock.
+                *
+                * To handle these scenarios, KVM uses a separate software-only
+                * bit (MMU-writable) to track if a SPTE is !writable due to
+                * a guest page table being write-protected (KVM clears the
+                * MMU-writable flag when write-protecting for shadow paging).
+                *
+                * The use of MMU-writable is also the primary motivation for
+                * the unconditional flush.  Because KVM must guarantee that a
+                * CPU doesn't contain stale, writable TLB entries for a
+                * !MMU-writable SPTE, KVM must flush if it encounters any
+                * MMU-writable SPTE regardless of whether the actual hardware
+                * writable bit was set.  I.e. KVM is almost guaranteed to need
+                * to flush, while unconditionally flushing allows the "remove
+                * write access" helpers to ignore MMU-writable entirely.
+                *
+                * See is_writable_pte() for more details (the case involving
+                * access-tracked SPTEs is particularly relevant).
+                */
+               kvm_arch_flush_remote_tlbs_memslot(kvm, new);
        }
 }
 
index 331310c..60814e1 100644 (file)
@@ -41,6 +41,59 @@ static bool ex_handler_default(const struct exception_table_entry *e,
        return true;
 }
 
+/*
+ * This is the *very* rare case where we do a "load_unaligned_zeropad()"
+ * and it's a page crosser into a non-existent page.
+ *
+ * This happens when we optimistically load a pathname a word-at-a-time
+ * and the name is less than the full word and the  next page is not
+ * mapped. Typically that only happens for CONFIG_DEBUG_PAGEALLOC.
+ *
+ * NOTE! The faulting address is always a 'mov mem,reg' type instruction
+ * of size 'long', and the exception fixup must always point to right
+ * after the instruction.
+ */
+static bool ex_handler_zeropad(const struct exception_table_entry *e,
+                              struct pt_regs *regs,
+                              unsigned long fault_addr)
+{
+       struct insn insn;
+       const unsigned long mask = sizeof(long) - 1;
+       unsigned long offset, addr, next_ip, len;
+       unsigned long *reg;
+
+       next_ip = ex_fixup_addr(e);
+       len = next_ip - regs->ip;
+       if (len > MAX_INSN_SIZE)
+               return false;
+
+       if (insn_decode(&insn, (void *) regs->ip, len, INSN_MODE_KERN))
+               return false;
+       if (insn.length != len)
+               return false;
+
+       if (insn.opcode.bytes[0] != 0x8b)
+               return false;
+       if (insn.opnd_bytes != sizeof(long))
+               return false;
+
+       addr = (unsigned long) insn_get_addr_ref(&insn, regs);
+       if (addr == ~0ul)
+               return false;
+
+       offset = addr & mask;
+       addr = addr & ~mask;
+       if (fault_addr != addr + sizeof(long))
+               return false;
+
+       reg = insn_get_modrm_reg_ptr(&insn, regs);
+       if (!reg)
+               return false;
+
+       *reg = *(unsigned long *)addr >> (offset * 8);
+       return ex_handler_default(e, regs);
+}
+
 static bool ex_handler_fault(const struct exception_table_entry *fixup,
                             struct pt_regs *regs, int trapnr)
 {
@@ -217,6 +270,8 @@ int fixup_exception(struct pt_regs *regs, int trapnr, unsigned long error_code,
                return ex_handler_sgx(e, regs, trapnr);
        case EX_TYPE_UCOPY_LEN:
                return ex_handler_ucopy_len(e, regs, trapnr, reg, imm);
+       case EX_TYPE_ZEROPAD:
+               return ex_handler_zeropad(e, regs, fault_addr);
        }
        BUG();
 }
index 39c5246..0fe690e 100644 (file)
@@ -645,7 +645,7 @@ phys_pud_init(pud_t *pud_page, unsigned long paddr, unsigned long paddr_end,
                        pages++;
                        spin_lock(&init_mm.page_table_lock);
 
-                       prot = __pgprot(pgprot_val(prot) | __PAGE_KERNEL_LARGE);
+                       prot = __pgprot(pgprot_val(prot) | _PAGE_PSE);
 
                        set_pte_init((pte_t *)pud,
                                     pfn_pte((paddr & PUD_MASK) >> PAGE_SHIFT,
index d5ef64d..66a209f 100644 (file)
@@ -62,6 +62,7 @@
 
 static bool __read_mostly pat_bp_initialized;
 static bool __read_mostly pat_disabled = !IS_ENABLED(CONFIG_X86_PAT);
+static bool __initdata pat_force_disabled = !IS_ENABLED(CONFIG_X86_PAT);
 static bool __read_mostly pat_bp_enabled;
 static bool __read_mostly pat_cm_initialized;
 
@@ -86,6 +87,7 @@ void pat_disable(const char *msg_reason)
 static int __init nopat(char *str)
 {
        pat_disable("PAT support disabled via boot option.");
+       pat_force_disabled = true;
        return 0;
 }
 early_param("nopat", nopat);
@@ -272,7 +274,7 @@ static void pat_ap_init(u64 pat)
        wrmsrl(MSR_IA32_CR_PAT, pat);
 }
 
-void init_cache_modes(void)
+void __init init_cache_modes(void)
 {
        u64 pat = 0;
 
@@ -313,6 +315,12 @@ void init_cache_modes(void)
                 */
                pat = PAT(0, WB) | PAT(1, WT) | PAT(2, UC_MINUS) | PAT(3, UC) |
                      PAT(4, WB) | PAT(5, WT) | PAT(6, UC_MINUS) | PAT(7, UC);
+       } else if (!pat_force_disabled && cpu_feature_enabled(X86_FEATURE_HYPERVISOR)) {
+               /*
+                * Clearly PAT is enabled underneath. Allow pat_enabled() to
+                * reflect this.
+                */
+               pat_bp_enabled = true;
        }
 
        __init_cache_modes(pat);
index 68fd2cf..f6e9f84 100644 (file)
@@ -6,10 +6,9 @@
 #include <asm/unistd.h>
 #include <sysdep/ptrace.h>
 
-typedef long syscall_handler_t(struct pt_regs);
+typedef long syscall_handler_t(struct syscall_args);
 
 extern syscall_handler_t *sys_call_table[];
 
 #define EXECUTE_SYSCALL(syscall, regs) \
-       ((long (*)(struct syscall_args)) \
-        (*sys_call_table[syscall]))(SYSCALL_ARGS(&regs->regs))
+       ((*sys_call_table[syscall]))(SYSCALL_ARGS(&regs->regs))
index ac8eee0..66162ea 100644 (file)
@@ -65,9 +65,6 @@ static int get_free_idx(struct task_struct* task)
        struct thread_struct *t = &task->thread;
        int idx;
 
-       if (!t->arch.tls_array)
-               return GDT_ENTRY_TLS_MIN;
-
        for (idx = 0; idx < GDT_ENTRY_TLS_ENTRIES; idx++)
                if (!t->arch.tls_array[idx].present)
                        return idx + GDT_ENTRY_TLS_MIN;
@@ -240,9 +237,6 @@ static int get_tls_entry(struct task_struct *task, struct user_desc *info,
 {
        struct thread_struct *t = &task->thread;
 
-       if (!t->arch.tls_array)
-               goto clear;
-
        if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)
                return -EINVAL;
 
index 8c0396f..6fbe97c 100644 (file)
@@ -65,7 +65,7 @@ quiet_cmd_vdso = VDSO    $@
                       -Wl,-T,$(filter %.lds,$^) $(filter %.o,$^) && \
                 sh $(srctree)/$(src)/checkundef.sh '$(NM)' '$@'
 
-VDSO_LDFLAGS = -fPIC -shared -Wl,--hash-style=sysv
+VDSO_LDFLAGS = -fPIC -shared -Wl,--hash-style=sysv -z noexecstack
 GCOV_PROFILE := n
 
 #
index a0d1104..651057c 100644 (file)
@@ -295,7 +295,7 @@ int blk_queue_enter(struct request_queue *q, blk_mq_req_flags_t flags)
 
        while (!blk_try_enter_queue(q, pm)) {
                if (flags & BLK_MQ_REQ_NOWAIT)
-                       return -EBUSY;
+                       return -EAGAIN;
 
                /*
                 * read pair of barrier in blk_freeze_queue_start(), we need to
@@ -325,7 +325,7 @@ int __bio_queue_enter(struct request_queue *q, struct bio *bio)
                        if (test_bit(GD_DEAD, &disk->state))
                                goto dead;
                        bio_wouldblock_error(bio);
-                       return -EBUSY;
+                       return -EAGAIN;
                }
 
                /*
index 67e6dbc..e59c306 100644 (file)
@@ -309,6 +309,11 @@ int blkdev_issue_secure_erase(struct block_device *bdev, sector_t sector,
        struct blk_plug plug;
        int ret = 0;
 
+       /* make sure that "len << SECTOR_SHIFT" doesn't overflow */
+       if (max_sectors > UINT_MAX >> SECTOR_SHIFT)
+               max_sectors = UINT_MAX >> SECTOR_SHIFT;
+       max_sectors &= ~bs_mask;
+
        if (max_sectors == 0)
                return -EOPNOTSUPP;
        if ((sector | nr_sects) & bs_mask)
@@ -322,10 +327,10 @@ int blkdev_issue_secure_erase(struct block_device *bdev, sector_t sector,
 
                bio = blk_next_bio(bio, bdev, 0, REQ_OP_SECURE_ERASE, gfp);
                bio->bi_iter.bi_sector = sector;
-               bio->bi_iter.bi_size = len;
+               bio->bi_iter.bi_size = len << SECTOR_SHIFT;
 
-               sector += len << SECTOR_SHIFT;
-               nr_sects -= len << SECTOR_SHIFT;
+               sector += len;
+               nr_sects -= len;
                if (!nr_sects) {
                        ret = submit_bio_wait(bio);
                        bio_put(bio);
index 8559cea..dee789f 100644 (file)
@@ -283,7 +283,9 @@ static const char *const rqf_name[] = {
        RQF_NAME(SPECIAL_PAYLOAD),
        RQF_NAME(ZONE_WRITE_LOCKED),
        RQF_NAME(MQ_POLL_SLEPT),
+       RQF_NAME(TIMED_OUT),
        RQF_NAME(ELV),
+       RQF_NAME(RESV),
 };
 #undef RQF_NAME
 
index 5ee62b9..c96c8c4 100644 (file)
@@ -1931,7 +1931,8 @@ out:
        /* If we didn't flush the entire list, we could have told the driver
         * there was more coming, but that turned out to be a lie.
         */
-       if ((!list_empty(list) || errors) && q->mq_ops->commit_rqs && queued)
+       if ((!list_empty(list) || errors || needs_resource ||
+            ret == BLK_STS_DEV_RESOURCE) && q->mq_ops->commit_rqs && queued)
                q->mq_ops->commit_rqs(hctx);
        /*
         * Any items that need requeuing? Stuff them into hctx->dispatch,
@@ -2229,26 +2230,6 @@ void blk_mq_delay_run_hw_queues(struct request_queue *q, unsigned long msecs)
 }
 EXPORT_SYMBOL(blk_mq_delay_run_hw_queues);
 
-/**
- * blk_mq_queue_stopped() - check whether one or more hctxs have been stopped
- * @q: request queue.
- *
- * The caller is responsible for serializing this function against
- * blk_mq_{start,stop}_hw_queue().
- */
-bool blk_mq_queue_stopped(struct request_queue *q)
-{
-       struct blk_mq_hw_ctx *hctx;
-       unsigned long i;
-
-       queue_for_each_hw_ctx(q, hctx, i)
-               if (blk_mq_hctx_stopped(hctx))
-                       return true;
-
-       return false;
-}
-EXPORT_SYMBOL(blk_mq_queue_stopped);
-
 /*
  * This function is often used for pausing .queue_rq() by driver when
  * there isn't enough resource or some conditions aren't satisfied, and
@@ -2570,7 +2551,7 @@ static void blk_mq_plug_issue_direct(struct blk_plug *plug, bool from_schedule)
                        break;
                case BLK_STS_RESOURCE:
                case BLK_STS_DEV_RESOURCE:
-                       blk_mq_request_bypass_insert(rq, false, last);
+                       blk_mq_request_bypass_insert(rq, false, true);
                        blk_mq_commit_rqs(hctx, &queued, from_schedule);
                        return;
                default:
@@ -2680,6 +2661,7 @@ void blk_mq_try_issue_list_directly(struct blk_mq_hw_ctx *hctx,
                list_del_init(&rq->queuelist);
                ret = blk_mq_request_issue_directly(rq, list_empty(list));
                if (ret != BLK_STS_OK) {
+                       errors++;
                        if (ret == BLK_STS_RESOURCE ||
                                        ret == BLK_STS_DEV_RESOURCE) {
                                blk_mq_request_bypass_insert(rq, false,
@@ -2687,7 +2669,6 @@ void blk_mq_try_issue_list_directly(struct blk_mq_hw_ctx *hctx,
                                break;
                        }
                        blk_mq_end_request(rq, ret);
-                       errors++;
                } else
                        queued++;
        }
index fc1d703..b8112f5 100644 (file)
@@ -596,6 +596,9 @@ static int blk_add_partitions(struct gendisk *disk)
        if (disk->flags & GENHD_FL_NO_PART)
                return 0;
 
+       if (test_bit(GD_SUPPRESS_PART_SCAN, &disk->state))
+               return 0;
+
        state = check_partition(disk);
        if (!state)
                return 0;
index db6ac54..e534fd4 100644 (file)
@@ -151,7 +151,7 @@ void acpi_thermal_cpufreq_exit(struct cpufreq_policy *policy)
        unsigned int cpu;
 
        for_each_cpu(cpu, policy->related_cpus) {
-               struct acpi_processor *pr = per_cpu(processors, policy->cpu);
+               struct acpi_processor *pr = per_cpu(processors, cpu);
 
                if (pr)
                        freq_qos_remove_request(&pr->thermal_req);
index 7b3ad8e..d4c168c 100644 (file)
@@ -370,7 +370,7 @@ static bool acpi_tie_nondev_subnodes(struct acpi_device_data *data)
                bool ret;
 
                status = acpi_attach_data(dn->handle, acpi_nondev_subnode_tag, dn);
-               if (ACPI_FAILURE(status)) {
+               if (ACPI_FAILURE(status) && status != AE_ALREADY_EXISTS) {
                        acpi_handle_err(dn->handle, "Can't tag data node\n");
                        return false;
                }
@@ -1043,11 +1043,10 @@ static int acpi_data_prop_read_single(const struct acpi_device_data *data,
                                break;                                  \
                        }                                               \
                        if (__items[i].integer.value > _Generic(__val,  \
-                                                               u8: U8_MAX, \
-                                                               u16: U16_MAX, \
-                                                               u32: U32_MAX, \
-                                                               u64: U64_MAX, \
-                                                               default: 0U)) { \
+                                                               u8 *: U8_MAX, \
+                                                               u16 *: U16_MAX, \
+                                                               u32 *: U32_MAX, \
+                                                               u64 *: U64_MAX)) { \
                                ret = -EOVERFLOW;                       \
                                break;                                  \
                        }                                               \
index 32b0e0b..110a535 100644 (file)
@@ -209,6 +209,7 @@ static int amba_match(struct device *dev, struct device_driver *drv)
        struct amba_device *pcdev = to_amba_device(dev);
        struct amba_driver *pcdrv = to_amba_driver(drv);
 
+       mutex_lock(&pcdev->periphid_lock);
        if (!pcdev->periphid) {
                int ret = amba_read_periphid(pcdev);
 
@@ -218,11 +219,14 @@ static int amba_match(struct device *dev, struct device_driver *drv)
                 * permanent failure in reading pid and cid, simply map it to
                 * -EPROBE_DEFER.
                 */
-               if (ret)
+               if (ret) {
+                       mutex_unlock(&pcdev->periphid_lock);
                        return -EPROBE_DEFER;
+               }
                dev_set_uevent_suppress(dev, false);
                kobject_uevent(&dev->kobj, KOBJ_ADD);
        }
+       mutex_unlock(&pcdev->periphid_lock);
 
        /* When driver_override is set, only bind to the matching driver */
        if (pcdev->driver_override)
@@ -532,6 +536,7 @@ static void amba_device_release(struct device *dev)
 
        if (d->res.parent)
                release_resource(&d->res);
+       mutex_destroy(&d->periphid_lock);
        kfree(d);
 }
 
@@ -584,6 +589,7 @@ static void amba_device_initialize(struct amba_device *dev, const char *name)
        dev->dev.dma_mask = &dev->dev.coherent_dma_mask;
        dev->dev.dma_parms = &dev->dma_parms;
        dev->res.name = dev_name(&dev->dev);
+       mutex_init(&dev->periphid_lock);
 }
 
 /**
index c964d7c..6428f6b 100644 (file)
@@ -1385,6 +1385,18 @@ static int binder_inc_ref_for_node(struct binder_proc *proc,
        }
        ret = binder_inc_ref_olocked(ref, strong, target_list);
        *rdata = ref->data;
+       if (ret && ref == new_ref) {
+               /*
+                * Cleanup the failed reference here as the target
+                * could now be dead and have already released its
+                * references by now. Calling on the new reference
+                * with strong=0 and a tmp_refs will not decrement
+                * the node. The new_ref gets kfree'd below.
+                */
+               binder_cleanup_ref_olocked(new_ref);
+               ref = NULL;
+       }
+
        binder_proc_unlock(proc);
        if (new_ref && ref != new_ref)
                /*
index 1014beb..9b1778c 100644 (file)
@@ -322,7 +322,6 @@ static inline void binder_alloc_set_vma(struct binder_alloc *alloc,
         */
        if (vma) {
                vm_start = vma->vm_start;
-               alloc->vma_vm_mm = vma->vm_mm;
                mmap_assert_write_locked(alloc->vma_vm_mm);
        } else {
                mmap_assert_locked(alloc->vma_vm_mm);
@@ -402,12 +401,15 @@ static struct binder_buffer *binder_alloc_new_buf_locked(
        size_t size, data_offsets_size;
        int ret;
 
+       mmap_read_lock(alloc->vma_vm_mm);
        if (!binder_alloc_get_vma(alloc)) {
+               mmap_read_unlock(alloc->vma_vm_mm);
                binder_alloc_debug(BINDER_DEBUG_USER_ERROR,
                                   "%d: binder_alloc_buf, no vma\n",
                                   alloc->pid);
                return ERR_PTR(-ESRCH);
        }
+       mmap_read_unlock(alloc->vma_vm_mm);
 
        data_offsets_size = ALIGN(data_size, sizeof(void *)) +
                ALIGN(offsets_size, sizeof(void *));
@@ -792,7 +794,6 @@ int binder_alloc_mmap_handler(struct binder_alloc *alloc,
        binder_insert_free_buffer(alloc, buffer);
        alloc->free_async_space = alloc->buffer_size / 2;
        binder_alloc_set_vma(alloc, vma);
-       mmgrab(alloc->vma_vm_mm);
 
        return 0;
 
@@ -929,17 +930,25 @@ void binder_alloc_print_pages(struct seq_file *m,
         * Make sure the binder_alloc is fully initialized, otherwise we might
         * read inconsistent state.
         */
-       if (binder_alloc_get_vma(alloc) != NULL) {
-               for (i = 0; i < alloc->buffer_size / PAGE_SIZE; i++) {
-                       page = &alloc->pages[i];
-                       if (!page->page_ptr)
-                               free++;
-                       else if (list_empty(&page->lru))
-                               active++;
-                       else
-                               lru++;
-               }
+
+       mmap_read_lock(alloc->vma_vm_mm);
+       if (binder_alloc_get_vma(alloc) == NULL) {
+               mmap_read_unlock(alloc->vma_vm_mm);
+               goto uninitialized;
        }
+
+       mmap_read_unlock(alloc->vma_vm_mm);
+       for (i = 0; i < alloc->buffer_size / PAGE_SIZE; i++) {
+               page = &alloc->pages[i];
+               if (!page->page_ptr)
+                       free++;
+               else if (list_empty(&page->lru))
+                       active++;
+               else
+                       lru++;
+       }
+
+uninitialized:
        mutex_unlock(&alloc->mutex);
        seq_printf(m, "  pages: %d:%d:%d\n", active, lru, free);
        seq_printf(m, "  pages high watermark: %zu\n", alloc->pages_high);
@@ -1080,6 +1089,8 @@ static struct shrinker binder_shrinker = {
 void binder_alloc_init(struct binder_alloc *alloc)
 {
        alloc->pid = current->group_leader->pid;
+       alloc->vma_vm_mm = current->mm;
+       mmgrab(alloc->vma_vm_mm);
        mutex_init(&alloc->mutex);
        INIT_LIST_HEAD(&alloc->buffers);
 }
index ef4508d..7c128c8 100644 (file)
@@ -2122,6 +2122,7 @@ const char *ata_get_cmd_name(u8 command)
                { ATA_CMD_WRITE_QUEUED_FUA_EXT, "WRITE DMA QUEUED FUA EXT" },
                { ATA_CMD_FPDMA_READ,           "READ FPDMA QUEUED" },
                { ATA_CMD_FPDMA_WRITE,          "WRITE FPDMA QUEUED" },
+               { ATA_CMD_NCQ_NON_DATA,         "NCQ NON-DATA" },
                { ATA_CMD_FPDMA_SEND,           "SEND FPDMA QUEUED" },
                { ATA_CMD_FPDMA_RECV,           "RECEIVE FPDMA QUEUED" },
                { ATA_CMD_PIO_READ,             "READ SECTOR(S)" },
index 0424b59..46cbe44 100644 (file)
@@ -724,7 +724,7 @@ const struct cpumask *cpu_clustergroup_mask(int cpu)
         */
        if (cpumask_subset(cpu_coregroup_mask(cpu),
                           &cpu_topology[cpu].cluster_sibling))
-               return get_cpu_mask(cpu);
+               return topology_sibling_cpumask(cpu);
 
        return &cpu_topology[cpu].cluster_sibling;
 }
@@ -735,7 +735,7 @@ void update_siblings_masks(unsigned int cpuid)
        int cpu, ret;
 
        ret = detect_cache_attributes(cpuid);
-       if (ret)
+       if (ret && ret != -ENOENT)
                pr_info("Early cacheinfo failed, ret = %d\n", ret);
 
        /* update core and thread sibling masks */
index 70f79fc..ec69b43 100644 (file)
@@ -274,12 +274,42 @@ static int __init deferred_probe_timeout_setup(char *str)
 }
 __setup("deferred_probe_timeout=", deferred_probe_timeout_setup);
 
+/**
+ * driver_deferred_probe_check_state() - Check deferred probe state
+ * @dev: device to check
+ *
+ * Return:
+ * * -ENODEV if initcalls have completed and modules are disabled.
+ * * -ETIMEDOUT if the deferred probe timeout was set and has expired
+ *   and modules are enabled.
+ * * -EPROBE_DEFER in other cases.
+ *
+ * Drivers or subsystems can opt-in to calling this function instead of directly
+ * returning -EPROBE_DEFER.
+ */
+int driver_deferred_probe_check_state(struct device *dev)
+{
+       if (!IS_ENABLED(CONFIG_MODULES) && initcalls_done) {
+               dev_warn(dev, "ignoring dependency for device, assuming no driver\n");
+               return -ENODEV;
+       }
+
+       if (!driver_deferred_probe_timeout && initcalls_done) {
+               dev_warn(dev, "deferred probe timeout, ignoring dependency\n");
+               return -ETIMEDOUT;
+       }
+
+       return -EPROBE_DEFER;
+}
+EXPORT_SYMBOL_GPL(driver_deferred_probe_check_state);
+
 static void deferred_probe_timeout_work_func(struct work_struct *work)
 {
        struct device_private *p;
 
        fw_devlink_drivers_done();
 
+       driver_deferred_probe_timeout = 0;
        driver_deferred_probe_trigger();
        flush_work(&deferred_probe_work);
 
@@ -881,6 +911,11 @@ static int __device_attach_driver(struct device_driver *drv, void *_data)
                dev_dbg(dev, "Device match requests probe deferral\n");
                dev->can_match = true;
                driver_deferred_probe_add(dev);
+               /*
+                * Device can't match with a driver right now, so don't attempt
+                * to match or bind with other drivers on the bus.
+                */
+               return ret;
        } else if (ret < 0) {
                dev_dbg(dev, "Bus failed to match device: %d\n", ret);
                return ret;
@@ -1120,6 +1155,11 @@ static int __driver_attach(struct device *dev, void *data)
                dev_dbg(dev, "Device match requests probe deferral\n");
                dev->can_match = true;
                driver_deferred_probe_add(dev);
+               /*
+                * Driver could not match with device, but may match with
+                * another device on the bus.
+                */
+               return 0;
        } else if (ret < 0) {
                dev_dbg(dev, "Bus failed to match device: %d\n", ret);
                return ret;
index 15a75af..676b627 100644 (file)
@@ -63,6 +63,12 @@ int driver_set_override(struct device *dev, const char **override,
        if (len >= (PAGE_SIZE - 1))
                return -EINVAL;
 
+       /*
+        * Compute the real length of the string in case userspace sends us a
+        * bunch of \0 characters like python likes to do.
+        */
+       len = strlen(s);
+
        if (!len) {
                /* Empty string passed - clear override */
                device_lock(dev);
index 77bad32..5b66b3d 100644 (file)
@@ -93,10 +93,9 @@ static void fw_dev_release(struct device *dev)
 {
        struct fw_sysfs *fw_sysfs = to_fw_sysfs(dev);
 
-       if (fw_sysfs->fw_upload_priv) {
-               free_fw_priv(fw_sysfs->fw_priv);
-               kfree(fw_sysfs->fw_upload_priv);
-       }
+       if (fw_sysfs->fw_upload_priv)
+               fw_upload_free(fw_sysfs);
+
        kfree(fw_sysfs);
 }
 
index 5d8ff16..df1d5ad 100644 (file)
@@ -106,12 +106,17 @@ extern struct device_attribute dev_attr_cancel;
 extern struct device_attribute dev_attr_remaining_size;
 
 int fw_upload_start(struct fw_sysfs *fw_sysfs);
+void fw_upload_free(struct fw_sysfs *fw_sysfs);
 umode_t fw_upload_is_visible(struct kobject *kobj, struct attribute *attr, int n);
 #else
 static inline int fw_upload_start(struct fw_sysfs *fw_sysfs)
 {
        return 0;
 }
+
+static inline void fw_upload_free(struct fw_sysfs *fw_sysfs)
+{
+}
 #endif
 
 #endif /* __FIRMWARE_SYSFS_H */
index 87044d5..a0af8f5 100644 (file)
@@ -264,6 +264,15 @@ int fw_upload_start(struct fw_sysfs *fw_sysfs)
        return 0;
 }
 
+void fw_upload_free(struct fw_sysfs *fw_sysfs)
+{
+       struct fw_upload_priv *fw_upload_priv = fw_sysfs->fw_upload_priv;
+
+       free_fw_priv(fw_sysfs->fw_priv);
+       kfree(fw_upload_priv->fw_upload);
+       kfree(fw_upload_priv);
+}
+
 /**
  * firmware_upload_register() - register for the firmware upload sysfs API
  * @module: kernel module of this device
@@ -377,6 +386,7 @@ void firmware_upload_unregister(struct fw_upload *fw_upload)
 {
        struct fw_sysfs *fw_sysfs = fw_upload->priv;
        struct fw_upload_priv *fw_upload_priv = fw_sysfs->fw_upload_priv;
+       struct module *module = fw_upload_priv->module;
 
        mutex_lock(&fw_upload_priv->lock);
        if (fw_upload_priv->progress == FW_UPLOAD_PROG_IDLE) {
@@ -392,6 +402,6 @@ void firmware_upload_unregister(struct fw_upload *fw_upload)
 
 unregister:
        device_unregister(&fw_sysfs->dev);
-       module_put(fw_upload_priv->module);
+       module_put(module);
 }
 EXPORT_SYMBOL_GPL(firmware_upload_unregister);
index 5a2e023..55a10e6 100644 (file)
@@ -2733,7 +2733,7 @@ static int __genpd_dev_pm_attach(struct device *dev, struct device *base_dev,
                mutex_unlock(&gpd_list_lock);
                dev_dbg(dev, "%s() failed to find PM domain: %ld\n",
                        __func__, PTR_ERR(pd));
-               return -ENODEV;
+               return driver_deferred_probe_check_state(base_dev);
        }
 
        dev_dbg(dev, "adding to PM domain %s\n", pd->name);
index 719323b..37ab23a 100644 (file)
@@ -113,6 +113,7 @@ static const struct regmap_bus *regmap_get_spi_bus(struct spi_device *spi,
                                                   const struct regmap_config *config)
 {
        size_t max_size = spi_max_transfer_size(spi);
+       size_t max_msg_size, reg_reserve_size;
        struct regmap_bus *bus;
 
        if (max_size != SIZE_MAX) {
@@ -120,9 +121,16 @@ static const struct regmap_bus *regmap_get_spi_bus(struct spi_device *spi,
                if (!bus)
                        return ERR_PTR(-ENOMEM);
 
+               max_msg_size = spi_max_message_size(spi);
+               reg_reserve_size = config->reg_bits / BITS_PER_BYTE
+                                + config->pad_bits / BITS_PER_BYTE;
+               if (max_size + reg_reserve_size > max_msg_size)
+                       max_size -= reg_reserve_size;
+
                bus->free_on_exit = true;
                bus->max_raw_read = max_size;
                bus->max_raw_write = max_size;
+
                return bus;
        }
 
index e3c0ba9..ad92192 100644 (file)
@@ -979,6 +979,11 @@ loop_set_status_from_info(struct loop_device *lo,
 
        lo->lo_offset = info->lo_offset;
        lo->lo_sizelimit = info->lo_sizelimit;
+
+       /* loff_t vars have been assigned __u64 */
+       if (lo->lo_offset < 0 || lo->lo_sizelimit < 0)
+               return -EOVERFLOW;
+
        memcpy(lo->lo_file_name, info->lo_file_name, LO_NAME_SIZE);
        lo->lo_file_name[LO_NAME_SIZE-1] = 0;
        lo->lo_flags = info->lo_flags;
index 2b7d1db..6a4a94b 100644 (file)
@@ -555,7 +555,7 @@ static inline struct ublk_uring_cmd_pdu *ublk_get_uring_cmd_pdu(
        return (struct ublk_uring_cmd_pdu *)&ioucmd->pdu;
 }
 
-static bool ubq_daemon_is_dying(struct ublk_queue *ubq)
+static inline bool ubq_daemon_is_dying(struct ublk_queue *ubq)
 {
        return ubq->ubq_daemon->flags & PF_EXITING;
 }
@@ -605,8 +605,9 @@ static void ublk_complete_rq(struct request *req)
 }
 
 /*
- * __ublk_fail_req() may be called from abort context or ->ubq_daemon
- * context during exiting, so lock is required.
+ * Since __ublk_rq_task_work always fails requests immediately during
+ * exiting, __ublk_fail_req() is only called from abort context during
+ * exiting. So lock is unnecessary.
  *
  * Also aborting may not be started yet, keep in mind that one failed
  * request may be issued by block layer again.
@@ -644,8 +645,7 @@ static inline void __ublk_rq_task_work(struct request *req)
        struct ublk_device *ub = ubq->dev;
        int tag = req->tag;
        struct ublk_io *io = &ubq->ios[tag];
-       bool task_exiting = current != ubq->ubq_daemon ||
-               (current->flags & PF_EXITING);
+       bool task_exiting = current != ubq->ubq_daemon || ubq_daemon_is_dying(ubq);
        unsigned int mapped_bytes;
 
        pr_devel("%s: complete: op %d, qid %d tag %d io_flags %x addr %llx\n",
@@ -680,6 +680,11 @@ static inline void __ublk_rq_task_work(struct request *req)
                 * do the copy work.
                 */
                io->flags &= ~UBLK_IO_FLAG_NEED_GET_DATA;
+               /* update iod->addr because ublksrv may have passed a new io buffer */
+               ublk_get_iod(ubq, req->tag)->addr = io->addr;
+               pr_devel("%s: update iod->addr: op %d, qid %d tag %d io_flags %x addr %llx\n",
+                               __func__, io->cmd->cmd_op, ubq->q_id, req->tag, io->flags,
+                               ublk_get_iod(ubq, req->tag)->addr);
        }
 
        mapped_bytes = ublk_map_io(ubq, req, io);
@@ -751,9 +756,25 @@ static blk_status_t ublk_queue_rq(struct blk_mq_hw_ctx *hctx,
                if (task_work_add(ubq->ubq_daemon, &data->work, notify_mode))
                        goto fail;
        } else {
-               struct io_uring_cmd *cmd = ubq->ios[rq->tag].cmd;
+               struct ublk_io *io = &ubq->ios[rq->tag];
+               struct io_uring_cmd *cmd = io->cmd;
                struct ublk_uring_cmd_pdu *pdu = ublk_get_uring_cmd_pdu(cmd);
 
+               /*
+                * If the check pass, we know that this is a re-issued request aborted
+                * previously in monitor_work because the ubq_daemon(cmd's task) is
+                * PF_EXITING. We cannot call io_uring_cmd_complete_in_task() anymore
+                * because this ioucmd's io_uring context may be freed now if no inflight
+                * ioucmd exists. Otherwise we may cause null-deref in ctx->fallback_work.
+                *
+                * Note: monitor_work sets UBLK_IO_FLAG_ABORTED and ends this request(releasing
+                * the tag). Then the request is re-started(allocating the tag) and we are here.
+                * Since releasing/allocating a tag implies smp_mb(), finding UBLK_IO_FLAG_ABORTED
+                * guarantees that here is a re-issued request aborted previously.
+                */
+               if ((io->flags & UBLK_IO_FLAG_ABORTED))
+                       goto fail;
+
                pdu->req = rq;
                io_uring_cmd_complete_in_task(cmd, ublk_rq_task_work_cb);
        }
index bda5c81..a284734 100644 (file)
@@ -226,6 +226,9 @@ struct xen_vbd {
        sector_t                size;
        unsigned int            flush_support:1;
        unsigned int            discard_secure:1;
+       /* Connect-time cached feature_persistent parameter value */
+       unsigned int            feature_gnt_persistent_parm:1;
+       /* Persistent grants feature negotiation result */
        unsigned int            feature_gnt_persistent:1;
        unsigned int            overflow_max_grants:1;
 };
index ee7ad2f..c0227df 100644 (file)
@@ -907,7 +907,7 @@ again:
        xen_blkbk_barrier(xbt, be, be->blkif->vbd.flush_support);
 
        err = xenbus_printf(xbt, dev->nodename, "feature-persistent", "%u",
-                       be->blkif->vbd.feature_gnt_persistent);
+                       be->blkif->vbd.feature_gnt_persistent_parm);
        if (err) {
                xenbus_dev_fatal(dev, err, "writing %s/feature-persistent",
                                 dev->nodename);
@@ -1085,7 +1085,9 @@ static int connect_ring(struct backend_info *be)
                return -ENOSYS;
        }
 
-       blkif->vbd.feature_gnt_persistent = feature_persistent &&
+       blkif->vbd.feature_gnt_persistent_parm = feature_persistent;
+       blkif->vbd.feature_gnt_persistent =
+               blkif->vbd.feature_gnt_persistent_parm &&
                xenbus_read_unsigned(dev->otherend, "feature-persistent", 0);
 
        blkif->vbd.overflow_max_grants = 0;
index 8e56e69..35b9bca 100644 (file)
@@ -213,6 +213,9 @@ struct blkfront_info
        unsigned int feature_fua:1;
        unsigned int feature_discard:1;
        unsigned int feature_secdiscard:1;
+       /* Connect-time cached feature_persistent parameter */
+       unsigned int feature_persistent_parm:1;
+       /* Persistent grants feature negotiation result */
        unsigned int feature_persistent:1;
        unsigned int bounce:1;
        unsigned int discard_granularity;
@@ -1756,6 +1759,12 @@ abort_transaction:
        return err;
 }
 
+/* Enable the persistent grants feature. */
+static bool feature_persistent = true;
+module_param(feature_persistent, bool, 0644);
+MODULE_PARM_DESC(feature_persistent,
+               "Enables the persistent grants feature");
+
 /* Common code used when first setting up, and when resuming. */
 static int talk_to_blkback(struct xenbus_device *dev,
                           struct blkfront_info *info)
@@ -1847,8 +1856,9 @@ again:
                message = "writing protocol";
                goto abort_transaction;
        }
+       info->feature_persistent_parm = feature_persistent;
        err = xenbus_printf(xbt, dev->nodename, "feature-persistent", "%u",
-                       info->feature_persistent);
+                       info->feature_persistent_parm);
        if (err)
                dev_warn(&dev->dev,
                         "writing persistent grants feature to xenbus");
@@ -1916,12 +1926,6 @@ static int negotiate_mq(struct blkfront_info *info)
        return 0;
 }
 
-/* Enable the persistent grants feature. */
-static bool feature_persistent = true;
-module_param(feature_persistent, bool, 0644);
-MODULE_PARM_DESC(feature_persistent,
-               "Enables the persistent grants feature");
-
 /*
  * Entry point to this code when a new device is created.  Allocate the basic
  * structures and the ring buffer for communication with the backend, and
@@ -2281,7 +2285,7 @@ static void blkfront_gather_backend_features(struct blkfront_info *info)
        if (xenbus_read_unsigned(info->xbdev->otherend, "feature-discard", 0))
                blkfront_setup_discard(info);
 
-       if (feature_persistent)
+       if (info->feature_persistent_parm)
                info->feature_persistent =
                        !!xenbus_read_unsigned(info->xbdev->otherend,
                                               "feature-persistent", 0);
index 92cb929..226ea76 100644 (file)
@@ -1146,14 +1146,15 @@ static ssize_t bd_stat_show(struct device *dev,
 static ssize_t debug_stat_show(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
-       int version = 2;
+       int version = 1;
        struct zram *zram = dev_to_zram(dev);
        ssize_t ret;
 
        down_read(&zram->init_lock);
        ret = scnprintf(buf, PAGE_SIZE,
-                       "version: %d\n%8llu\n",
+                       "version: %d\n%8llu %8llu\n",
                        version,
+                       (u64)atomic64_read(&zram->stats.writestall),
                        (u64)atomic64_read(&zram->stats.miss_free));
        up_read(&zram->init_lock);
 
@@ -1351,7 +1352,7 @@ static int __zram_bvec_write(struct zram *zram, struct bio_vec *bvec,
 {
        int ret = 0;
        unsigned long alloced_pages;
-       unsigned long handle = 0;
+       unsigned long handle = -ENOMEM;
        unsigned int comp_len = 0;
        void *src, *dst, *mem;
        struct zcomp_strm *zstrm;
@@ -1369,6 +1370,7 @@ static int __zram_bvec_write(struct zram *zram, struct bio_vec *bvec,
        }
        kunmap_atomic(mem);
 
+compress_again:
        zstrm = zcomp_stream_get(zram->comp);
        src = kmap_atomic(page);
        ret = zcomp_compress(zstrm, src, &comp_len);
@@ -1377,20 +1379,39 @@ static int __zram_bvec_write(struct zram *zram, struct bio_vec *bvec,
        if (unlikely(ret)) {
                zcomp_stream_put(zram->comp);
                pr_err("Compression failed! err=%d\n", ret);
+               zs_free(zram->mem_pool, handle);
                return ret;
        }
 
        if (comp_len >= huge_class_size)
                comp_len = PAGE_SIZE;
-
-       handle = zs_malloc(zram->mem_pool, comp_len,
-                       __GFP_KSWAPD_RECLAIM |
-                       __GFP_NOWARN |
-                       __GFP_HIGHMEM |
-                       __GFP_MOVABLE);
-
+       /*
+        * handle allocation has 2 paths:
+        * a) fast path is executed with preemption disabled (for
+        *  per-cpu streams) and has __GFP_DIRECT_RECLAIM bit clear,
+        *  since we can't sleep;
+        * b) slow path enables preemption and attempts to allocate
+        *  the page with __GFP_DIRECT_RECLAIM bit set. we have to
+        *  put per-cpu compression stream and, thus, to re-do
+        *  the compression once handle is allocated.
+        *
+        * if we have a 'non-null' handle here then we are coming
+        * from the slow path and handle has already been allocated.
+        */
+       if (IS_ERR((void *)handle))
+               handle = zs_malloc(zram->mem_pool, comp_len,
+                               __GFP_KSWAPD_RECLAIM |
+                               __GFP_NOWARN |
+                               __GFP_HIGHMEM |
+                               __GFP_MOVABLE);
        if (IS_ERR((void *)handle)) {
                zcomp_stream_put(zram->comp);
+               atomic64_inc(&zram->stats.writestall);
+               handle = zs_malloc(zram->mem_pool, comp_len,
+                               GFP_NOIO | __GFP_HIGHMEM |
+                               __GFP_MOVABLE);
+               if (!IS_ERR((void *)handle))
+                       goto compress_again;
                return PTR_ERR((void *)handle);
        }
 
@@ -1948,6 +1969,7 @@ static int zram_add(void)
        if (ZRAM_LOGICAL_BLOCK_SIZE == PAGE_SIZE)
                blk_queue_max_write_zeroes_sectors(zram->disk->queue, UINT_MAX);
 
+       blk_queue_flag_set(QUEUE_FLAG_STABLE_WRITES, zram->disk->queue);
        ret = device_add_disk(NULL, zram->disk, zram_disk_groups);
        if (ret)
                goto out_cleanup_disk;
index 158c91e..80c3b43 100644 (file)
@@ -81,6 +81,7 @@ struct zram_stats {
        atomic64_t huge_pages_since;    /* no. of huge pages since zram set up */
        atomic64_t pages_stored;        /* no. of pages currently stored */
        atomic_long_t max_used_pages;   /* no. of maximum pages stored */
+       atomic64_t writestall;          /* no. of write slow paths */
        atomic64_t miss_free;           /* no. of missed free */
 #ifdef CONFIG_ZRAM_WRITEBACK
        atomic64_t bd_count;            /* no. of pages in backing device */
index f3aef77..df0fbfe 100644 (file)
@@ -430,12 +430,25 @@ irqreturn_t mhi_irq_handler(int irq_number, void *dev)
 {
        struct mhi_event *mhi_event = dev;
        struct mhi_controller *mhi_cntrl = mhi_event->mhi_cntrl;
-       struct mhi_event_ctxt *er_ctxt =
-               &mhi_cntrl->mhi_ctxt->er_ctxt[mhi_event->er_index];
+       struct mhi_event_ctxt *er_ctxt;
        struct mhi_ring *ev_ring = &mhi_event->ring;
-       dma_addr_t ptr = le64_to_cpu(er_ctxt->rp);
+       dma_addr_t ptr;
        void *dev_rp;
 
+       /*
+        * If CONFIG_DEBUG_SHIRQ is set, the IRQ handler will get invoked during __free_irq()
+        * and by that time mhi_ctxt() would've freed. So check for the existence of mhi_ctxt
+        * before handling the IRQs.
+        */
+       if (!mhi_cntrl->mhi_ctxt) {
+               dev_dbg(&mhi_cntrl->mhi_dev->dev,
+                       "mhi_ctxt has been freed\n");
+               return IRQ_HANDLED;
+       }
+
+       er_ctxt = &mhi_cntrl->mhi_ctxt->er_ctxt[mhi_event->er_index];
+       ptr = le64_to_cpu(er_ctxt->rp);
+
        if (!is_valid_ring_ptr(ev_ring, ptr)) {
                dev_err(&mhi_cntrl->mhi_dev->dev,
                        "Event ring rp points outside of the event ring\n");
index 84ca98e..32a932a 100644 (file)
@@ -480,6 +480,11 @@ static ssize_t splice_write_null(struct pipe_inode_info *pipe, struct file *out,
        return splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_null);
 }
 
+static int uring_cmd_null(struct io_uring_cmd *ioucmd, unsigned int issue_flags)
+{
+       return 0;
+}
+
 static ssize_t read_iter_zero(struct kiocb *iocb, struct iov_iter *iter)
 {
        size_t written = 0;
@@ -663,6 +668,7 @@ static const struct file_operations null_fops = {
        .read_iter      = read_iter_null,
        .write_iter     = write_iter_null,
        .splice_write   = splice_write_null,
+       .uring_cmd      = uring_cmd_null,
 };
 
 static const struct file_operations __maybe_unused port_fops = {
index 7351800..876b37b 100644 (file)
@@ -203,7 +203,7 @@ static unsigned long raspberrypi_fw_get_rate(struct clk_hw *hw,
        ret = raspberrypi_clock_property(rpi->firmware, data,
                                         RPI_FIRMWARE_GET_CLOCK_RATE, &val);
        if (ret)
-               return ret;
+               return 0;
 
        return val;
 }
@@ -220,7 +220,7 @@ static int raspberrypi_fw_set_rate(struct clk_hw *hw, unsigned long rate,
        ret = raspberrypi_clock_property(rpi->firmware, data,
                                         RPI_FIRMWARE_SET_CLOCK_RATE, &_rate);
        if (ret)
-               dev_err_ratelimited(rpi->dev, "Failed to change %s frequency: %d",
+               dev_err_ratelimited(rpi->dev, "Failed to change %s frequency: %d\n",
                                    clk_hw_get_name(hw), ret);
 
        return ret;
@@ -288,7 +288,7 @@ static struct clk_hw *raspberrypi_clk_register(struct raspberrypi_clk *rpi,
                                         RPI_FIRMWARE_GET_MIN_CLOCK_RATE,
                                         &min_rate);
        if (ret) {
-               dev_err(rpi->dev, "Failed to get clock %d min freq: %d",
+               dev_err(rpi->dev, "Failed to get clock %d min freq: %d\n",
                        id, ret);
                return ERR_PTR(ret);
        }
@@ -344,8 +344,13 @@ static int raspberrypi_discover_clocks(struct raspberrypi_clk *rpi,
        struct rpi_firmware_get_clocks_response *clks;
        int ret;
 
+       /*
+        * The firmware doesn't guarantee that the last element of
+        * RPI_FIRMWARE_GET_CLOCKS is zeroed. So allocate an additional
+        * zero element as sentinel.
+        */
        clks = devm_kcalloc(rpi->dev,
-                           RPI_FIRMWARE_NUM_CLK_ID, sizeof(*clks),
+                           RPI_FIRMWARE_NUM_CLK_ID + 1, sizeof(*clks),
                            GFP_KERNEL);
        if (!clks)
                return -ENOMEM;
@@ -360,7 +365,8 @@ static int raspberrypi_discover_clocks(struct raspberrypi_clk *rpi,
                struct raspberrypi_clk_variant *variant;
 
                if (clks->id > RPI_FIRMWARE_NUM_CLK_ID) {
-                       dev_err(rpi->dev, "Unknown clock id: %u", clks->id);
+                       dev_err(rpi->dev, "Unknown clock id: %u (max: %u)\n",
+                                          clks->id, RPI_FIRMWARE_NUM_CLK_ID);
                        return -EINVAL;
                }
 
index 7fc191c..bd0b35c 100644 (file)
@@ -840,10 +840,9 @@ static void clk_core_unprepare(struct clk_core *core)
        if (core->ops->unprepare)
                core->ops->unprepare(core->hw);
 
-       clk_pm_runtime_put(core);
-
        trace_clk_unprepare_complete(core);
        clk_core_unprepare(core->parent);
+       clk_pm_runtime_put(core);
 }
 
 static void clk_core_unprepare_lock(struct clk_core *core)
index ef2a445..373e943 100644 (file)
@@ -135,6 +135,7 @@ static struct device_node *ti_find_clock_provider(struct device_node *from,
                        continue;
 
                if (!strncmp(n, tmp, strlen(tmp))) {
+                       of_node_get(np);
                        found = true;
                        break;
                }
index 7820c4e..69b3d61 100644 (file)
@@ -532,7 +532,7 @@ static unsigned int __resolve_freq(struct cpufreq_policy *policy,
 
        target_freq = clamp_val(target_freq, policy->min, policy->max);
 
-       if (!cpufreq_driver->target_index)
+       if (!policy->freq_table)
                return target_freq;
 
        idx = cpufreq_frequency_table_target(policy, target_freq, relation);
index 205acb2..e3885c9 100644 (file)
@@ -295,7 +295,8 @@ void dma_resv_add_fence(struct dma_resv *obj, struct dma_fence *fence,
                enum dma_resv_usage old_usage;
 
                dma_resv_list_entry(fobj, i, obj, &old, &old_usage);
-               if ((old->context == fence->context && old_usage >= usage) ||
+               if ((old->context == fence->context && old_usage >= usage &&
+                    dma_fence_is_later(fence, old)) ||
                    dma_fence_is_signaled(old)) {
                        dma_resv_list_set(fobj, i, fence, usage);
                        dma_fence_put(old);
index d4f1e4e..85e0070 100644 (file)
@@ -31,14 +31,14 @@ struct udma_dev *of_xudma_dev_get(struct device_node *np, const char *property)
        }
 
        pdev = of_find_device_by_node(udma_node);
+       if (np != udma_node)
+               of_node_put(udma_node);
+
        if (!pdev) {
                pr_debug("UDMA device not found\n");
                return ERR_PTR(-EPROBE_DEFER);
        }
 
-       if (np != udma_node)
-               of_node_put(udma_node);
-
        ud = platform_get_drvdata(pdev);
        if (!ud) {
                pr_debug("UDMA has not been probed\n");
index 6276934..8cd4e69 100644 (file)
@@ -3040,9 +3040,10 @@ static int xilinx_dma_probe(struct platform_device *pdev)
 
        /* Request and map I/O memory */
        xdev->regs = devm_platform_ioremap_resource(pdev, 0);
-       if (IS_ERR(xdev->regs))
-               return PTR_ERR(xdev->regs);
-
+       if (IS_ERR(xdev->regs)) {
+               err = PTR_ERR(xdev->regs);
+               goto disable_clks;
+       }
        /* Retrieve the DMA engine properties from the device tree */
        xdev->max_buffer_len = GENMASK(XILINX_DMA_MAX_TRANS_LEN_MAX - 1, 0);
        xdev->s2mm_chan_id = xdev->dma_config->max_channels / 2;
@@ -3070,7 +3071,7 @@ static int xilinx_dma_probe(struct platform_device *pdev)
                if (err < 0) {
                        dev_err(xdev->dev,
                                "missing xlnx,num-fstores property\n");
-                       return err;
+                       goto disable_clks;
                }
 
                err = of_property_read_u32(node, "xlnx,flush-fsync",
@@ -3090,7 +3091,11 @@ static int xilinx_dma_probe(struct platform_device *pdev)
                xdev->ext_addr = false;
 
        /* Set the dma mask bits */
-       dma_set_mask_and_coherent(xdev->dev, DMA_BIT_MASK(addr_width));
+       err = dma_set_mask_and_coherent(xdev->dev, DMA_BIT_MASK(addr_width));
+       if (err < 0) {
+               dev_err(xdev->dev, "DMA mask error %d\n", err);
+               goto disable_clks;
+       }
 
        /* Initialize the DMA engine */
        xdev->common.dev = &pdev->dev;
@@ -3137,7 +3142,7 @@ static int xilinx_dma_probe(struct platform_device *pdev)
        for_each_child_of_node(node, child) {
                err = xilinx_dma_child_probe(xdev, child);
                if (err < 0)
-                       goto disable_clks;
+                       goto error;
        }
 
        if (xdev->dma_config->dmatype == XDMA_TYPE_VDMA) {
@@ -3172,12 +3177,12 @@ static int xilinx_dma_probe(struct platform_device *pdev)
 
        return 0;
 
-disable_clks:
-       xdma_disable_allclks(xdev);
 error:
        for (i = 0; i < xdev->dma_config->max_channels; i++)
                if (xdev->chan[i])
                        xilinx_dma_chan_remove(xdev->chan[i]);
+disable_clks:
+       xdma_disable_allclks(xdev);
 
        return err;
 }
index dc299ab..3f4ee39 100644 (file)
@@ -849,7 +849,7 @@ static struct dma_async_tx_descriptor *zynqmp_dma_prep_memcpy(
 
        zynqmp_dma_desc_config_eod(chan, desc);
        async_tx_ack(&first->async_tx);
-       first->async_tx.flags = flags;
+       first->async_tx.flags = (enum dma_ctrl_flags)flags;
        return &first->async_tx;
 }
 
index f191a1f..0eb6b61 100644 (file)
@@ -630,7 +630,7 @@ static int __init dmi_smbios3_present(const u8 *buf)
 {
        if (memcmp(buf, "_SM3_", 5) == 0 &&
            buf[6] < 32 && dmi_checksum(buf, buf[6])) {
-               dmi_ver = get_unaligned_be32(buf + 6) & 0xFFFFFF;
+               dmi_ver = get_unaligned_be24(buf + 7);
                dmi_num = 0;                    /* No longer specified */
                dmi_len = get_unaligned_le32(buf + 12);
                dmi_base = get_unaligned_le64(buf + 16);
index a415518..74cc71b 100644 (file)
@@ -164,6 +164,7 @@ static void dio48e_irq_mask(struct irq_data *data)
                dio48egpio->irq_mask &= ~BIT(0);
        else
                dio48egpio->irq_mask &= ~BIT(1);
+       gpiochip_disable_irq(chip, offset);
 
        if (!dio48egpio->irq_mask)
                /* disable interrupts */
@@ -191,6 +192,7 @@ static void dio48e_irq_unmask(struct irq_data *data)
                iowrite8(0x00, &dio48egpio->reg->enable_interrupt);
        }
 
+       gpiochip_enable_irq(chip, offset);
        if (offset == 19)
                dio48egpio->irq_mask |= BIT(0);
        else
@@ -213,12 +215,14 @@ static int dio48e_irq_set_type(struct irq_data *data, unsigned int flow_type)
        return 0;
 }
 
-static struct irq_chip dio48e_irqchip = {
+static const struct irq_chip dio48e_irqchip = {
        .name = "104-dio-48e",
        .irq_ack = dio48e_irq_ack,
        .irq_mask = dio48e_irq_mask,
        .irq_unmask = dio48e_irq_unmask,
-       .irq_set_type = dio48e_irq_set_type
+       .irq_set_type = dio48e_irq_set_type,
+       .flags = IRQCHIP_IMMUTABLE,
+       GPIOCHIP_IRQ_RESOURCE_HELPERS,
 };
 
 static irqreturn_t dio48e_irq_handler(int irq, void *dev_id)
@@ -322,7 +326,7 @@ static int dio48e_probe(struct device *dev, unsigned int id)
        dio48egpio->chip.set_multiple = dio48e_gpio_set_multiple;
 
        girq = &dio48egpio->chip.irq;
-       girq->chip = &dio48e_irqchip;
+       gpio_irq_chip_set_chip(girq, &dio48e_irqchip);
        /* This will let us handle the parent IRQ in the driver */
        girq->parent_handler = NULL;
        girq->num_parents = 0;
index 40be76e..3286b91 100644 (file)
@@ -113,6 +113,7 @@ static void idi_48_irq_mask(struct irq_data *data)
        spin_lock_irqsave(&idi48gpio->lock, flags);
 
        idi48gpio->irq_mask[boundary] &= ~mask;
+       gpiochip_disable_irq(chip, offset);
 
        /* Exit early if there are still input lines with IRQ unmasked */
        if (idi48gpio->irq_mask[boundary])
@@ -140,6 +141,7 @@ static void idi_48_irq_unmask(struct irq_data *data)
 
        prev_irq_mask = idi48gpio->irq_mask[boundary];
 
+       gpiochip_enable_irq(chip, offset);
        idi48gpio->irq_mask[boundary] |= mask;
 
        /* Exit early if IRQ was already unmasked for this boundary */
@@ -164,12 +166,14 @@ static int idi_48_irq_set_type(struct irq_data *data, unsigned int flow_type)
        return 0;
 }
 
-static struct irq_chip idi_48_irqchip = {
+static const struct irq_chip idi_48_irqchip = {
        .name = "104-idi-48",
        .irq_ack = idi_48_irq_ack,
        .irq_mask = idi_48_irq_mask,
        .irq_unmask = idi_48_irq_unmask,
-       .irq_set_type = idi_48_irq_set_type
+       .irq_set_type = idi_48_irq_set_type,
+       .flags = IRQCHIP_IMMUTABLE,
+       GPIOCHIP_IRQ_RESOURCE_HELPERS,
 };
 
 static irqreturn_t idi_48_irq_handler(int irq, void *dev_id)
@@ -267,7 +271,7 @@ static int idi_48_probe(struct device *dev, unsigned int id)
        idi48gpio->chip.get_multiple = idi_48_gpio_get_multiple;
 
        girq = &idi48gpio->chip.irq;
-       girq->chip = &idi_48_irqchip;
+       gpio_irq_chip_set_chip(girq, &idi_48_irqchip);
        /* This will let us handle the parent IRQ in the driver */
        girq->parent_handler = NULL;
        girq->num_parents = 0;
index 65a5f58..4756e58 100644 (file)
@@ -174,10 +174,11 @@ static void idio_16_irq_mask(struct irq_data *data)
 {
        struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
        struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
-       const unsigned long mask = BIT(irqd_to_hwirq(data));
+       const unsigned long offset = irqd_to_hwirq(data);
        unsigned long flags;
 
-       idio16gpio->irq_mask &= ~mask;
+       idio16gpio->irq_mask &= ~BIT(offset);
+       gpiochip_disable_irq(chip, offset);
 
        if (!idio16gpio->irq_mask) {
                raw_spin_lock_irqsave(&idio16gpio->lock, flags);
@@ -192,11 +193,12 @@ static void idio_16_irq_unmask(struct irq_data *data)
 {
        struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
        struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
-       const unsigned long mask = BIT(irqd_to_hwirq(data));
+       const unsigned long offset = irqd_to_hwirq(data);
        const unsigned long prev_irq_mask = idio16gpio->irq_mask;
        unsigned long flags;
 
-       idio16gpio->irq_mask |= mask;
+       gpiochip_enable_irq(chip, offset);
+       idio16gpio->irq_mask |= BIT(offset);
 
        if (!prev_irq_mask) {
                raw_spin_lock_irqsave(&idio16gpio->lock, flags);
@@ -217,12 +219,14 @@ static int idio_16_irq_set_type(struct irq_data *data, unsigned int flow_type)
        return 0;
 }
 
-static struct irq_chip idio_16_irqchip = {
+static const struct irq_chip idio_16_irqchip = {
        .name = "104-idio-16",
        .irq_ack = idio_16_irq_ack,
        .irq_mask = idio_16_irq_mask,
        .irq_unmask = idio_16_irq_unmask,
-       .irq_set_type = idio_16_irq_set_type
+       .irq_set_type = idio_16_irq_set_type,
+       .flags = IRQCHIP_IMMUTABLE,
+       GPIOCHIP_IRQ_RESOURCE_HELPERS,
 };
 
 static irqreturn_t idio_16_irq_handler(int irq, void *dev_id)
@@ -299,7 +303,7 @@ static int idio_16_probe(struct device *dev, unsigned int id)
        idio16gpio->out_state = 0xFFFF;
 
        girq = &idio16gpio->chip.irq;
-       girq->chip = &idio_16_irqchip;
+       gpio_irq_chip_set_chip(girq, &idio_16_irqchip);
        /* This will let us handle the parent IRQ in the driver */
        girq->parent_handler = NULL;
        girq->num_parents = 0;
index f422c3e..f77a965 100644 (file)
  * struct ftgpio_gpio - Gemini GPIO state container
  * @dev: containing device for this instance
  * @gc: gpiochip for this instance
- * @irq: irqchip for this instance
  * @base: remapped I/O-memory base
  * @clk: silicon clock
  */
 struct ftgpio_gpio {
        struct device *dev;
        struct gpio_chip gc;
-       struct irq_chip irq;
        void __iomem *base;
        struct clk *clk;
 };
@@ -70,6 +68,7 @@ static void ftgpio_gpio_mask_irq(struct irq_data *d)
        val = readl(g->base + GPIO_INT_EN);
        val &= ~BIT(irqd_to_hwirq(d));
        writel(val, g->base + GPIO_INT_EN);
+       gpiochip_disable_irq(gc, irqd_to_hwirq(d));
 }
 
 static void ftgpio_gpio_unmask_irq(struct irq_data *d)
@@ -78,6 +77,7 @@ static void ftgpio_gpio_unmask_irq(struct irq_data *d)
        struct ftgpio_gpio *g = gpiochip_get_data(gc);
        u32 val;
 
+       gpiochip_enable_irq(gc, irqd_to_hwirq(d));
        val = readl(g->base + GPIO_INT_EN);
        val |= BIT(irqd_to_hwirq(d));
        writel(val, g->base + GPIO_INT_EN);
@@ -221,6 +221,16 @@ static int ftgpio_gpio_set_config(struct gpio_chip *gc, unsigned int offset,
        return 0;
 }
 
+static const struct irq_chip ftgpio_irq_chip = {
+       .name = "FTGPIO010",
+       .irq_ack = ftgpio_gpio_ack_irq,
+       .irq_mask = ftgpio_gpio_mask_irq,
+       .irq_unmask = ftgpio_gpio_unmask_irq,
+       .irq_set_type = ftgpio_gpio_set_irq_type,
+       .flags = IRQCHIP_IMMUTABLE,
+        GPIOCHIP_IRQ_RESOURCE_HELPERS,
+};
+
 static int ftgpio_gpio_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -277,14 +287,8 @@ static int ftgpio_gpio_probe(struct platform_device *pdev)
        if (!IS_ERR(g->clk))
                g->gc.set_config = ftgpio_gpio_set_config;
 
-       g->irq.name = "FTGPIO010";
-       g->irq.irq_ack = ftgpio_gpio_ack_irq;
-       g->irq.irq_mask = ftgpio_gpio_mask_irq;
-       g->irq.irq_unmask = ftgpio_gpio_unmask_irq;
-       g->irq.irq_set_type = ftgpio_gpio_set_irq_type;
-
        girq = &g->gc.irq;
-       girq->chip = &g->irq;
+       gpio_irq_chip_set_chip(girq, &ftgpio_irq_chip);
        girq->parent_handler = ftgpio_gpio_irq_handler;
        girq->num_parents = 1;
        girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents),
index 312309b..56656fb 100644 (file)
@@ -63,6 +63,14 @@ static void ixp4xx_gpio_irq_ack(struct irq_data *d)
        __raw_writel(BIT(d->hwirq), g->base + IXP4XX_REG_GPIS);
 }
 
+static void ixp4xx_gpio_mask_irq(struct irq_data *d)
+{
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+
+       irq_chip_mask_parent(d);
+       gpiochip_disable_irq(gc, d->hwirq);
+}
+
 static void ixp4xx_gpio_irq_unmask(struct irq_data *d)
 {
        struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
@@ -72,6 +80,7 @@ static void ixp4xx_gpio_irq_unmask(struct irq_data *d)
        if (!(g->irq_edge & BIT(d->hwirq)))
                ixp4xx_gpio_irq_ack(d);
 
+       gpiochip_enable_irq(gc, d->hwirq);
        irq_chip_unmask_parent(d);
 }
 
@@ -149,12 +158,14 @@ static int ixp4xx_gpio_irq_set_type(struct irq_data *d, unsigned int type)
        return irq_chip_set_type_parent(d, IRQ_TYPE_LEVEL_HIGH);
 }
 
-static struct irq_chip ixp4xx_gpio_irqchip = {
+static const struct irq_chip ixp4xx_gpio_irqchip = {
        .name = "IXP4GPIO",
        .irq_ack = ixp4xx_gpio_irq_ack,
-       .irq_mask = irq_chip_mask_parent,
+       .irq_mask = ixp4xx_gpio_mask_irq,
        .irq_unmask = ixp4xx_gpio_irq_unmask,
        .irq_set_type = ixp4xx_gpio_irq_set_type,
+       .flags = IRQCHIP_IMMUTABLE,
+       GPIOCHIP_IRQ_RESOURCE_HELPERS,
 };
 
 static int ixp4xx_gpio_child_to_parent_hwirq(struct gpio_chip *gc,
@@ -263,7 +274,7 @@ static int ixp4xx_gpio_probe(struct platform_device *pdev)
        g->gc.owner = THIS_MODULE;
 
        girq = &g->gc.irq;
-       girq->chip = &ixp4xx_gpio_irqchip;
+       gpio_irq_chip_set_chip(girq, &ixp4xx_gpio_irqchip);
        girq->fwnode = g->fwnode;
        girq->parent_domain = parent;
        girq->child_to_parent_hwirq = ixp4xx_gpio_child_to_parent_hwirq;
index 8943cea..523dfd1 100644 (file)
@@ -373,6 +373,13 @@ static void gpio_mockup_debugfs_setup(struct device *dev,
        }
 }
 
+static void gpio_mockup_debugfs_cleanup(void *data)
+{
+       struct gpio_mockup_chip *chip = data;
+
+       debugfs_remove_recursive(chip->dbg_dir);
+}
+
 static void gpio_mockup_dispose_mappings(void *data)
 {
        struct gpio_mockup_chip *chip = data;
@@ -455,7 +462,7 @@ static int gpio_mockup_probe(struct platform_device *pdev)
 
        gpio_mockup_debugfs_setup(dev, chip);
 
-       return 0;
+       return devm_add_action_or_reset(dev, gpio_mockup_debugfs_cleanup, chip);
 }
 
 static const struct of_device_id gpio_mockup_of_match[] = {
@@ -526,8 +533,10 @@ static int __init gpio_mockup_register_chip(int idx)
        }
 
        fwnode = fwnode_create_software_node(properties, NULL);
-       if (IS_ERR(fwnode))
+       if (IS_ERR(fwnode)) {
+               kfree_strarray(line_names, ngpio);
                return PTR_ERR(fwnode);
+       }
 
        pdevinfo.name = "gpio-mockup";
        pdevinfo.id = idx;
@@ -590,9 +599,9 @@ static int __init gpio_mockup_init(void)
 
 static void __exit gpio_mockup_exit(void)
 {
+       gpio_mockup_unregister_pdevs();
        debugfs_remove_recursive(gpio_mockup_dbg_dir);
        platform_driver_unregister(&gpio_mockup_driver);
-       gpio_mockup_unregister_pdevs();
 }
 
 module_init(gpio_mockup_init);
index 1504982..3eb08cd 100644 (file)
@@ -169,6 +169,7 @@ static int mpc8xxx_irq_set_type(struct irq_data *d, unsigned int flow_type)
 
        switch (flow_type) {
        case IRQ_TYPE_EDGE_FALLING:
+       case IRQ_TYPE_LEVEL_LOW:
                raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
                gc->write_reg(mpc8xxx_gc->regs + GPIO_ICR,
                        gc->read_reg(mpc8xxx_gc->regs + GPIO_ICR)
index d8a26e5..f163f5c 100644 (file)
@@ -112,6 +112,8 @@ mediatek_gpio_irq_unmask(struct irq_data *d)
        unsigned long flags;
        u32 rise, fall, high, low;
 
+       gpiochip_enable_irq(gc, d->hwirq);
+
        spin_lock_irqsave(&rg->lock, flags);
        rise = mtk_gpio_r32(rg, GPIO_REG_REDGE);
        fall = mtk_gpio_r32(rg, GPIO_REG_FEDGE);
@@ -143,6 +145,8 @@ mediatek_gpio_irq_mask(struct irq_data *d)
        mtk_gpio_w32(rg, GPIO_REG_HLVL, high & ~BIT(pin));
        mtk_gpio_w32(rg, GPIO_REG_LLVL, low & ~BIT(pin));
        spin_unlock_irqrestore(&rg->lock, flags);
+
+       gpiochip_disable_irq(gc, d->hwirq);
 }
 
 static int
@@ -204,6 +208,16 @@ mediatek_gpio_xlate(struct gpio_chip *chip,
        return gpio % MTK_BANK_WIDTH;
 }
 
+static const struct irq_chip mt7621_irq_chip = {
+       .name           = "mt7621-gpio",
+       .irq_mask_ack   = mediatek_gpio_irq_mask,
+       .irq_mask       = mediatek_gpio_irq_mask,
+       .irq_unmask     = mediatek_gpio_irq_unmask,
+       .irq_set_type   = mediatek_gpio_irq_type,
+       .flags          = IRQCHIP_IMMUTABLE,
+       GPIOCHIP_IRQ_RESOURCE_HELPERS,
+};
+
 static int
 mediatek_gpio_bank_probe(struct device *dev, int bank)
 {
@@ -238,11 +252,6 @@ mediatek_gpio_bank_probe(struct device *dev, int bank)
                return -ENOMEM;
 
        rg->chip.offset = bank * MTK_BANK_WIDTH;
-       rg->irq_chip.name = dev_name(dev);
-       rg->irq_chip.irq_unmask = mediatek_gpio_irq_unmask;
-       rg->irq_chip.irq_mask = mediatek_gpio_irq_mask;
-       rg->irq_chip.irq_mask_ack = mediatek_gpio_irq_mask;
-       rg->irq_chip.irq_set_type = mediatek_gpio_irq_type;
 
        if (mtk->gpio_irq) {
                struct gpio_irq_chip *girq;
@@ -262,7 +271,7 @@ mediatek_gpio_bank_probe(struct device *dev, int bank)
                }
 
                girq = &rg->chip.irq;
-               girq->chip = &rg->irq_chip;
+               gpio_irq_chip_set_chip(girq, &mt7621_irq_chip);
                /* This will let us handle the parent IRQ in the driver */
                girq->parent_handler = NULL;
                girq->num_parents = 0;
index ecd7d16..2925f4d 100644 (file)
@@ -1175,7 +1175,9 @@ static int pca953x_suspend(struct device *dev)
 {
        struct pca953x_chip *chip = dev_get_drvdata(dev);
 
+       mutex_lock(&chip->i2c_lock);
        regcache_cache_only(chip->regmap, true);
+       mutex_unlock(&chip->i2c_lock);
 
        if (atomic_read(&chip->wakeup_path))
                device_set_wakeup_path(dev);
@@ -1198,13 +1200,17 @@ static int pca953x_resume(struct device *dev)
                }
        }
 
+       mutex_lock(&chip->i2c_lock);
        regcache_cache_only(chip->regmap, false);
        regcache_mark_dirty(chip->regmap);
        ret = pca953x_regcache_sync(dev);
-       if (ret)
+       if (ret) {
+               mutex_unlock(&chip->i2c_lock);
                return ret;
+       }
 
        ret = regcache_sync(chip->regmap);
+       mutex_unlock(&chip->i2c_lock);
        if (ret) {
                dev_err(dev, "Failed to restore register map: %d\n", ret);
                return ret;
index c7fbfa3..1198ab0 100644 (file)
@@ -661,24 +661,17 @@ static int pxa_gpio_probe(struct platform_device *pdev)
        if (IS_ERR(gpio_reg_base))
                return PTR_ERR(gpio_reg_base);
 
-       clk = clk_get(&pdev->dev, NULL);
+       clk = devm_clk_get_enabled(&pdev->dev, NULL);
        if (IS_ERR(clk)) {
                dev_err(&pdev->dev, "Error %ld to get gpio clock\n",
                        PTR_ERR(clk));
                return PTR_ERR(clk);
        }
-       ret = clk_prepare_enable(clk);
-       if (ret) {
-               clk_put(clk);
-               return ret;
-       }
 
        /* Initialize GPIO chips */
        ret = pxa_init_gpio_chip(pchip, pxa_last_gpio + 1, gpio_reg_base);
-       if (ret) {
-               clk_put(clk);
+       if (ret)
                return ret;
-       }
 
        /* clear all GPIO edge detects */
        for_each_gpio_bank(gpio, c, pchip) {
index 63dcf42..d6418f8 100644 (file)
  * @lock: Lock for accessing the IRQ registers and values
  * @intr_mask: Mask for interrupts lines
  * @intr_type: Interrupt type selection
+ * @bank_read: Read a bank setting as a single 32-bit value
+ * @bank_write: Write a bank setting as a single 32-bit value
+ * @imr_line_pos: Bit shift of an IRQ line's IMR value.
+ *
+ * The DIR, DATA, and ISR registers consist of four 8-bit port values, packed
+ * into a single 32-bit register. Use @bank_read (@bank_write) to get (assign)
+ * a value from (to) these registers. The IMR register consists of four 16-bit
+ * port values, packed into two 32-bit registers. Use @imr_line_pos to get the
+ * bit shift of the 2-bit field for a line's IMR settings. Shifts larger than
+ * 32 overflow into the second register.
  *
  * Because the interrupt mask register (IMR) combines the function of IRQ type
  * selection and masking, two extra values are stored. @intr_mask is used to
- * mask/unmask the interrupts for a GPIO port, and @intr_type is used to store
+ * mask/unmask the interrupts for a GPIO line, and @intr_type is used to store
  * the selected interrupt types. The logical AND of these values is written to
  * IMR on changes.
  */
@@ -59,10 +69,11 @@ struct realtek_gpio_ctrl {
        void __iomem *cpumask_base;
        struct cpumask cpu_irq_maskable;
        raw_spinlock_t lock;
-       u16 intr_mask[REALTEK_GPIO_PORTS_PER_BANK];
-       u16 intr_type[REALTEK_GPIO_PORTS_PER_BANK];
-       unsigned int (*port_offset_u8)(unsigned int port);
-       unsigned int (*port_offset_u16)(unsigned int port);
+       u8 intr_mask[REALTEK_GPIO_MAX];
+       u8 intr_type[REALTEK_GPIO_MAX];
+       u32 (*bank_read)(void __iomem *reg);
+       void (*bank_write)(void __iomem *reg, u32 value);
+       unsigned int (*line_imr_pos)(unsigned int line);
 };
 
 /* Expand with more flags as devices with other quirks are added */
@@ -101,14 +112,22 @@ static struct realtek_gpio_ctrl *irq_data_to_ctrl(struct irq_data *data)
  * port. The two interrupt mask registers store two bits per GPIO, so use u16
  * values.
  */
-static unsigned int realtek_gpio_port_offset_u8(unsigned int port)
+static u32 realtek_gpio_bank_read_swapped(void __iomem *reg)
 {
-       return port;
+       return ioread32be(reg);
 }
 
-static unsigned int realtek_gpio_port_offset_u16(unsigned int port)
+static void realtek_gpio_bank_write_swapped(void __iomem *reg, u32 value)
 {
-       return 2 * port;
+       iowrite32be(value, reg);
+}
+
+static unsigned int realtek_gpio_line_imr_pos_swapped(unsigned int line)
+{
+       unsigned int port_pin = line % 8;
+       unsigned int port = line / 8;
+
+       return 2 * (8 * (port ^ 1) + port_pin);
 }
 
 /*
@@ -119,66 +138,67 @@ static unsigned int realtek_gpio_port_offset_u16(unsigned int port)
  * per GPIO, so use u16 values. The first register contains ports 1 and 0, the
  * second ports 3 and 2.
  */
-static unsigned int realtek_gpio_port_offset_u8_rev(unsigned int port)
+static u32 realtek_gpio_bank_read(void __iomem *reg)
 {
-       return 3 - port;
+       return ioread32(reg);
 }
 
-static unsigned int realtek_gpio_port_offset_u16_rev(unsigned int port)
+static void realtek_gpio_bank_write(void __iomem *reg, u32 value)
 {
-       return 2 * (port ^ 1);
+       iowrite32(value, reg);
 }
 
-static void realtek_gpio_write_imr(struct realtek_gpio_ctrl *ctrl,
-       unsigned int port, u16 irq_type, u16 irq_mask)
+static unsigned int realtek_gpio_line_imr_pos(unsigned int line)
 {
-       iowrite16(irq_type & irq_mask,
-               ctrl->base + REALTEK_GPIO_REG_IMR + ctrl->port_offset_u16(port));
+       return 2 * line;
 }
 
-static void realtek_gpio_clear_isr(struct realtek_gpio_ctrl *ctrl,
-       unsigned int port, u8 mask)
+static void realtek_gpio_clear_isr(struct realtek_gpio_ctrl *ctrl, u32 mask)
 {
-       iowrite8(mask, ctrl->base + REALTEK_GPIO_REG_ISR + ctrl->port_offset_u8(port));
+       ctrl->bank_write(ctrl->base + REALTEK_GPIO_REG_ISR, mask);
 }
 
-static u8 realtek_gpio_read_isr(struct realtek_gpio_ctrl *ctrl, unsigned int port)
+static u32 realtek_gpio_read_isr(struct realtek_gpio_ctrl *ctrl)
 {
-       return ioread8(ctrl->base + REALTEK_GPIO_REG_ISR + ctrl->port_offset_u8(port));
+       return ctrl->bank_read(ctrl->base + REALTEK_GPIO_REG_ISR);
 }
 
-/* Set the rising and falling edge mask bits for a GPIO port pin */
-static u16 realtek_gpio_imr_bits(unsigned int pin, u16 value)
+/* Set the rising and falling edge mask bits for a GPIO pin */
+static void realtek_gpio_update_line_imr(struct realtek_gpio_ctrl *ctrl, unsigned int line)
 {
-       return (value & REALTEK_GPIO_IMR_LINE_MASK) << 2 * pin;
+       void __iomem *reg = ctrl->base + REALTEK_GPIO_REG_IMR;
+       unsigned int line_shift = ctrl->line_imr_pos(line);
+       unsigned int shift = line_shift % 32;
+       u32 irq_type = ctrl->intr_type[line];
+       u32 irq_mask = ctrl->intr_mask[line];
+       u32 reg_val;
+
+       reg += 4 * (line_shift / 32);
+       reg_val = ioread32(reg);
+       reg_val &= ~(REALTEK_GPIO_IMR_LINE_MASK << shift);
+       reg_val |= (irq_type & irq_mask & REALTEK_GPIO_IMR_LINE_MASK) << shift;
+       iowrite32(reg_val, reg);
 }
 
 static void realtek_gpio_irq_ack(struct irq_data *data)
 {
        struct realtek_gpio_ctrl *ctrl = irq_data_to_ctrl(data);
        irq_hw_number_t line = irqd_to_hwirq(data);
-       unsigned int port = line / 8;
-       unsigned int port_pin = line % 8;
 
-       realtek_gpio_clear_isr(ctrl, port, BIT(port_pin));
+       realtek_gpio_clear_isr(ctrl, BIT(line));
 }
 
 static void realtek_gpio_irq_unmask(struct irq_data *data)
 {
        struct realtek_gpio_ctrl *ctrl = irq_data_to_ctrl(data);
        unsigned int line = irqd_to_hwirq(data);
-       unsigned int port = line / 8;
-       unsigned int port_pin = line % 8;
        unsigned long flags;
-       u16 m;
 
        gpiochip_enable_irq(&ctrl->gc, line);
 
        raw_spin_lock_irqsave(&ctrl->lock, flags);
-       m = ctrl->intr_mask[port];
-       m |= realtek_gpio_imr_bits(port_pin, REALTEK_GPIO_IMR_LINE_MASK);
-       ctrl->intr_mask[port] = m;
-       realtek_gpio_write_imr(ctrl, port, ctrl->intr_type[port], m);
+       ctrl->intr_mask[line] = REALTEK_GPIO_IMR_LINE_MASK;
+       realtek_gpio_update_line_imr(ctrl, line);
        raw_spin_unlock_irqrestore(&ctrl->lock, flags);
 }
 
@@ -186,16 +206,11 @@ static void realtek_gpio_irq_mask(struct irq_data *data)
 {
        struct realtek_gpio_ctrl *ctrl = irq_data_to_ctrl(data);
        unsigned int line = irqd_to_hwirq(data);
-       unsigned int port = line / 8;
-       unsigned int port_pin = line % 8;
        unsigned long flags;
-       u16 m;
 
        raw_spin_lock_irqsave(&ctrl->lock, flags);
-       m = ctrl->intr_mask[port];
-       m &= ~realtek_gpio_imr_bits(port_pin, REALTEK_GPIO_IMR_LINE_MASK);
-       ctrl->intr_mask[port] = m;
-       realtek_gpio_write_imr(ctrl, port, ctrl->intr_type[port], m);
+       ctrl->intr_mask[line] = 0;
+       realtek_gpio_update_line_imr(ctrl, line);
        raw_spin_unlock_irqrestore(&ctrl->lock, flags);
 
        gpiochip_disable_irq(&ctrl->gc, line);
@@ -205,10 +220,8 @@ static int realtek_gpio_irq_set_type(struct irq_data *data, unsigned int flow_ty
 {
        struct realtek_gpio_ctrl *ctrl = irq_data_to_ctrl(data);
        unsigned int line = irqd_to_hwirq(data);
-       unsigned int port = line / 8;
-       unsigned int port_pin = line % 8;
        unsigned long flags;
-       u16 type, t;
+       u8 type;
 
        switch (flow_type & IRQ_TYPE_SENSE_MASK) {
        case IRQ_TYPE_EDGE_FALLING:
@@ -227,11 +240,8 @@ static int realtek_gpio_irq_set_type(struct irq_data *data, unsigned int flow_ty
        irq_set_handler_locked(data, handle_edge_irq);
 
        raw_spin_lock_irqsave(&ctrl->lock, flags);
-       t = ctrl->intr_type[port];
-       t &= ~realtek_gpio_imr_bits(port_pin, REALTEK_GPIO_IMR_LINE_MASK);
-       t |= realtek_gpio_imr_bits(port_pin, type);
-       ctrl->intr_type[port] = t;
-       realtek_gpio_write_imr(ctrl, port, t, ctrl->intr_mask[port]);
+       ctrl->intr_type[line] = type;
+       realtek_gpio_update_line_imr(ctrl, line);
        raw_spin_unlock_irqrestore(&ctrl->lock, flags);
 
        return 0;
@@ -242,28 +252,21 @@ static void realtek_gpio_irq_handler(struct irq_desc *desc)
        struct gpio_chip *gc = irq_desc_get_handler_data(desc);
        struct realtek_gpio_ctrl *ctrl = gpiochip_get_data(gc);
        struct irq_chip *irq_chip = irq_desc_get_chip(desc);
-       unsigned int lines_done;
-       unsigned int port_pin_count;
        unsigned long status;
        int offset;
 
        chained_irq_enter(irq_chip, desc);
 
-       for (lines_done = 0; lines_done < gc->ngpio; lines_done += 8) {
-               status = realtek_gpio_read_isr(ctrl, lines_done / 8);
-               port_pin_count = min(gc->ngpio - lines_done, 8U);
-               for_each_set_bit(offset, &status, port_pin_count)
-                       generic_handle_domain_irq(gc->irq.domain, offset + lines_done);
-       }
+       status = realtek_gpio_read_isr(ctrl);
+       for_each_set_bit(offset, &status, gc->ngpio)
+               generic_handle_domain_irq(gc->irq.domain, offset);
 
        chained_irq_exit(irq_chip, desc);
 }
 
-static inline void __iomem *realtek_gpio_irq_cpu_mask(struct realtek_gpio_ctrl *ctrl,
-       unsigned int port, int cpu)
+static inline void __iomem *realtek_gpio_irq_cpu_mask(struct realtek_gpio_ctrl *ctrl, int cpu)
 {
-       return ctrl->cpumask_base + ctrl->port_offset_u8(port) +
-               REALTEK_GPIO_PORTS_PER_BANK * cpu;
+       return ctrl->cpumask_base + REALTEK_GPIO_PORTS_PER_BANK * cpu;
 }
 
 static int realtek_gpio_irq_set_affinity(struct irq_data *data,
@@ -271,12 +274,10 @@ static int realtek_gpio_irq_set_affinity(struct irq_data *data,
 {
        struct realtek_gpio_ctrl *ctrl = irq_data_to_ctrl(data);
        unsigned int line = irqd_to_hwirq(data);
-       unsigned int port = line / 8;
-       unsigned int port_pin = line % 8;
        void __iomem *irq_cpu_mask;
        unsigned long flags;
        int cpu;
-       u8 v;
+       u32 v;
 
        if (!ctrl->cpumask_base)
                return -ENXIO;
@@ -284,15 +285,15 @@ static int realtek_gpio_irq_set_affinity(struct irq_data *data,
        raw_spin_lock_irqsave(&ctrl->lock, flags);
 
        for_each_cpu(cpu, &ctrl->cpu_irq_maskable) {
-               irq_cpu_mask = realtek_gpio_irq_cpu_mask(ctrl, port, cpu);
-               v = ioread8(irq_cpu_mask);
+               irq_cpu_mask = realtek_gpio_irq_cpu_mask(ctrl, cpu);
+               v = ctrl->bank_read(irq_cpu_mask);
 
                if (cpumask_test_cpu(cpu, dest))
-                       v |= BIT(port_pin);
+                       v |= BIT(line);
                else
-                       v &= ~BIT(port_pin);
+                       v &= ~BIT(line);
 
-               iowrite8(v, irq_cpu_mask);
+               ctrl->bank_write(irq_cpu_mask, v);
        }
 
        raw_spin_unlock_irqrestore(&ctrl->lock, flags);
@@ -305,16 +306,17 @@ static int realtek_gpio_irq_set_affinity(struct irq_data *data,
 static int realtek_gpio_irq_init(struct gpio_chip *gc)
 {
        struct realtek_gpio_ctrl *ctrl = gpiochip_get_data(gc);
-       unsigned int port;
+       u32 mask_all = GENMASK(gc->ngpio - 1, 0);
+       unsigned int line;
        int cpu;
 
-       for (port = 0; (port * 8) < gc->ngpio; port++) {
-               realtek_gpio_write_imr(ctrl, port, 0, 0);
-               realtek_gpio_clear_isr(ctrl, port, GENMASK(7, 0));
+       for (line = 0; line < gc->ngpio; line++)
+               realtek_gpio_update_line_imr(ctrl, line);
 
-               for_each_cpu(cpu, &ctrl->cpu_irq_maskable)
-                       iowrite8(GENMASK(7, 0), realtek_gpio_irq_cpu_mask(ctrl, port, cpu));
-       }
+       realtek_gpio_clear_isr(ctrl, mask_all);
+
+       for_each_cpu(cpu, &ctrl->cpu_irq_maskable)
+               ctrl->bank_write(realtek_gpio_irq_cpu_mask(ctrl, cpu), mask_all);
 
        return 0;
 }
@@ -387,12 +389,14 @@ static int realtek_gpio_probe(struct platform_device *pdev)
 
        if (dev_flags & GPIO_PORTS_REVERSED) {
                bgpio_flags = 0;
-               ctrl->port_offset_u8 = realtek_gpio_port_offset_u8_rev;
-               ctrl->port_offset_u16 = realtek_gpio_port_offset_u16_rev;
+               ctrl->bank_read = realtek_gpio_bank_read;
+               ctrl->bank_write = realtek_gpio_bank_write;
+               ctrl->line_imr_pos = realtek_gpio_line_imr_pos;
        } else {
                bgpio_flags = BGPIOF_BIG_ENDIAN_BYTE_ORDER;
-               ctrl->port_offset_u8 = realtek_gpio_port_offset_u8;
-               ctrl->port_offset_u16 = realtek_gpio_port_offset_u16;
+               ctrl->bank_read = realtek_gpio_bank_read_swapped;
+               ctrl->bank_write = realtek_gpio_bank_write_swapped;
+               ctrl->line_imr_pos = realtek_gpio_line_imr_pos_swapped;
        }
 
        err = bgpio_init(&ctrl->gc, dev, 4,
index f91e876..bb50335 100644 (file)
@@ -419,11 +419,11 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type)
                        goto out;
                } else {
                        bank->toggle_edge_mode |= mask;
-                       level |= mask;
+                       level &= ~mask;
 
                        /*
                         * Determine gpio state. If 1 next interrupt should be
-                        * falling otherwise rising.
+                        * low otherwise high.
                         */
                        data = readl(bank->reg_base + bank->gpio_regs->ext_port);
                        if (data & mask)
index fa4bc74..e739dce 100644 (file)
@@ -307,6 +307,8 @@ static int tqmx86_gpio_probe(struct platform_device *pdev)
                girq->default_type = IRQ_TYPE_NONE;
                girq->handler = handle_simple_irq;
                girq->init_valid_mask = tqmx86_init_irq_valid_mask;
+
+               irq_domain_set_pm_device(girq->domain, dev);
        }
 
        ret = devm_gpiochip_add_data(dev, chip, gpio);
@@ -315,8 +317,6 @@ static int tqmx86_gpio_probe(struct platform_device *pdev)
                goto out_pm_dis;
        }
 
-       irq_domain_set_pm_device(girq->domain, dev);
-
        dev_info(dev, "GPIO functionality initialized with %d pins\n",
                 chip->ngpio);
 
index b098f2d..59fb106 100644 (file)
@@ -265,6 +265,7 @@ static void ws16c48_irq_mask(struct irq_data *data)
        raw_spin_lock_irqsave(&ws16c48gpio->lock, flags);
 
        ws16c48gpio->irq_mask &= ~mask;
+       gpiochip_disable_irq(chip, offset);
        port_state = ws16c48gpio->irq_mask >> (8 * port);
 
        /* Select Register Page 2; Unlock all I/O ports */
@@ -295,6 +296,7 @@ static void ws16c48_irq_unmask(struct irq_data *data)
 
        raw_spin_lock_irqsave(&ws16c48gpio->lock, flags);
 
+       gpiochip_enable_irq(chip, offset);
        ws16c48gpio->irq_mask |= mask;
        port_state = ws16c48gpio->irq_mask >> (8 * port);
 
@@ -356,12 +358,14 @@ static int ws16c48_irq_set_type(struct irq_data *data, unsigned flow_type)
        return 0;
 }
 
-static struct irq_chip ws16c48_irqchip = {
+static const struct irq_chip ws16c48_irqchip = {
        .name = "ws16c48",
        .irq_ack = ws16c48_irq_ack,
        .irq_mask = ws16c48_irq_mask,
        .irq_unmask = ws16c48_irq_unmask,
-       .irq_set_type = ws16c48_irq_set_type
+       .irq_set_type = ws16c48_irq_set_type,
+       .flags = IRQCHIP_IMMUTABLE,
+       GPIOCHIP_IRQ_RESOURCE_HELPERS,
 };
 
 static irqreturn_t ws16c48_irq_handler(int irq, void *dev_id)
@@ -463,7 +467,7 @@ static int ws16c48_probe(struct device *dev, unsigned int id)
        ws16c48gpio->chip.set_multiple = ws16c48_gpio_set_multiple;
 
        girq = &ws16c48gpio->chip.irq;
-       girq->chip = &ws16c48_irqchip;
+       gpio_irq_chip_set_chip(girq, &ws16c48_irqchip);
        /* This will let us handle the parent IRQ in the driver */
        girq->parent_handler = NULL;
        girq->num_parents = 0;
index f8041d4..92f1855 100644 (file)
@@ -1986,7 +1986,6 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip)
                ret = -ENODEV;
                goto out_free_le;
        }
-       le->irq = irq;
 
        if (eflags & GPIOEVENT_REQUEST_RISING_EDGE)
                irqflags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ?
@@ -2000,7 +1999,7 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip)
        init_waitqueue_head(&le->wait);
 
        /* Request a thread to read the events */
-       ret = request_threaded_irq(le->irq,
+       ret = request_threaded_irq(irq,
                                   lineevent_irq_handler,
                                   lineevent_irq_thread,
                                   irqflags,
@@ -2009,6 +2008,8 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip)
        if (ret)
                goto out_free_le;
 
+       le->irq = irq;
+
        fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC);
        if (fd < 0) {
                ret = fd;
index c6cc493..2b97b8a 100644 (file)
@@ -148,30 +148,22 @@ aldebaran_mode2_perform_reset(struct amdgpu_reset_control *reset_ctl,
                              struct amdgpu_reset_context *reset_context)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)reset_ctl->handle;
+       struct list_head *reset_device_list = reset_context->reset_device_list;
        struct amdgpu_device *tmp_adev = NULL;
-       struct list_head reset_device_list;
        int r = 0;
 
        dev_dbg(adev->dev, "aldebaran perform hw reset\n");
+
+       if (reset_device_list == NULL)
+               return -EINVAL;
+
        if (adev->ip_versions[MP1_HWIP][0] == IP_VERSION(13, 0, 2) &&
            reset_context->hive == NULL) {
                /* Wrong context, return error */
                return -EINVAL;
        }
 
-       INIT_LIST_HEAD(&reset_device_list);
-       if (reset_context->hive) {
-               list_for_each_entry (tmp_adev,
-                                    &reset_context->hive->device_list,
-                                    gmc.xgmi.head)
-                       list_add_tail(&tmp_adev->reset_list,
-                                     &reset_device_list);
-       } else {
-               list_add_tail(&reset_context->reset_req_dev->reset_list,
-                             &reset_device_list);
-       }
-
-       list_for_each_entry (tmp_adev, &reset_device_list, reset_list) {
+       list_for_each_entry(tmp_adev, reset_device_list, reset_list) {
                mutex_lock(&tmp_adev->reset_cntl->reset_lock);
                tmp_adev->reset_cntl->active_reset = AMD_RESET_METHOD_MODE2;
        }
@@ -179,7 +171,7 @@ aldebaran_mode2_perform_reset(struct amdgpu_reset_control *reset_ctl,
         * Mode2 reset doesn't need any sync between nodes in XGMI hive, instead launch
         * them together so that they can be completed asynchronously on multiple nodes
         */
-       list_for_each_entry (tmp_adev, &reset_device_list, reset_list) {
+       list_for_each_entry(tmp_adev, reset_device_list, reset_list) {
                /* For XGMI run all resets in parallel to speed up the process */
                if (tmp_adev->gmc.xgmi.num_physical_nodes > 1) {
                        if (!queue_work(system_unbound_wq,
@@ -197,7 +189,7 @@ aldebaran_mode2_perform_reset(struct amdgpu_reset_control *reset_ctl,
 
        /* For XGMI wait for all resets to complete before proceed */
        if (!r) {
-               list_for_each_entry (tmp_adev, &reset_device_list, reset_list) {
+               list_for_each_entry(tmp_adev, reset_device_list, reset_list) {
                        if (tmp_adev->gmc.xgmi.num_physical_nodes > 1) {
                                flush_work(&tmp_adev->reset_cntl->reset_work);
                                r = tmp_adev->asic_reset_res;
@@ -207,7 +199,7 @@ aldebaran_mode2_perform_reset(struct amdgpu_reset_control *reset_ctl,
                }
        }
 
-       list_for_each_entry (tmp_adev, &reset_device_list, reset_list) {
+       list_for_each_entry(tmp_adev, reset_device_list, reset_list) {
                mutex_unlock(&tmp_adev->reset_cntl->reset_lock);
                tmp_adev->reset_cntl->active_reset = AMD_RESET_METHOD_NONE;
        }
@@ -339,10 +331,13 @@ static int
 aldebaran_mode2_restore_hwcontext(struct amdgpu_reset_control *reset_ctl,
                                  struct amdgpu_reset_context *reset_context)
 {
+       struct list_head *reset_device_list = reset_context->reset_device_list;
        struct amdgpu_device *tmp_adev = NULL;
-       struct list_head reset_device_list;
        int r;
 
+       if (reset_device_list == NULL)
+               return -EINVAL;
+
        if (reset_context->reset_req_dev->ip_versions[MP1_HWIP][0] ==
                    IP_VERSION(13, 0, 2) &&
            reset_context->hive == NULL) {
@@ -350,19 +345,7 @@ aldebaran_mode2_restore_hwcontext(struct amdgpu_reset_control *reset_ctl,
                return -EINVAL;
        }
 
-       INIT_LIST_HEAD(&reset_device_list);
-       if (reset_context->hive) {
-               list_for_each_entry (tmp_adev,
-                                    &reset_context->hive->device_list,
-                                    gmc.xgmi.head)
-                       list_add_tail(&tmp_adev->reset_list,
-                                     &reset_device_list);
-       } else {
-               list_add_tail(&reset_context->reset_req_dev->reset_list,
-                             &reset_device_list);
-       }
-
-       list_for_each_entry (tmp_adev, &reset_device_list, reset_list) {
+       list_for_each_entry(tmp_adev, reset_device_list, reset_list) {
                dev_info(tmp_adev->dev,
                         "GPU reset succeeded, trying to resume\n");
                r = aldebaran_mode2_restore_ip(tmp_adev);
index e146810..d597e26 100644 (file)
@@ -317,7 +317,7 @@ enum amdgpu_kiq_irq {
        AMDGPU_CP_KIQ_IRQ_DRIVER0 = 0,
        AMDGPU_CP_KIQ_IRQ_LAST
 };
-
+#define SRIOV_USEC_TIMEOUT  1200000 /* wait 12 * 100ms for SRIOV */
 #define MAX_KIQ_REG_WAIT       5000 /* in usecs, 5ms */
 #define MAX_KIQ_REG_BAILOUT_INTERVAL   5 /* in msecs, 5ms */
 #define MAX_KIQ_REG_TRY 1000
index 3c09dcc..647220a 100644 (file)
@@ -96,6 +96,7 @@ struct amdgpu_amdkfd_fence {
 struct amdgpu_kfd_dev {
        struct kfd_dev *dev;
        uint64_t vram_used;
+       uint64_t vram_used_aligned;
        bool init_complete;
        struct work_struct reset_work;
 };
index a699134..2170db8 100644 (file)
 #define AMDGPU_USERPTR_RESTORE_DELAY_MS 1
 
 /*
- * Align VRAM allocations to 2MB to avoid fragmentation caused by 4K allocations in the tail 2MB
+ * Align VRAM availability to 2MB to avoid fragmentation caused by 4K allocations in the tail 2MB
  * BO chunk
  */
-#define VRAM_ALLOCATION_ALIGN (1 << 21)
+#define VRAM_AVAILABLITY_ALIGN (1 << 21)
 
 /* Impose limit on how much memory KFD can use */
 static struct {
@@ -149,7 +149,7 @@ int amdgpu_amdkfd_reserve_mem_limit(struct amdgpu_device *adev,
                 * to avoid fragmentation caused by 4K allocations in the tail
                 * 2M BO chunk.
                 */
-               vram_needed = ALIGN(size, VRAM_ALLOCATION_ALIGN);
+               vram_needed = size;
        } else if (alloc_flag & KFD_IOC_ALLOC_MEM_FLAGS_USERPTR) {
                system_mem_needed = size;
        } else if (!(alloc_flag &
@@ -182,8 +182,10 @@ int amdgpu_amdkfd_reserve_mem_limit(struct amdgpu_device *adev,
         */
        WARN_ONCE(vram_needed && !adev,
                  "adev reference can't be null when vram is used");
-       if (adev)
+       if (adev) {
                adev->kfd.vram_used += vram_needed;
+               adev->kfd.vram_used_aligned += ALIGN(vram_needed, VRAM_AVAILABLITY_ALIGN);
+       }
        kfd_mem_limit.system_mem_used += system_mem_needed;
        kfd_mem_limit.ttm_mem_used += ttm_mem_needed;
 
@@ -203,8 +205,10 @@ void amdgpu_amdkfd_unreserve_mem_limit(struct amdgpu_device *adev,
        } else if (alloc_flag & KFD_IOC_ALLOC_MEM_FLAGS_VRAM) {
                WARN_ONCE(!adev,
                          "adev reference can't be null when alloc mem flags vram is set");
-               if (adev)
-                       adev->kfd.vram_used -= ALIGN(size, VRAM_ALLOCATION_ALIGN);
+               if (adev) {
+                       adev->kfd.vram_used -= size;
+                       adev->kfd.vram_used_aligned -= ALIGN(size, VRAM_AVAILABLITY_ALIGN);
+               }
        } else if (alloc_flag & KFD_IOC_ALLOC_MEM_FLAGS_USERPTR) {
                kfd_mem_limit.system_mem_used -= size;
        } else if (!(alloc_flag &
@@ -1608,15 +1612,14 @@ size_t amdgpu_amdkfd_get_available_memory(struct amdgpu_device *adev)
        uint64_t reserved_for_pt =
                ESTIMATE_PT_SIZE(amdgpu_amdkfd_total_mem_size);
        size_t available;
-
        spin_lock(&kfd_mem_limit.mem_limit_lock);
        available = adev->gmc.real_vram_size
-               - adev->kfd.vram_used
+               - adev->kfd.vram_used_aligned
                - atomic64_read(&adev->vram_pin_size)
                - reserved_for_pt;
        spin_unlock(&kfd_mem_limit.mem_limit_lock);
 
-       return ALIGN_DOWN(available, VRAM_ALLOCATION_ALIGN);
+       return ALIGN_DOWN(available, VRAM_AVAILABLITY_ALIGN);
 }
 
 int amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu(
@@ -1725,7 +1728,7 @@ int amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu(
        add_kgd_mem_to_kfd_bo_list(*mem, avm->process_info, user_addr);
 
        if (user_addr) {
-               pr_debug("creating userptr BO for user_addr = %llu\n", user_addr);
+               pr_debug("creating userptr BO for user_addr = %llx\n", user_addr);
                ret = init_user_pages(*mem, user_addr, criu_resume);
                if (ret)
                        goto allocate_init_user_pages_failed;
index fd8f373..b81b77a 100644 (file)
@@ -314,7 +314,7 @@ amdgpu_atomfirmware_get_vram_info(struct amdgpu_device *adev,
                                        mem_channel_number = vram_info->v30.channel_num;
                                        mem_channel_width = vram_info->v30.channel_width;
                                        if (vram_width)
-                                               *vram_width = mem_channel_number * mem_channel_width;
+                                               *vram_width = mem_channel_number * (1 << mem_channel_width);
                                        break;
                                default:
                                        return -EINVAL;
index d8f1335..b7bae83 100644 (file)
@@ -837,16 +837,12 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p)
                        continue;
 
                r = amdgpu_vm_bo_update(adev, bo_va, false);
-               if (r) {
-                       mutex_unlock(&p->bo_list->bo_list_mutex);
+               if (r)
                        return r;
-               }
 
                r = amdgpu_sync_fence(&p->job->sync, bo_va->last_pt_update);
-               if (r) {
-                       mutex_unlock(&p->bo_list->bo_list_mutex);
+               if (r)
                        return r;
-               }
        }
 
        r = amdgpu_vm_handle_moved(adev, vm);
index e2eec98..cb00c7d 100644 (file)
@@ -1705,7 +1705,7 @@ static ssize_t amdgpu_reset_dump_register_list_write(struct file *f,
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)file_inode(f)->i_private;
        char reg_offset[11];
-       uint32_t *new, *tmp = NULL;
+       uint32_t *new = NULL, *tmp = NULL;
        int ret, i = 0, len = 0;
 
        do {
@@ -1747,7 +1747,8 @@ static ssize_t amdgpu_reset_dump_register_list_write(struct file *f,
        ret = size;
 
 error_free:
-       kfree(tmp);
+       if (tmp != new)
+               kfree(tmp);
        kfree(new);
        return ret;
 }
index c4a6fe3..be7aff2 100644 (file)
@@ -2365,8 +2365,16 @@ static int amdgpu_device_ip_init(struct amdgpu_device *adev)
                }
                adev->ip_blocks[i].status.sw = true;
 
-               /* need to do gmc hw init early so we can allocate gpu mem */
-               if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC) {
+               if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_COMMON) {
+                       /* need to do common hw init early so everything is set up for gmc */
+                       r = adev->ip_blocks[i].version->funcs->hw_init((void *)adev);
+                       if (r) {
+                               DRM_ERROR("hw_init %d failed %d\n", i, r);
+                               goto init_failed;
+                       }
+                       adev->ip_blocks[i].status.hw = true;
+               } else if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC) {
+                       /* need to do gmc hw init early so we can allocate gpu mem */
                        /* Try to reserve bad pages early */
                        if (amdgpu_sriov_vf(adev))
                                amdgpu_virt_exchange_data(adev);
@@ -2456,12 +2464,14 @@ static int amdgpu_device_ip_init(struct amdgpu_device *adev)
                        if (!hive->reset_domain ||
                            !amdgpu_reset_get_reset_domain(hive->reset_domain)) {
                                r = -ENOENT;
+                               amdgpu_put_xgmi_hive(hive);
                                goto init_failed;
                        }
 
                        /* Drop the early temporary reset domain we created for device */
                        amdgpu_reset_put_reset_domain(adev->reset_domain);
                        adev->reset_domain = hive->reset_domain;
+                       amdgpu_put_xgmi_hive(hive);
                }
        }
 
@@ -3050,8 +3060,8 @@ static int amdgpu_device_ip_reinit_early_sriov(struct amdgpu_device *adev)
        int i, r;
 
        static enum amd_ip_block_type ip_order[] = {
-               AMD_IP_BLOCK_TYPE_GMC,
                AMD_IP_BLOCK_TYPE_COMMON,
+               AMD_IP_BLOCK_TYPE_GMC,
                AMD_IP_BLOCK_TYPE_PSP,
                AMD_IP_BLOCK_TYPE_IH,
        };
@@ -4413,8 +4423,6 @@ static int amdgpu_device_reset_sriov(struct amdgpu_device *adev,
 retry:
        amdgpu_amdkfd_pre_reset(adev);
 
-       amdgpu_amdkfd_pre_reset(adev);
-
        if (from_hypervisor)
                r = amdgpu_virt_request_full_gpu(adev, true);
        else
@@ -4742,6 +4750,8 @@ int amdgpu_do_asic_reset(struct list_head *device_list_handle,
        tmp_adev = list_first_entry(device_list_handle, struct amdgpu_device,
                                    reset_list);
        amdgpu_reset_reg_dumps(tmp_adev);
+
+       reset_context->reset_device_list = device_list_handle;
        r = amdgpu_reset_perform_reset(tmp_adev, reset_context);
        /* If reset handler not implemented, continue; otherwise return */
        if (r == -ENOSYS)
@@ -5522,7 +5532,8 @@ bool amdgpu_device_is_peer_accessible(struct amdgpu_device *adev,
                ~*peer_adev->dev->dma_mask : ~((1ULL << 32) - 1);
        resource_size_t aper_limit =
                adev->gmc.aper_base + adev->gmc.aper_size - 1;
-       bool p2p_access = !(pci_p2pdma_distance_many(adev->pdev,
+       bool p2p_access = !adev->gmc.xgmi.connected_to_cpu &&
+                         !(pci_p2pdma_distance_many(adev->pdev,
                                        &peer_adev->dev, 1, true) < 0);
 
        return pcie_p2p && p2p_access && (adev->gmc.visible_vram_size &&
index c20922a..5b09c8f 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/pci.h>
 #include <linux/pm_runtime.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_damage_helper.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drm_fb_helper.h>
@@ -496,6 +497,7 @@ bool amdgpu_display_ddc_probe(struct amdgpu_connector *amdgpu_connector,
 static const struct drm_framebuffer_funcs amdgpu_fb_funcs = {
        .destroy = drm_gem_fb_destroy,
        .create_handle = drm_gem_fb_create_handle,
+       .dirty = drm_atomic_helper_dirtyfb,
 };
 
 uint32_t amdgpu_display_supported_domains(struct amdgpu_device *adev,
index ecada5e..e325150 100644 (file)
@@ -66,10 +66,15 @@ static bool is_fru_eeprom_supported(struct amdgpu_device *adev)
                return true;
        case CHIP_SIENNA_CICHLID:
                if (strnstr(atom_ctx->vbios_version, "D603",
+                   sizeof(atom_ctx->vbios_version))) {
+                       if (strnstr(atom_ctx->vbios_version, "D603GLXE",
                            sizeof(atom_ctx->vbios_version)))
-                       return true;
-               else
+                               return false;
+                       else
+                               return true;
+               } else {
                        return false;
+               }
        default:
                return false;
        }
index 5071b96..c2fd6f3 100644 (file)
@@ -159,7 +159,10 @@ void amdgpu_job_free(struct amdgpu_job *job)
        amdgpu_sync_free(&job->sync);
        amdgpu_sync_free(&job->sched_sync);
 
-       dma_fence_put(&job->hw_fence);
+       if (!job->hw_fence.ops)
+               kfree(job);
+       else
+               dma_fence_put(&job->hw_fence);
 }
 
 int amdgpu_job_submit(struct amdgpu_job *job, struct drm_sched_entity *entity,
@@ -272,10 +275,6 @@ void amdgpu_job_stop_all_jobs_on_sched(struct drm_gpu_scheduler *sched)
        /* Signal all jobs not yet scheduled */
        for (i = DRM_SCHED_PRIORITY_COUNT - 1; i >= DRM_SCHED_PRIORITY_MIN; i--) {
                struct drm_sched_rq *rq = &sched->sched_rq[i];
-
-               if (!rq)
-                       continue;
-
                spin_lock(&rq->lock);
                list_for_each_entry(s_entity, &rq->entities, list) {
                        while ((s_job = to_drm_sched_job(spsc_queue_pop(&s_entity->job_queue)))) {
index b067ce4..c9dec24 100644 (file)
@@ -486,11 +486,14 @@ static int psp_sw_fini(void *handle)
                release_firmware(psp->ta_fw);
                psp->ta_fw = NULL;
        }
-       if (adev->psp.cap_fw) {
+       if (psp->cap_fw) {
                release_firmware(psp->cap_fw);
                psp->cap_fw = NULL;
        }
-
+       if (psp->toc_fw) {
+               release_firmware(psp->toc_fw);
+               psp->toc_fw = NULL;
+       }
        if (adev->ip_versions[MP0_HWIP][0] == IP_VERSION(11, 0, 0) ||
            adev->ip_versions[MP0_HWIP][0] == IP_VERSION(11, 0, 7))
                psp_sysfs_fini(adev);
@@ -753,7 +756,7 @@ static int psp_tmr_init(struct psp_context *psp)
        }
 
        pptr = amdgpu_sriov_vf(psp->adev) ? &tmr_buf : NULL;
-       ret = amdgpu_bo_create_kernel(psp->adev, tmr_size, PSP_TMR_SIZE(psp->adev),
+       ret = amdgpu_bo_create_kernel(psp->adev, tmr_size, PSP_TMR_ALIGNMENT,
                                      AMDGPU_GEM_DOMAIN_VRAM,
                                      &psp->tmr_bo, &psp->tmr_mc_addr, pptr);
 
@@ -2401,7 +2404,7 @@ static int psp_load_smu_fw(struct psp_context *psp)
 static bool fw_load_skip_check(struct psp_context *psp,
                               struct amdgpu_firmware_info *ucode)
 {
-       if (!ucode->fw)
+       if (!ucode->fw || !ucode->ucode_size)
                return true;
 
        if (ucode->ucode_id == AMDGPU_UCODE_ID_SMC &&
@@ -2641,6 +2644,9 @@ static int psp_hw_fini(void *handle)
                psp_rap_terminate(psp);
                psp_dtm_terminate(psp);
                psp_hdcp_terminate(psp);
+
+               if (adev->gmc.xgmi.num_physical_nodes > 1)
+                       psp_xgmi_terminate(psp);
        }
 
        psp_asd_terminate(psp);
index c32b74b..e593e8c 100644 (file)
@@ -36,6 +36,7 @@
 #define PSP_CMD_BUFFER_SIZE    0x1000
 #define PSP_1_MEG              0x100000
 #define PSP_TMR_SIZE(adev)     ((adev)->asic_type == CHIP_ALDEBARAN ? 0x800000 : 0x400000)
+#define PSP_TMR_ALIGNMENT      0x100000
 #define PSP_FW_NAME_LEN                0x24
 
 enum psp_shared_mem_size {
index ff5361f..12c6f97 100644 (file)
@@ -1811,7 +1811,8 @@ static void amdgpu_ras_log_on_err_counter(struct amdgpu_device *adev)
                amdgpu_ras_query_error_status(adev, &info);
 
                if (adev->ip_versions[MP0_HWIP][0] != IP_VERSION(11, 0, 2) &&
-                   adev->ip_versions[MP0_HWIP][0] != IP_VERSION(11, 0, 4)) {
+                   adev->ip_versions[MP0_HWIP][0] != IP_VERSION(11, 0, 4) &&
+                   adev->ip_versions[MP0_HWIP][0] != IP_VERSION(13, 0, 0)) {
                        if (amdgpu_ras_reset_error_status(adev, info.head.block))
                                dev_warn(adev->dev, "Failed to reset error counter and error status");
                }
index 9e55a5d..ffda156 100644 (file)
@@ -37,6 +37,7 @@ struct amdgpu_reset_context {
        struct amdgpu_device *reset_req_dev;
        struct amdgpu_job *job;
        struct amdgpu_hive_info *hive;
+       struct list_head *reset_device_list;
        unsigned long flags;
 };
 
index 3b4c194..134575a 100644 (file)
@@ -637,6 +637,8 @@ struct amdgpu_ttm_tt {
 #endif
 };
 
+#define ttm_to_amdgpu_ttm_tt(ptr)      container_of(ptr, struct amdgpu_ttm_tt, ttm)
+
 #ifdef CONFIG_DRM_AMDGPU_USERPTR
 /*
  * amdgpu_ttm_tt_get_user_pages - get device accessible pages that back user
@@ -648,7 +650,7 @@ struct amdgpu_ttm_tt {
 int amdgpu_ttm_tt_get_user_pages(struct amdgpu_bo *bo, struct page **pages)
 {
        struct ttm_tt *ttm = bo->tbo.ttm;
-       struct amdgpu_ttm_tt *gtt = (void *)ttm;
+       struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
        unsigned long start = gtt->userptr;
        struct vm_area_struct *vma;
        struct mm_struct *mm;
@@ -702,7 +704,7 @@ out_unlock:
  */
 bool amdgpu_ttm_tt_get_user_pages_done(struct ttm_tt *ttm)
 {
-       struct amdgpu_ttm_tt *gtt = (void *)ttm;
+       struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
        bool r = false;
 
        if (!gtt || !gtt->userptr)
@@ -751,7 +753,7 @@ static int amdgpu_ttm_tt_pin_userptr(struct ttm_device *bdev,
                                     struct ttm_tt *ttm)
 {
        struct amdgpu_device *adev = amdgpu_ttm_adev(bdev);
-       struct amdgpu_ttm_tt *gtt = (void *)ttm;
+       struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
        int write = !(gtt->userflags & AMDGPU_GEM_USERPTR_READONLY);
        enum dma_data_direction direction = write ?
                DMA_BIDIRECTIONAL : DMA_TO_DEVICE;
@@ -788,7 +790,7 @@ static void amdgpu_ttm_tt_unpin_userptr(struct ttm_device *bdev,
                                        struct ttm_tt *ttm)
 {
        struct amdgpu_device *adev = amdgpu_ttm_adev(bdev);
-       struct amdgpu_ttm_tt *gtt = (void *)ttm;
+       struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
        int write = !(gtt->userflags & AMDGPU_GEM_USERPTR_READONLY);
        enum dma_data_direction direction = write ?
                DMA_BIDIRECTIONAL : DMA_TO_DEVICE;
@@ -822,7 +824,7 @@ static void amdgpu_ttm_gart_bind(struct amdgpu_device *adev,
 {
        struct amdgpu_bo *abo = ttm_to_amdgpu_bo(tbo);
        struct ttm_tt *ttm = tbo->ttm;
-       struct amdgpu_ttm_tt *gtt = (void *)ttm;
+       struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
 
        if (amdgpu_bo_encrypted(abo))
                flags |= AMDGPU_PTE_TMZ;
@@ -860,7 +862,7 @@ static int amdgpu_ttm_backend_bind(struct ttm_device *bdev,
                                   struct ttm_resource *bo_mem)
 {
        struct amdgpu_device *adev = amdgpu_ttm_adev(bdev);
-       struct amdgpu_ttm_tt *gtt = (void*)ttm;
+       struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
        uint64_t flags;
        int r;
 
@@ -927,7 +929,7 @@ int amdgpu_ttm_alloc_gart(struct ttm_buffer_object *bo)
 {
        struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev);
        struct ttm_operation_ctx ctx = { false, false };
-       struct amdgpu_ttm_tt *gtt = (void *)bo->ttm;
+       struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(bo->ttm);
        struct ttm_placement placement;
        struct ttm_place placements;
        struct ttm_resource *tmp;
@@ -998,7 +1000,7 @@ static void amdgpu_ttm_backend_unbind(struct ttm_device *bdev,
                                      struct ttm_tt *ttm)
 {
        struct amdgpu_device *adev = amdgpu_ttm_adev(bdev);
-       struct amdgpu_ttm_tt *gtt = (void *)ttm;
+       struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
 
        /* if the pages have userptr pinning then clear that first */
        if (gtt->userptr) {
@@ -1025,7 +1027,7 @@ static void amdgpu_ttm_backend_unbind(struct ttm_device *bdev,
 static void amdgpu_ttm_backend_destroy(struct ttm_device *bdev,
                                       struct ttm_tt *ttm)
 {
-       struct amdgpu_ttm_tt *gtt = (void *)ttm;
+       struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
 
        if (gtt->usertask)
                put_task_struct(gtt->usertask);
@@ -1079,7 +1081,7 @@ static int amdgpu_ttm_tt_populate(struct ttm_device *bdev,
                                  struct ttm_operation_ctx *ctx)
 {
        struct amdgpu_device *adev = amdgpu_ttm_adev(bdev);
-       struct amdgpu_ttm_tt *gtt = (void *)ttm;
+       struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
        pgoff_t i;
        int ret;
 
@@ -1113,7 +1115,7 @@ static int amdgpu_ttm_tt_populate(struct ttm_device *bdev,
 static void amdgpu_ttm_tt_unpopulate(struct ttm_device *bdev,
                                     struct ttm_tt *ttm)
 {
-       struct amdgpu_ttm_tt *gtt = (void *)ttm;
+       struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
        struct amdgpu_device *adev;
        pgoff_t i;
 
@@ -1182,7 +1184,7 @@ int amdgpu_ttm_tt_set_userptr(struct ttm_buffer_object *bo,
        /* Set TTM_TT_FLAG_EXTERNAL before populate but after create. */
        bo->ttm->page_flags |= TTM_TT_FLAG_EXTERNAL;
 
-       gtt = (void *)bo->ttm;
+       gtt = ttm_to_amdgpu_ttm_tt(bo->ttm);
        gtt->userptr = addr;
        gtt->userflags = flags;
 
@@ -1199,7 +1201,7 @@ int amdgpu_ttm_tt_set_userptr(struct ttm_buffer_object *bo,
  */
 struct mm_struct *amdgpu_ttm_tt_get_usermm(struct ttm_tt *ttm)
 {
-       struct amdgpu_ttm_tt *gtt = (void *)ttm;
+       struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
 
        if (gtt == NULL)
                return NULL;
@@ -1218,7 +1220,7 @@ struct mm_struct *amdgpu_ttm_tt_get_usermm(struct ttm_tt *ttm)
 bool amdgpu_ttm_tt_affect_userptr(struct ttm_tt *ttm, unsigned long start,
                                  unsigned long end, unsigned long *userptr)
 {
-       struct amdgpu_ttm_tt *gtt = (void *)ttm;
+       struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
        unsigned long size;
 
        if (gtt == NULL || !gtt->userptr)
@@ -1241,7 +1243,7 @@ bool amdgpu_ttm_tt_affect_userptr(struct ttm_tt *ttm, unsigned long start,
  */
 bool amdgpu_ttm_tt_is_userptr(struct ttm_tt *ttm)
 {
-       struct amdgpu_ttm_tt *gtt = (void *)ttm;
+       struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
 
        if (gtt == NULL || !gtt->userptr)
                return false;
@@ -1254,7 +1256,7 @@ bool amdgpu_ttm_tt_is_userptr(struct ttm_tt *ttm)
  */
 bool amdgpu_ttm_tt_is_readonly(struct ttm_tt *ttm)
 {
-       struct amdgpu_ttm_tt *gtt = (void *)ttm;
+       struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
 
        if (gtt == NULL)
                return false;
index ebed3f5..96b6cf4 100644 (file)
@@ -390,6 +390,7 @@ union amdgpu_firmware_header {
        struct rlc_firmware_header_v2_1 rlc_v2_1;
        struct rlc_firmware_header_v2_2 rlc_v2_2;
        struct rlc_firmware_header_v2_3 rlc_v2_3;
+       struct rlc_firmware_header_v2_4 rlc_v2_4;
        struct sdma_firmware_header_v1_0 sdma;
        struct sdma_firmware_header_v1_1 sdma_v1_1;
        struct sdma_firmware_header_v2_0 sdma_v2_0;
index 108e8e8..576849e 100644 (file)
@@ -496,8 +496,7 @@ static int amdgpu_vkms_sw_init(void *handle)
        adev_to_drm(adev)->mode_config.max_height = YRES_MAX;
 
        adev_to_drm(adev)->mode_config.preferred_depth = 24;
-       /* disable prefer shadow for now due to hibernation issues */
-       adev_to_drm(adev)->mode_config.prefer_shadow = 0;
+       adev_to_drm(adev)->mode_config.prefer_shadow = 1;
 
        adev_to_drm(adev)->mode_config.fb_base = adev->gmc.aper_base;
 
index 1b108d0..f2aebbf 100644 (file)
@@ -742,7 +742,7 @@ int amdgpu_xgmi_remove_device(struct amdgpu_device *adev)
                amdgpu_put_xgmi_hive(hive);
        }
 
-       return psp_xgmi_terminate(&adev->psp);
+       return 0;
 }
 
 static int amdgpu_xgmi_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *ras_block)
index 33a8a73..f0e235f 100644 (file)
 #include "navi10_enum.h"
 #include "soc15_common.h"
 
+#define regATHUB_MISC_CNTL_V3_0_1                      0x00d7
+#define regATHUB_MISC_CNTL_V3_0_1_BASE_IDX             0
+
+
+static uint32_t athub_v3_0_get_cg_cntl(struct amdgpu_device *adev)
+{
+       uint32_t data;
+
+       switch (adev->ip_versions[ATHUB_HWIP][0]) {
+       case IP_VERSION(3, 0, 1):
+               data = RREG32_SOC15(ATHUB, 0, regATHUB_MISC_CNTL_V3_0_1);
+               break;
+       default:
+               data = RREG32_SOC15(ATHUB, 0, regATHUB_MISC_CNTL);
+               break;
+       }
+       return data;
+}
+
+static void athub_v3_0_set_cg_cntl(struct amdgpu_device *adev, uint32_t data)
+{
+       switch (adev->ip_versions[ATHUB_HWIP][0]) {
+       case IP_VERSION(3, 0, 1):
+               WREG32_SOC15(ATHUB, 0, regATHUB_MISC_CNTL_V3_0_1, data);
+               break;
+       default:
+               WREG32_SOC15(ATHUB, 0, regATHUB_MISC_CNTL, data);
+               break;
+       }
+}
+
 static void
 athub_v3_0_update_medium_grain_clock_gating(struct amdgpu_device *adev,
                                            bool enable)
 {
        uint32_t def, data;
 
-       def = data = RREG32_SOC15(ATHUB, 0, regATHUB_MISC_CNTL);
+       def = data = athub_v3_0_get_cg_cntl(adev);
 
        if (enable && (adev->cg_flags & AMD_CG_SUPPORT_ATHUB_MGCG))
                data |= ATHUB_MISC_CNTL__CG_ENABLE_MASK;
@@ -42,7 +73,7 @@ athub_v3_0_update_medium_grain_clock_gating(struct amdgpu_device *adev,
                data &= ~ATHUB_MISC_CNTL__CG_ENABLE_MASK;
 
        if (def != data)
-               WREG32_SOC15(ATHUB, 0, regATHUB_MISC_CNTL, data);
+               athub_v3_0_set_cg_cntl(adev, data);
 }
 
 static void
@@ -51,7 +82,7 @@ athub_v3_0_update_medium_grain_light_sleep(struct amdgpu_device *adev,
 {
        uint32_t def, data;
 
-       def = data = RREG32_SOC15(ATHUB, 0, regATHUB_MISC_CNTL);
+       def = data = athub_v3_0_get_cg_cntl(adev);
 
        if (enable && (adev->cg_flags & AMD_CG_SUPPORT_ATHUB_LS))
                data |= ATHUB_MISC_CNTL__CG_MEM_LS_ENABLE_MASK;
@@ -59,7 +90,7 @@ athub_v3_0_update_medium_grain_light_sleep(struct amdgpu_device *adev,
                data &= ~ATHUB_MISC_CNTL__CG_MEM_LS_ENABLE_MASK;
 
        if (def != data)
-               WREG32_SOC15(ATHUB, 0, regATHUB_MISC_CNTL, data);
+               athub_v3_0_set_cg_cntl(adev, data);
 }
 
 int athub_v3_0_set_clockgating(struct amdgpu_device *adev,
@@ -70,6 +101,7 @@ int athub_v3_0_set_clockgating(struct amdgpu_device *adev,
 
        switch (adev->ip_versions[ATHUB_HWIP][0]) {
        case IP_VERSION(3, 0, 0):
+       case IP_VERSION(3, 0, 1):
        case IP_VERSION(3, 0, 2):
                athub_v3_0_update_medium_grain_clock_gating(adev,
                                state == AMD_CG_STATE_GATE);
@@ -88,7 +120,7 @@ void athub_v3_0_get_clockgating(struct amdgpu_device *adev, u64 *flags)
        int data;
 
        /* AMD_CG_SUPPORT_ATHUB_MGCG */
-       data = RREG32_SOC15(ATHUB, 0, regATHUB_MISC_CNTL);
+       data = athub_v3_0_get_cg_cntl(adev);
        if (data & ATHUB_MISC_CNTL__CG_ENABLE_MASK)
                *flags |= AMD_CG_SUPPORT_ATHUB_MGCG;
 
index 9c964cd..288fce7 100644 (file)
@@ -2796,8 +2796,7 @@ static int dce_v10_0_sw_init(void *handle)
        adev_to_drm(adev)->mode_config.max_height = 16384;
 
        adev_to_drm(adev)->mode_config.preferred_depth = 24;
-       /* disable prefer shadow for now due to hibernation issues */
-       adev_to_drm(adev)->mode_config.prefer_shadow = 0;
+       adev_to_drm(adev)->mode_config.prefer_shadow = 1;
 
        adev_to_drm(adev)->mode_config.fb_modifiers_not_supported = true;
 
index e0ad9f2..cbe5250 100644 (file)
@@ -2914,8 +2914,7 @@ static int dce_v11_0_sw_init(void *handle)
        adev_to_drm(adev)->mode_config.max_height = 16384;
 
        adev_to_drm(adev)->mode_config.preferred_depth = 24;
-       /* disable prefer shadow for now due to hibernation issues */
-       adev_to_drm(adev)->mode_config.prefer_shadow = 0;
+       adev_to_drm(adev)->mode_config.prefer_shadow = 1;
 
        adev_to_drm(adev)->mode_config.fb_modifiers_not_supported = true;
 
index 77f5e99..b1c44fa 100644 (file)
@@ -2673,8 +2673,7 @@ static int dce_v6_0_sw_init(void *handle)
        adev_to_drm(adev)->mode_config.max_width = 16384;
        adev_to_drm(adev)->mode_config.max_height = 16384;
        adev_to_drm(adev)->mode_config.preferred_depth = 24;
-       /* disable prefer shadow for now due to hibernation issues */
-       adev_to_drm(adev)->mode_config.prefer_shadow = 0;
+       adev_to_drm(adev)->mode_config.prefer_shadow = 1;
        adev_to_drm(adev)->mode_config.fb_modifiers_not_supported = true;
        adev_to_drm(adev)->mode_config.fb_base = adev->gmc.aper_base;
 
index 802e5c7..a22b45c 100644 (file)
@@ -2693,8 +2693,11 @@ static int dce_v8_0_sw_init(void *handle)
        adev_to_drm(adev)->mode_config.max_height = 16384;
 
        adev_to_drm(adev)->mode_config.preferred_depth = 24;
-       /* disable prefer shadow for now due to hibernation issues */
-       adev_to_drm(adev)->mode_config.prefer_shadow = 0;
+       if (adev->asic_type == CHIP_HAWAII)
+               /* disable prefer shadow for now due to hibernation issues */
+               adev_to_drm(adev)->mode_config.prefer_shadow = 0;
+       else
+               adev_to_drm(adev)->mode_config.prefer_shadow = 1;
 
        adev_to_drm(adev)->mode_config.fb_modifiers_not_supported = true;
 
index fafbad3..a3cd5c1 100644 (file)
@@ -4274,35 +4274,45 @@ static int gfx_v10_0_init_microcode(struct amdgpu_device *adev)
 
                }
 
-               info = &adev->firmware.ucode[AMDGPU_UCODE_ID_GLOBAL_TAP_DELAYS];
-               info->ucode_id = AMDGPU_UCODE_ID_GLOBAL_TAP_DELAYS;
-               info->fw = adev->gfx.rlc_fw;
-               adev->firmware.fw_size +=
-                       ALIGN(adev->gfx.rlc.global_tap_delays_ucode_size_bytes, PAGE_SIZE);
+               if (adev->gfx.rlc.global_tap_delays_ucode_size_bytes) {
+                       info = &adev->firmware.ucode[AMDGPU_UCODE_ID_GLOBAL_TAP_DELAYS];
+                       info->ucode_id = AMDGPU_UCODE_ID_GLOBAL_TAP_DELAYS;
+                       info->fw = adev->gfx.rlc_fw;
+                       adev->firmware.fw_size +=
+                               ALIGN(adev->gfx.rlc.global_tap_delays_ucode_size_bytes, PAGE_SIZE);
+               }
 
-               info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SE0_TAP_DELAYS];
-               info->ucode_id = AMDGPU_UCODE_ID_SE0_TAP_DELAYS;
-               info->fw = adev->gfx.rlc_fw;
-               adev->firmware.fw_size +=
-                       ALIGN(adev->gfx.rlc.se0_tap_delays_ucode_size_bytes, PAGE_SIZE);
+               if (adev->gfx.rlc.se0_tap_delays_ucode_size_bytes) {
+                       info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SE0_TAP_DELAYS];
+                       info->ucode_id = AMDGPU_UCODE_ID_SE0_TAP_DELAYS;
+                       info->fw = adev->gfx.rlc_fw;
+                       adev->firmware.fw_size +=
+                               ALIGN(adev->gfx.rlc.se0_tap_delays_ucode_size_bytes, PAGE_SIZE);
+               }
 
-               info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SE1_TAP_DELAYS];
-               info->ucode_id = AMDGPU_UCODE_ID_SE1_TAP_DELAYS;
-               info->fw = adev->gfx.rlc_fw;
-               adev->firmware.fw_size +=
-                       ALIGN(adev->gfx.rlc.se1_tap_delays_ucode_size_bytes, PAGE_SIZE);
+               if (adev->gfx.rlc.se1_tap_delays_ucode_size_bytes) {
+                       info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SE1_TAP_DELAYS];
+                       info->ucode_id = AMDGPU_UCODE_ID_SE1_TAP_DELAYS;
+                       info->fw = adev->gfx.rlc_fw;
+                       adev->firmware.fw_size +=
+                               ALIGN(adev->gfx.rlc.se1_tap_delays_ucode_size_bytes, PAGE_SIZE);
+               }
 
-               info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SE2_TAP_DELAYS];
-               info->ucode_id = AMDGPU_UCODE_ID_SE2_TAP_DELAYS;
-               info->fw = adev->gfx.rlc_fw;
-               adev->firmware.fw_size +=
-                       ALIGN(adev->gfx.rlc.se2_tap_delays_ucode_size_bytes, PAGE_SIZE);
+               if (adev->gfx.rlc.se2_tap_delays_ucode_size_bytes) {
+                       info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SE2_TAP_DELAYS];
+                       info->ucode_id = AMDGPU_UCODE_ID_SE2_TAP_DELAYS;
+                       info->fw = adev->gfx.rlc_fw;
+                       adev->firmware.fw_size +=
+                               ALIGN(adev->gfx.rlc.se2_tap_delays_ucode_size_bytes, PAGE_SIZE);
+               }
 
-               info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SE3_TAP_DELAYS];
-               info->ucode_id = AMDGPU_UCODE_ID_SE3_TAP_DELAYS;
-               info->fw = adev->gfx.rlc_fw;
-               adev->firmware.fw_size +=
-                       ALIGN(adev->gfx.rlc.se3_tap_delays_ucode_size_bytes, PAGE_SIZE);
+               if (adev->gfx.rlc.se3_tap_delays_ucode_size_bytes) {
+                       info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SE3_TAP_DELAYS];
+                       info->ucode_id = AMDGPU_UCODE_ID_SE3_TAP_DELAYS;
+                       info->fw = adev->gfx.rlc_fw;
+                       adev->firmware.fw_size +=
+                               ALIGN(adev->gfx.rlc.se3_tap_delays_ucode_size_bytes, PAGE_SIZE);
+               }
 
                info = &adev->firmware.ucode[AMDGPU_UCODE_ID_CP_MEC1];
                info->ucode_id = AMDGPU_UCODE_ID_CP_MEC1;
@@ -4846,7 +4856,7 @@ static int gfx_v10_0_sw_init(void *handle)
        case IP_VERSION(10, 3, 3):
        case IP_VERSION(10, 3, 7):
                adev->gfx.me.num_me = 1;
-               adev->gfx.me.num_pipe_per_me = 2;
+               adev->gfx.me.num_pipe_per_me = 1;
                adev->gfx.me.num_queue_per_pipe = 1;
                adev->gfx.mec.num_mec = 2;
                adev->gfx.mec.num_pipe_per_mec = 4;
index 6fd71cb..f6b1bb4 100644 (file)
@@ -53,6 +53,7 @@
 #define GFX11_MEC_HPD_SIZE     2048
 
 #define RLCG_UCODE_LOADING_START_ADDRESS       0x00002000L
+#define RLC_PG_DELAY_3_DEFAULT_GC_11_0_1       0x1388
 
 #define regCGTT_WD_CLK_CTRL            0x5086
 #define regCGTT_WD_CLK_CTRL_BASE_IDX   1
@@ -130,6 +131,8 @@ static void gfx_v11_0_ring_invalidate_tlbs(struct amdgpu_ring *ring,
                                           bool all_hub, uint8_t dst_sel);
 static void gfx_v11_0_set_safe_mode(struct amdgpu_device *adev);
 static void gfx_v11_0_unset_safe_mode(struct amdgpu_device *adev);
+static void gfx_v11_0_update_perf_clk(struct amdgpu_device *adev,
+                                     bool enable);
 
 static void gfx11_kiq_set_resources(struct amdgpu_ring *kiq_ring, uint64_t queue_mask)
 {
@@ -1138,6 +1141,7 @@ static const struct amdgpu_gfx_funcs gfx_v11_0_gfx_funcs = {
        .read_wave_vgprs = &gfx_v11_0_read_wave_vgprs,
        .select_me_pipe_q = &gfx_v11_0_select_me_pipe_q,
        .init_spm_golden = &gfx_v11_0_init_spm_golden_registers,
+       .update_perfmon_mgcg = &gfx_v11_0_update_perf_clk,
 };
 
 static int gfx_v11_0_gpu_early_init(struct amdgpu_device *adev)
@@ -5181,9 +5185,12 @@ static void gfx_v11_0_update_coarse_grain_clock_gating(struct amdgpu_device *ade
                data = REG_SET_FIELD(data, SDMA0_RLC_CGCG_CTRL, CGCG_INT_ENABLE, 1);
                WREG32_SOC15(GC, 0, regSDMA0_RLC_CGCG_CTRL, data);
 
-               data = RREG32_SOC15(GC, 0, regSDMA1_RLC_CGCG_CTRL);
-               data = REG_SET_FIELD(data, SDMA1_RLC_CGCG_CTRL, CGCG_INT_ENABLE, 1);
-               WREG32_SOC15(GC, 0, regSDMA1_RLC_CGCG_CTRL, data);
+               /* Some ASICs only have one SDMA instance, not need to configure SDMA1 */
+               if (adev->sdma.num_instances > 1) {
+                       data = RREG32_SOC15(GC, 0, regSDMA1_RLC_CGCG_CTRL);
+                       data = REG_SET_FIELD(data, SDMA1_RLC_CGCG_CTRL, CGCG_INT_ENABLE, 1);
+                       WREG32_SOC15(GC, 0, regSDMA1_RLC_CGCG_CTRL, data);
+               }
        } else {
                /* Program RLC_CGCG_CGLS_CTRL */
                def = data = RREG32_SOC15(GC, 0, regRLC_CGCG_CGLS_CTRL);
@@ -5212,9 +5219,12 @@ static void gfx_v11_0_update_coarse_grain_clock_gating(struct amdgpu_device *ade
                data &= ~SDMA0_RLC_CGCG_CTRL__CGCG_INT_ENABLE_MASK;
                WREG32_SOC15(GC, 0, regSDMA0_RLC_CGCG_CTRL, data);
 
-               data = RREG32_SOC15(GC, 0, regSDMA1_RLC_CGCG_CTRL);
-               data &= ~SDMA1_RLC_CGCG_CTRL__CGCG_INT_ENABLE_MASK;
-               WREG32_SOC15(GC, 0, regSDMA1_RLC_CGCG_CTRL, data);
+               /* Some ASICs only have one SDMA instance, not need to configure SDMA1 */
+               if (adev->sdma.num_instances > 1) {
+                       data = RREG32_SOC15(GC, 0, regSDMA1_RLC_CGCG_CTRL);
+                       data &= ~SDMA1_RLC_CGCG_CTRL__CGCG_INT_ENABLE_MASK;
+                       WREG32_SOC15(GC, 0, regSDMA1_RLC_CGCG_CTRL, data);
+               }
        }
 }
 
@@ -5279,6 +5289,38 @@ static const struct amdgpu_rlc_funcs gfx_v11_0_rlc_funcs = {
        .update_spm_vmid = gfx_v11_0_update_spm_vmid,
 };
 
+static void gfx_v11_cntl_power_gating(struct amdgpu_device *adev, bool enable)
+{
+       u32 data = RREG32_SOC15(GC, 0, regRLC_PG_CNTL);
+
+       if (enable && (adev->pg_flags & AMD_PG_SUPPORT_GFX_PG))
+               data |= RLC_PG_CNTL__GFX_POWER_GATING_ENABLE_MASK;
+       else
+               data &= ~RLC_PG_CNTL__GFX_POWER_GATING_ENABLE_MASK;
+
+       WREG32_SOC15(GC, 0, regRLC_PG_CNTL, data);
+
+       // Program RLC_PG_DELAY3 for CGPG hysteresis
+       if (enable && (adev->pg_flags & AMD_PG_SUPPORT_GFX_PG)) {
+               switch (adev->ip_versions[GC_HWIP][0]) {
+               case IP_VERSION(11, 0, 1):
+                       WREG32_SOC15(GC, 0, regRLC_PG_DELAY_3, RLC_PG_DELAY_3_DEFAULT_GC_11_0_1);
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
+static void gfx_v11_cntl_pg(struct amdgpu_device *adev, bool enable)
+{
+       amdgpu_gfx_rlc_enter_safe_mode(adev);
+
+       gfx_v11_cntl_power_gating(adev, enable);
+
+       amdgpu_gfx_rlc_exit_safe_mode(adev);
+}
+
 static int gfx_v11_0_set_powergating_state(void *handle,
                                           enum amd_powergating_state state)
 {
@@ -5293,6 +5335,10 @@ static int gfx_v11_0_set_powergating_state(void *handle,
        case IP_VERSION(11, 0, 2):
                amdgpu_gfx_off_ctrl(adev, enable);
                break;
+       case IP_VERSION(11, 0, 1):
+               gfx_v11_cntl_pg(adev, enable);
+               amdgpu_gfx_off_ctrl(adev, enable);
+               break;
        default:
                break;
        }
@@ -5310,6 +5356,7 @@ static int gfx_v11_0_set_clockgating_state(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):
                gfx_v11_0_update_gfx_clock_gating(adev,
                                state ==  AMD_CG_STATE_GATE);
index c6e0f93..fc9c104 100644 (file)
@@ -2587,7 +2587,8 @@ static void gfx_v9_0_constants_init(struct amdgpu_device *adev)
 
        gfx_v9_0_tiling_mode_table_init(adev);
 
-       gfx_v9_0_setup_rb(adev);
+       if (adev->gfx.num_gfx_rings)
+               gfx_v9_0_setup_rb(adev);
        gfx_v9_0_get_cu_info(adev, &adev->gfx.cu_info);
        adev->gfx.config.db_debug2 = RREG32_SOC15(GC, 0, mmDB_DEBUG2);
 
index 9ae8cda..f513e2c 100644 (file)
@@ -419,6 +419,7 @@ static int gmc_v10_0_flush_gpu_tlb_pasid(struct amdgpu_device *adev,
        uint32_t seq;
        uint16_t queried_pasid;
        bool ret;
+       u32 usec_timeout = amdgpu_sriov_vf(adev) ? SRIOV_USEC_TIMEOUT : adev->usec_timeout;
        struct amdgpu_ring *ring = &adev->gfx.kiq.ring;
        struct amdgpu_kiq *kiq = &adev->gfx.kiq;
 
@@ -437,7 +438,7 @@ static int gmc_v10_0_flush_gpu_tlb_pasid(struct amdgpu_device *adev,
 
                amdgpu_ring_commit(ring);
                spin_unlock(&adev->gfx.kiq.ring_lock);
-               r = amdgpu_fence_wait_polling(ring, seq, adev->usec_timeout);
+               r = amdgpu_fence_wait_polling(ring, seq, usec_timeout);
                if (r < 1) {
                        dev_err(adev->dev, "wait for kiq fence error: %ld.\n", r);
                        return -ETIME;
index 22761a3..4603653 100644 (file)
@@ -896,6 +896,7 @@ static int gmc_v9_0_flush_gpu_tlb_pasid(struct amdgpu_device *adev,
        uint32_t seq;
        uint16_t queried_pasid;
        bool ret;
+       u32 usec_timeout = amdgpu_sriov_vf(adev) ? SRIOV_USEC_TIMEOUT : adev->usec_timeout;
        struct amdgpu_ring *ring = &adev->gfx.kiq.ring;
        struct amdgpu_kiq *kiq = &adev->gfx.kiq;
 
@@ -935,7 +936,7 @@ static int gmc_v9_0_flush_gpu_tlb_pasid(struct amdgpu_device *adev,
 
                amdgpu_ring_commit(ring);
                spin_unlock(&adev->gfx.kiq.ring_lock);
-               r = amdgpu_fence_wait_polling(ring, seq, adev->usec_timeout);
+               r = amdgpu_fence_wait_polling(ring, seq, usec_timeout);
                if (r < 1) {
                        dev_err(adev->dev, "wait for kiq fence error: %ld.\n", r);
                        up_read(&adev->reset_domain->sem);
@@ -1624,12 +1625,15 @@ static int gmc_v9_0_sw_init(void *handle)
                        amdgpu_vm_adjust_size(adev, 256 * 1024, 9, 3, 47);
                else
                        amdgpu_vm_adjust_size(adev, 256 * 1024, 9, 3, 48);
+               if (adev->ip_versions[GC_HWIP][0] == IP_VERSION(9, 4, 2))
+                       adev->gmc.translate_further = adev->vm_manager.num_level > 1;
                break;
        case IP_VERSION(9, 4, 1):
                adev->num_vmhubs = 3;
 
                /* Keep the vm size same with Vega20 */
                amdgpu_vm_adjust_size(adev, 256 * 1024, 9, 3, 48);
+               adev->gmc.translate_further = adev->vm_manager.num_level > 1;
                break;
        default:
                break;
index 39a696c..29c3484 100644 (file)
@@ -40,6 +40,156 @@ static void hdp_v5_2_flush_hdp(struct amdgpu_device *adev,
                        0);
 }
 
+static void hdp_v5_2_update_mem_power_gating(struct amdgpu_device *adev,
+                                            bool enable)
+{
+       uint32_t hdp_clk_cntl;
+       uint32_t hdp_mem_pwr_cntl;
+
+       if (!(adev->cg_flags & (AMD_CG_SUPPORT_HDP_LS |
+                               AMD_CG_SUPPORT_HDP_DS |
+                               AMD_CG_SUPPORT_HDP_SD)))
+               return;
+
+       hdp_clk_cntl = RREG32_SOC15(HDP, 0, regHDP_CLK_CNTL);
+       hdp_mem_pwr_cntl = RREG32_SOC15(HDP, 0, regHDP_MEM_POWER_CTRL);
+
+       /* Before doing clock/power mode switch, forced on MEM clock */
+       hdp_clk_cntl = REG_SET_FIELD(hdp_clk_cntl, HDP_CLK_CNTL,
+                                    ATOMIC_MEM_CLK_SOFT_OVERRIDE, 1);
+       hdp_clk_cntl = REG_SET_FIELD(hdp_clk_cntl, HDP_CLK_CNTL,
+                                    RC_MEM_CLK_SOFT_OVERRIDE, 1);
+       WREG32_SOC15(HDP, 0, regHDP_CLK_CNTL, hdp_clk_cntl);
+
+       /* disable clock and power gating before any changing */
+       hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, HDP_MEM_POWER_CTRL,
+                                        ATOMIC_MEM_POWER_CTRL_EN, 0);
+       hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, HDP_MEM_POWER_CTRL,
+                                        ATOMIC_MEM_POWER_LS_EN, 0);
+       hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, HDP_MEM_POWER_CTRL,
+                                        ATOMIC_MEM_POWER_DS_EN, 0);
+       hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, HDP_MEM_POWER_CTRL,
+                                        ATOMIC_MEM_POWER_SD_EN, 0);
+       hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, HDP_MEM_POWER_CTRL,
+                                        RC_MEM_POWER_CTRL_EN, 0);
+       hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, HDP_MEM_POWER_CTRL,
+                                        RC_MEM_POWER_LS_EN, 0);
+       hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, HDP_MEM_POWER_CTRL,
+                                        RC_MEM_POWER_DS_EN, 0);
+       hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, HDP_MEM_POWER_CTRL,
+                                        RC_MEM_POWER_SD_EN, 0);
+       WREG32_SOC15(HDP, 0, regHDP_MEM_POWER_CTRL, hdp_mem_pwr_cntl);
+
+       /* Already disabled above. The actions below are for "enabled" only */
+       if (enable) {
+               /* only one clock gating mode (LS/DS/SD) can be enabled */
+               if (adev->cg_flags & AMD_CG_SUPPORT_HDP_SD) {
+                       hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl,
+                                                        HDP_MEM_POWER_CTRL,
+                                                        ATOMIC_MEM_POWER_SD_EN, 1);
+                       hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl,
+                                                        HDP_MEM_POWER_CTRL,
+                                                        RC_MEM_POWER_SD_EN, 1);
+               } else if (adev->cg_flags & AMD_CG_SUPPORT_HDP_LS) {
+                       hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl,
+                                                        HDP_MEM_POWER_CTRL,
+                                                        ATOMIC_MEM_POWER_LS_EN, 1);
+                       hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl,
+                                                        HDP_MEM_POWER_CTRL,
+                                                        RC_MEM_POWER_LS_EN, 1);
+               } else if (adev->cg_flags & AMD_CG_SUPPORT_HDP_DS) {
+                       hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl,
+                                                        HDP_MEM_POWER_CTRL,
+                                                        ATOMIC_MEM_POWER_DS_EN, 1);
+                       hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl,
+                                                        HDP_MEM_POWER_CTRL,
+                                                        RC_MEM_POWER_DS_EN, 1);
+               }
+
+               /* confirmed that ATOMIC/RC_MEM_POWER_CTRL_EN have to be set for SRAM LS/DS/SD */
+               if (adev->cg_flags & (AMD_CG_SUPPORT_HDP_LS | AMD_CG_SUPPORT_HDP_DS |
+                                     AMD_CG_SUPPORT_HDP_SD)) {
+                       hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, HDP_MEM_POWER_CTRL,
+                                                        ATOMIC_MEM_POWER_CTRL_EN, 1);
+                       hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, HDP_MEM_POWER_CTRL,
+                                                        RC_MEM_POWER_CTRL_EN, 1);
+                       WREG32_SOC15(HDP, 0, regHDP_MEM_POWER_CTRL, hdp_mem_pwr_cntl);
+               }
+       }
+
+       /* disable MEM clock override after clock/power mode changing */
+       hdp_clk_cntl = REG_SET_FIELD(hdp_clk_cntl, HDP_CLK_CNTL,
+                                    ATOMIC_MEM_CLK_SOFT_OVERRIDE, 0);
+       hdp_clk_cntl = REG_SET_FIELD(hdp_clk_cntl, HDP_CLK_CNTL,
+                                    RC_MEM_CLK_SOFT_OVERRIDE, 0);
+       WREG32_SOC15(HDP, 0, regHDP_CLK_CNTL, hdp_clk_cntl);
+}
+
+static void hdp_v5_2_update_medium_grain_clock_gating(struct amdgpu_device *adev,
+                                                     bool enable)
+{
+       uint32_t hdp_clk_cntl;
+
+       if (!(adev->cg_flags & AMD_CG_SUPPORT_HDP_MGCG))
+               return;
+
+       hdp_clk_cntl = RREG32_SOC15(HDP, 0, regHDP_CLK_CNTL);
+
+       if (enable) {
+               hdp_clk_cntl &=
+                       ~(uint32_t)
+                       (HDP_CLK_CNTL__ATOMIC_MEM_CLK_SOFT_OVERRIDE_MASK |
+                        HDP_CLK_CNTL__RC_MEM_CLK_SOFT_OVERRIDE_MASK |
+                        HDP_CLK_CNTL__DBUS_CLK_SOFT_OVERRIDE_MASK |
+                        HDP_CLK_CNTL__DYN_CLK_SOFT_OVERRIDE_MASK |
+                        HDP_CLK_CNTL__XDP_REG_CLK_SOFT_OVERRIDE_MASK |
+                        HDP_CLK_CNTL__HDP_REG_CLK_SOFT_OVERRIDE_MASK);
+       } else {
+               hdp_clk_cntl |= HDP_CLK_CNTL__ATOMIC_MEM_CLK_SOFT_OVERRIDE_MASK |
+                       HDP_CLK_CNTL__RC_MEM_CLK_SOFT_OVERRIDE_MASK |
+                       HDP_CLK_CNTL__DBUS_CLK_SOFT_OVERRIDE_MASK |
+                       HDP_CLK_CNTL__DYN_CLK_SOFT_OVERRIDE_MASK |
+                       HDP_CLK_CNTL__XDP_REG_CLK_SOFT_OVERRIDE_MASK |
+                       HDP_CLK_CNTL__HDP_REG_CLK_SOFT_OVERRIDE_MASK;
+       }
+
+       WREG32_SOC15(HDP, 0, regHDP_CLK_CNTL, hdp_clk_cntl);
+}
+
+static void hdp_v5_2_get_clockgating_state(struct amdgpu_device *adev,
+                                          u64 *flags)
+{
+       uint32_t tmp;
+
+       /* AMD_CG_SUPPORT_HDP_MGCG */
+       tmp = RREG32_SOC15(HDP, 0, regHDP_CLK_CNTL);
+       if (!(tmp & (HDP_CLK_CNTL__ATOMIC_MEM_CLK_SOFT_OVERRIDE_MASK |
+                    HDP_CLK_CNTL__RC_MEM_CLK_SOFT_OVERRIDE_MASK |
+                    HDP_CLK_CNTL__DBUS_CLK_SOFT_OVERRIDE_MASK |
+                    HDP_CLK_CNTL__DYN_CLK_SOFT_OVERRIDE_MASK |
+                    HDP_CLK_CNTL__XDP_REG_CLK_SOFT_OVERRIDE_MASK |
+                    HDP_CLK_CNTL__HDP_REG_CLK_SOFT_OVERRIDE_MASK)))
+               *flags |= AMD_CG_SUPPORT_HDP_MGCG;
+
+       /* AMD_CG_SUPPORT_HDP_LS/DS/SD */
+       tmp = RREG32_SOC15(HDP, 0, regHDP_MEM_POWER_CTRL);
+       if (tmp & HDP_MEM_POWER_CTRL__ATOMIC_MEM_POWER_LS_EN_MASK)
+               *flags |= AMD_CG_SUPPORT_HDP_LS;
+       else if (tmp & HDP_MEM_POWER_CTRL__ATOMIC_MEM_POWER_DS_EN_MASK)
+               *flags |= AMD_CG_SUPPORT_HDP_DS;
+       else if (tmp & HDP_MEM_POWER_CTRL__ATOMIC_MEM_POWER_SD_EN_MASK)
+               *flags |= AMD_CG_SUPPORT_HDP_SD;
+}
+
+static void hdp_v5_2_update_clock_gating(struct amdgpu_device *adev,
+                                             bool enable)
+{
+       hdp_v5_2_update_mem_power_gating(adev, enable);
+       hdp_v5_2_update_medium_grain_clock_gating(adev, enable);
+}
+
 const struct amdgpu_hdp_funcs hdp_v5_2_funcs = {
        .flush_hdp = hdp_v5_2_flush_hdp,
+       .update_clock_gating = hdp_v5_2_update_clock_gating,
+       .get_clock_gating_state = hdp_v5_2_get_clockgating_state,
 };
index 92dc60a..085e613 100644 (file)
@@ -727,6 +727,7 @@ static const struct amd_ip_funcs ih_v6_0_ip_funcs = {
 static const struct amdgpu_ih_funcs ih_v6_0_funcs = {
        .get_wptr = ih_v6_0_get_wptr,
        .decode_iv = amdgpu_ih_decode_iv_helper,
+       .decode_iv_ts = amdgpu_ih_decode_iv_ts_helper,
        .set_rptr = ih_v6_0_set_rptr
 };
 
index 120ea29..cc3fdbb 100644 (file)
@@ -183,6 +183,7 @@ 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;
 
        return mes_v11_0_submit_pkt_and_poll_completion(mes,
                        &mes_add_queue_pkt, sizeof(mes_add_queue_pkt),
index 3f44a09..3e51e77 100644 (file)
@@ -176,6 +176,7 @@ static void mmhub_v1_0_init_cache_regs(struct amdgpu_device *adev)
        tmp = REG_SET_FIELD(tmp, VM_L2_CNTL2, INVALIDATE_L2_CACHE, 1);
        WREG32_SOC15(MMHUB, 0, mmVM_L2_CNTL2, tmp);
 
+       tmp = mmVM_L2_CNTL3_DEFAULT;
        if (adev->gmc.translate_further) {
                tmp = REG_SET_FIELD(tmp, VM_L2_CNTL3, BANK_SELECT, 12);
                tmp = REG_SET_FIELD(tmp, VM_L2_CNTL3,
index cac72ce..e8058ed 100644 (file)
@@ -518,18 +518,41 @@ static u64 mmhub_v3_0_1_get_mc_fb_offset(struct amdgpu_device *adev)
 static void mmhub_v3_0_1_update_medium_grain_clock_gating(struct amdgpu_device *adev,
                                                          bool enable)
 {
-       //TODO
+       uint32_t def, data;
+
+       def = data = RREG32_SOC15(MMHUB, 0, regMM_ATC_L2_MISC_CG);
+
+       if (enable)
+               data |= MM_ATC_L2_MISC_CG__ENABLE_MASK;
+       else
+               data &= ~MM_ATC_L2_MISC_CG__ENABLE_MASK;
+
+       if (def != data)
+               WREG32_SOC15(MMHUB, 0, regMM_ATC_L2_MISC_CG, data);
 }
 
 static void mmhub_v3_0_1_update_medium_grain_light_sleep(struct amdgpu_device *adev,
                                                         bool enable)
 {
-       //TODO
+       uint32_t def, data;
+
+       def = data = RREG32_SOC15(MMHUB, 0, regMM_ATC_L2_MISC_CG);
+
+       if (enable)
+               data |= MM_ATC_L2_MISC_CG__MEM_LS_ENABLE_MASK;
+       else
+               data &= ~MM_ATC_L2_MISC_CG__MEM_LS_ENABLE_MASK;
+
+       if (def != data)
+               WREG32_SOC15(MMHUB, 0, regMM_ATC_L2_MISC_CG, data);
 }
 
 static int mmhub_v3_0_1_set_clockgating(struct amdgpu_device *adev,
                                        enum amd_clockgating_state state)
 {
+       if (amdgpu_sriov_vf(adev))
+               return 0;
+
        mmhub_v3_0_1_update_medium_grain_clock_gating(adev,
                        state == AMD_CG_STATE_GATE);
        mmhub_v3_0_1_update_medium_grain_light_sleep(adev,
@@ -539,7 +562,20 @@ static int mmhub_v3_0_1_set_clockgating(struct amdgpu_device *adev,
 
 static void mmhub_v3_0_1_get_clockgating(struct amdgpu_device *adev, u64 *flags)
 {
-       //TODO
+       int data;
+
+       if (amdgpu_sriov_vf(adev))
+               *flags = 0;
+
+       data = RREG32_SOC15(MMHUB, 0, regMM_ATC_L2_MISC_CG);
+
+       /* AMD_CG_SUPPORT_MC_MGCG */
+       if (data & MM_ATC_L2_MISC_CG__ENABLE_MASK)
+               *flags |= AMD_CG_SUPPORT_MC_MGCG;
+
+       /* AMD_CG_SUPPORT_MC_LS */
+       if (data & MM_ATC_L2_MISC_CG__MEM_LS_ENABLE_MASK)
+               *flags |= AMD_CG_SUPPORT_MC_LS;
 }
 
 const struct amdgpu_mmhub_funcs mmhub_v3_0_1_funcs = {
index 6e0145b..445cb06 100644 (file)
@@ -295,9 +295,17 @@ static void mmhub_v9_4_disable_identity_aperture(struct amdgpu_device *adev,
 static void mmhub_v9_4_setup_vmid_config(struct amdgpu_device *adev, int hubid)
 {
        struct amdgpu_vmhub *hub = &adev->vmhub[AMDGPU_MMHUB_0];
+       unsigned int num_level, block_size;
        uint32_t tmp;
        int i;
 
+       num_level = adev->vm_manager.num_level;
+       block_size = adev->vm_manager.block_size;
+       if (adev->gmc.translate_further)
+               num_level -= 1;
+       else
+               block_size -= 9;
+
        for (i = 0; i <= 14; i++) {
                tmp = RREG32_SOC15_OFFSET(MMHUB, 0, mmVML2VC0_VM_CONTEXT1_CNTL,
                                hubid * MMHUB_INSTANCE_REGISTER_OFFSET + i);
@@ -305,7 +313,7 @@ static void mmhub_v9_4_setup_vmid_config(struct amdgpu_device *adev, int hubid)
                                    ENABLE_CONTEXT, 1);
                tmp = REG_SET_FIELD(tmp, VML2VC0_VM_CONTEXT1_CNTL,
                                    PAGE_TABLE_DEPTH,
-                                   adev->vm_manager.num_level);
+                                   num_level);
                tmp = REG_SET_FIELD(tmp, VML2VC0_VM_CONTEXT1_CNTL,
                                    RANGE_PROTECTION_FAULT_ENABLE_DEFAULT, 1);
                tmp = REG_SET_FIELD(tmp, VML2VC0_VM_CONTEXT1_CNTL,
@@ -323,7 +331,7 @@ static void mmhub_v9_4_setup_vmid_config(struct amdgpu_device *adev, int hubid)
                                    EXECUTE_PROTECTION_FAULT_ENABLE_DEFAULT, 1);
                tmp = REG_SET_FIELD(tmp, VML2VC0_VM_CONTEXT1_CNTL,
                                    PAGE_TABLE_BLOCK_SIZE,
-                                   adev->vm_manager.block_size - 9);
+                                   block_size);
                /* Send no-retry XNACK on fault to suppress VM fault storm. */
                tmp = REG_SET_FIELD(tmp, VML2VC0_VM_CONTEXT1_CNTL,
                                    RETRY_PERMISSION_OR_INVALID_PAGE_FAULT,
index 4b5396d..eec13cb 100644 (file)
@@ -409,9 +409,11 @@ static u32 navi10_ih_get_wptr(struct amdgpu_device *adev,
        u32 wptr, tmp;
        struct amdgpu_ih_regs *ih_regs;
 
-       if (ih == &adev->irq.ih) {
+       if (ih == &adev->irq.ih || ih == &adev->irq.ih_soft) {
                /* Only ring0 supports writeback. On other rings fall back
                 * to register-based code with overflow checking below.
+                * ih_soft ring doesn't have any backing hardware registers,
+                * update wptr and return.
                 */
                wptr = le32_to_cpu(*ih->wptr_cpu);
 
@@ -483,6 +485,9 @@ static void navi10_ih_set_rptr(struct amdgpu_device *adev,
 {
        struct amdgpu_ih_regs *ih_regs;
 
+       if (ih == &adev->irq.ih_soft)
+               return;
+
        if (ih->use_doorbell) {
                /* XXX check if swapping is necessary on BE */
                *ih->rptr_cpu = ih->rptr;
index b465baa..aa761ff 100644 (file)
@@ -380,6 +380,7 @@ static void nbio_v2_3_enable_aspm(struct amdgpu_device *adev,
                WREG32_PCIE(smnPCIE_LC_CNTL, data);
 }
 
+#ifdef CONFIG_PCIEASPM
 static void nbio_v2_3_program_ltr(struct amdgpu_device *adev)
 {
        uint32_t def, data;
@@ -401,9 +402,11 @@ static void nbio_v2_3_program_ltr(struct amdgpu_device *adev)
        if (def != data)
                WREG32_PCIE(smnBIF_CFG_DEV0_EPF0_DEVICE_CNTL2, data);
 }
+#endif
 
 static void nbio_v2_3_program_aspm(struct amdgpu_device *adev)
 {
+#ifdef CONFIG_PCIEASPM
        uint32_t def, data;
 
        def = data = RREG32_PCIE(smnPCIE_LC_CNTL);
@@ -459,7 +462,10 @@ static void nbio_v2_3_program_aspm(struct amdgpu_device *adev)
        if (def != data)
                WREG32_PCIE(smnPCIE_LC_CNTL6, data);
 
-       nbio_v2_3_program_ltr(adev);
+       /* Don't bother about LTR if LTR is not enabled
+        * in the path */
+       if (adev->pdev->ltr_path)
+               nbio_v2_3_program_ltr(adev);
 
        def = data = RREG32_SOC15(NBIO, 0, mmRCC_BIF_STRAP3);
        data |= 0x5DE0 << RCC_BIF_STRAP3__STRAP_VLINK_ASPM_IDLE_TIMER__SHIFT;
@@ -483,6 +489,7 @@ static void nbio_v2_3_program_aspm(struct amdgpu_device *adev)
        data &= ~PCIE_LC_CNTL3__LC_DSC_DONT_ENTER_L23_AFTER_PME_ACK_MASK;
        if (def != data)
                WREG32_PCIE(smnPCIE_LC_CNTL3, data);
+#endif
 }
 
 static void nbio_v2_3_apply_lc_spc_mode_wa(struct amdgpu_device *adev)
index f7f6dde..37615a7 100644 (file)
@@ -282,6 +282,7 @@ static void nbio_v6_1_init_registers(struct amdgpu_device *adev)
                        mmBIF_BX_DEV0_EPF0_VF0_HDP_MEM_COHERENCY_FLUSH_CNTL) << 2;
 }
 
+#ifdef CONFIG_PCIEASPM
 static void nbio_v6_1_program_ltr(struct amdgpu_device *adev)
 {
        uint32_t def, data;
@@ -303,9 +304,11 @@ static void nbio_v6_1_program_ltr(struct amdgpu_device *adev)
        if (def != data)
                WREG32_PCIE(smnBIF_CFG_DEV0_EPF0_DEVICE_CNTL2, data);
 }
+#endif
 
 static void nbio_v6_1_program_aspm(struct amdgpu_device *adev)
 {
+#ifdef CONFIG_PCIEASPM
        uint32_t def, data;
 
        def = data = RREG32_PCIE(smnPCIE_LC_CNTL);
@@ -361,7 +364,10 @@ static void nbio_v6_1_program_aspm(struct amdgpu_device *adev)
        if (def != data)
                WREG32_PCIE(smnPCIE_LC_CNTL6, data);
 
-       nbio_v6_1_program_ltr(adev);
+       /* Don't bother about LTR if LTR is not enabled
+        * in the path */
+       if (adev->pdev->ltr_path)
+               nbio_v6_1_program_ltr(adev);
 
        def = data = RREG32_PCIE(smnRCC_BIF_STRAP3);
        data |= 0x5DE0 << RCC_BIF_STRAP3__STRAP_VLINK_ASPM_IDLE_TIMER__SHIFT;
@@ -385,6 +391,7 @@ static void nbio_v6_1_program_aspm(struct amdgpu_device *adev)
        data &= ~PCIE_LC_CNTL3__LC_DSC_DONT_ENTER_L23_AFTER_PME_ACK_MASK;
        if (def != data)
                WREG32_PCIE(smnPCIE_LC_CNTL3, data);
+#endif
 }
 
 const struct amdgpu_nbio_funcs nbio_v6_1_funcs = {
index 11848d1..19455a7 100644 (file)
@@ -673,6 +673,7 @@ struct amdgpu_nbio_ras nbio_v7_4_ras = {
 };
 
 
+#ifdef CONFIG_PCIEASPM
 static void nbio_v7_4_program_ltr(struct amdgpu_device *adev)
 {
        uint32_t def, data;
@@ -694,9 +695,11 @@ static void nbio_v7_4_program_ltr(struct amdgpu_device *adev)
        if (def != data)
                WREG32_PCIE(smnBIF_CFG_DEV0_EPF0_DEVICE_CNTL2, data);
 }
+#endif
 
 static void nbio_v7_4_program_aspm(struct amdgpu_device *adev)
 {
+#ifdef CONFIG_PCIEASPM
        uint32_t def, data;
 
        if (adev->ip_versions[NBIO_HWIP][0] == IP_VERSION(7, 4, 4))
@@ -755,7 +758,10 @@ static void nbio_v7_4_program_aspm(struct amdgpu_device *adev)
        if (def != data)
                WREG32_PCIE(smnPCIE_LC_CNTL6, data);
 
-       nbio_v7_4_program_ltr(adev);
+       /* Don't bother about LTR if LTR is not enabled
+        * in the path */
+       if (adev->pdev->ltr_path)
+               nbio_v7_4_program_ltr(adev);
 
        def = data = RREG32_PCIE(smnRCC_BIF_STRAP3);
        data |= 0x5DE0 << RCC_BIF_STRAP3__STRAP_VLINK_ASPM_IDLE_TIMER__SHIFT;
@@ -779,6 +785,7 @@ static void nbio_v7_4_program_aspm(struct amdgpu_device *adev)
        data &= ~PCIE_LC_CNTL3__LC_DSC_DONT_ENTER_L23_AFTER_PME_ACK_MASK;
        if (def != data)
                WREG32_PCIE(smnPCIE_LC_CNTL3, data);
+#endif
 }
 
 const struct amdgpu_nbio_funcs nbio_v7_4_funcs = {
index 01e8288..def8937 100644 (file)
 #include "nbio/nbio_7_7_0_sh_mask.h"
 #include <uapi/linux/kfd_ioctl.h>
 
+static void nbio_v7_7_remap_hdp_registers(struct amdgpu_device *adev)
+{
+       WREG32_SOC15(NBIO, 0, regBIF_BX0_REMAP_HDP_MEM_FLUSH_CNTL,
+                    adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL);
+       WREG32_SOC15(NBIO, 0, regBIF_BX0_REMAP_HDP_REG_FLUSH_CNTL,
+                    adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_REG_FLUSH_CNTL);
+}
+
 static u32 nbio_v7_7_get_rev_id(struct amdgpu_device *adev)
 {
        u32 tmp;
@@ -68,12 +76,6 @@ static void nbio_v7_7_sdma_doorbell_range(struct amdgpu_device *adev, int instan
                doorbell_range = REG_SET_FIELD(doorbell_range,
                                               GDC0_BIF_CSDMA_DOORBELL_RANGE,
                                               SIZE, doorbell_size);
-               doorbell_range = REG_SET_FIELD(doorbell_range,
-                                              GDC0_BIF_SDMA0_DOORBELL_RANGE,
-                                              OFFSET, doorbell_index);
-               doorbell_range = REG_SET_FIELD(doorbell_range,
-                                              GDC0_BIF_SDMA0_DOORBELL_RANGE,
-                                              SIZE, doorbell_size);
        } else {
                doorbell_range = REG_SET_FIELD(doorbell_range,
                                               GDC0_BIF_SDMA0_DOORBELL_RANGE,
@@ -247,6 +249,81 @@ static void nbio_v7_7_init_registers(struct amdgpu_device *adev)
 
 }
 
+static void nbio_v7_7_update_medium_grain_clock_gating(struct amdgpu_device *adev,
+                                                      bool enable)
+{
+       uint32_t def, data;
+
+       if (enable && !(adev->cg_flags & AMD_CG_SUPPORT_BIF_MGCG))
+               return;
+
+       def = data = RREG32_SOC15(NBIO, 0, regBIF0_CPM_CONTROL);
+       if (enable) {
+               data |= (BIF0_CPM_CONTROL__LCLK_DYN_GATE_ENABLE_MASK |
+                        BIF0_CPM_CONTROL__TXCLK_DYN_GATE_ENABLE_MASK |
+                        BIF0_CPM_CONTROL__TXCLK_LCNT_GATE_ENABLE_MASK |
+                        BIF0_CPM_CONTROL__TXCLK_REGS_GATE_ENABLE_MASK |
+                        BIF0_CPM_CONTROL__TXCLK_PRBS_GATE_ENABLE_MASK |
+                        BIF0_CPM_CONTROL__REFCLK_REGS_GATE_ENABLE_MASK);
+       } else {
+               data &= ~(BIF0_CPM_CONTROL__LCLK_DYN_GATE_ENABLE_MASK |
+                         BIF0_CPM_CONTROL__TXCLK_DYN_GATE_ENABLE_MASK |
+                         BIF0_CPM_CONTROL__TXCLK_LCNT_GATE_ENABLE_MASK |
+                         BIF0_CPM_CONTROL__TXCLK_REGS_GATE_ENABLE_MASK |
+                         BIF0_CPM_CONTROL__TXCLK_PRBS_GATE_ENABLE_MASK |
+                         BIF0_CPM_CONTROL__REFCLK_REGS_GATE_ENABLE_MASK);
+       }
+
+       if (def != data)
+               WREG32_SOC15(NBIO, 0, regBIF0_CPM_CONTROL, data);
+}
+
+static void nbio_v7_7_update_medium_grain_light_sleep(struct amdgpu_device *adev,
+                                                     bool enable)
+{
+       uint32_t def, data;
+
+       if (enable && !(adev->cg_flags & AMD_CG_SUPPORT_BIF_LS))
+               return;
+
+       def = data = RREG32_SOC15(NBIO, 0, regBIF0_PCIE_CNTL2);
+       if (enable)
+               data |= BIF0_PCIE_CNTL2__SLV_MEM_LS_EN_MASK;
+       else
+               data &= ~BIF0_PCIE_CNTL2__SLV_MEM_LS_EN_MASK;
+
+       if (def != data)
+               WREG32_SOC15(NBIO, 0, regBIF0_PCIE_CNTL2, data);
+
+       def = data = RREG32_SOC15(NBIO, 0, regBIF0_PCIE_TX_POWER_CTRL_1);
+       if (enable) {
+               data |= (BIF0_PCIE_TX_POWER_CTRL_1__MST_MEM_LS_EN_MASK |
+                       BIF0_PCIE_TX_POWER_CTRL_1__REPLAY_MEM_LS_EN_MASK);
+       } else {
+               data &= ~(BIF0_PCIE_TX_POWER_CTRL_1__MST_MEM_LS_EN_MASK |
+                       BIF0_PCIE_TX_POWER_CTRL_1__REPLAY_MEM_LS_EN_MASK);
+       }
+
+       if (def != data)
+               WREG32_SOC15(NBIO, 0, regBIF0_PCIE_TX_POWER_CTRL_1, data);
+}
+
+static void nbio_v7_7_get_clockgating_state(struct amdgpu_device *adev,
+                                           u64 *flags)
+{
+       uint32_t data;
+
+       /* AMD_CG_SUPPORT_BIF_MGCG */
+       data = RREG32_SOC15(NBIO, 0, regBIF0_CPM_CONTROL);
+       if (data & BIF0_CPM_CONTROL__LCLK_DYN_GATE_ENABLE_MASK)
+               *flags |= AMD_CG_SUPPORT_BIF_MGCG;
+
+       /* AMD_CG_SUPPORT_BIF_LS */
+       data = RREG32_SOC15(NBIO, 0, regBIF0_PCIE_CNTL2);
+       if (data & BIF0_PCIE_CNTL2__SLV_MEM_LS_EN_MASK)
+               *flags |= AMD_CG_SUPPORT_BIF_LS;
+}
+
 const struct amdgpu_nbio_funcs nbio_v7_7_funcs = {
        .get_hdp_flush_req_offset = nbio_v7_7_get_hdp_flush_req_offset,
        .get_hdp_flush_done_offset = nbio_v7_7_get_hdp_flush_done_offset,
@@ -262,6 +339,10 @@ const struct amdgpu_nbio_funcs nbio_v7_7_funcs = {
        .enable_doorbell_aperture = nbio_v7_7_enable_doorbell_aperture,
        .enable_doorbell_selfring_aperture = nbio_v7_7_enable_doorbell_selfring_aperture,
        .ih_doorbell_range = nbio_v7_7_ih_doorbell_range,
+       .update_medium_grain_clock_gating = nbio_v7_7_update_medium_grain_clock_gating,
+       .update_medium_grain_light_sleep = nbio_v7_7_update_medium_grain_light_sleep,
+       .get_clockgating_state = nbio_v7_7_get_clockgating_state,
        .ih_control = nbio_v7_7_ih_control,
        .init_registers = nbio_v7_7_init_registers,
+       .remap_hdp_registers = nbio_v7_7_remap_hdp_registers,
 };
index a258820..0b2ac41 100644 (file)
@@ -101,6 +101,16 @@ static int psp_v12_0_init_microcode(struct psp_context *psp)
                adev->psp.dtm_context.context.bin_desc.start_addr =
                        (uint8_t *)adev->psp.hdcp_context.context.bin_desc.start_addr +
                        le32_to_cpu(ta_hdr->dtm.offset_bytes);
+
+               if (adev->apu_flags & AMD_APU_IS_RENOIR) {
+                       adev->psp.securedisplay_context.context.bin_desc.fw_version =
+                               le32_to_cpu(ta_hdr->securedisplay.fw_version);
+                       adev->psp.securedisplay_context.context.bin_desc.size_bytes =
+                               le32_to_cpu(ta_hdr->securedisplay.size_bytes);
+                       adev->psp.securedisplay_context.context.bin_desc.start_addr =
+                               (uint8_t *)adev->psp.hdcp_context.context.bin_desc.start_addr +
+                               le32_to_cpu(ta_hdr->securedisplay.offset_bytes);
+               }
        }
 
        return 0;
index 726a5bb..a75a286 100644 (file)
@@ -20,7 +20,6 @@
  * OTHER DEALINGS IN THE SOFTWARE.
  *
  */
-#include <linux/dev_printk.h>
 #include <drm/drm_drv.h>
 #include <linux/vmalloc.h>
 #include "amdgpu.h"
index 65181ef..56424f7 100644 (file)
@@ -1504,6 +1504,11 @@ static int sdma_v4_0_start(struct amdgpu_device *adev)
                WREG32_SDMA(i, mmSDMA0_CNTL, temp);
 
                if (!amdgpu_sriov_vf(adev)) {
+                       ring = &adev->sdma.instance[i].ring;
+                       adev->nbio.funcs->sdma_doorbell_range(adev, i,
+                               ring->use_doorbell, ring->doorbell_index,
+                               adev->doorbell_index.sdma_doorbell_range);
+
                        /* unhalt engine */
                        temp = RREG32_SDMA(i, mmSDMA0_F32_CNTL);
                        temp = REG_SET_FIELD(temp, SDMA0_F32_CNTL, HALT, 0);
index fde6154..183024d 100644 (file)
@@ -1211,25 +1211,6 @@ static int soc15_common_sw_fini(void *handle)
        return 0;
 }
 
-static void soc15_doorbell_range_init(struct amdgpu_device *adev)
-{
-       int i;
-       struct amdgpu_ring *ring;
-
-       /* sdma/ih doorbell range are programed by hypervisor */
-       if (!amdgpu_sriov_vf(adev)) {
-               for (i = 0; i < adev->sdma.num_instances; i++) {
-                       ring = &adev->sdma.instance[i].ring;
-                       adev->nbio.funcs->sdma_doorbell_range(adev, i,
-                               ring->use_doorbell, ring->doorbell_index,
-                               adev->doorbell_index.sdma_doorbell_range);
-               }
-
-               adev->nbio.funcs->ih_doorbell_range(adev, adev->irq.ih.use_doorbell,
-                                               adev->irq.ih.doorbell_index);
-       }
-}
-
 static int soc15_common_hw_init(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
@@ -1249,12 +1230,6 @@ static int soc15_common_hw_init(void *handle)
 
        /* enable the doorbell aperture */
        soc15_enable_doorbell_aperture(adev, true);
-       /* HW doorbell routing policy: doorbell writing not
-        * in SDMA/IH/MM/ACV range will be routed to CP. So
-        * we need to init SDMA/IH/MM/ACV doorbell range prior
-        * to CP ip block init and ring test.
-        */
-       soc15_doorbell_range_init(adev);
 
        return 0;
 }
index 52816de..2e50db3 100644 (file)
@@ -421,6 +421,7 @@ static bool soc21_need_full_reset(struct amdgpu_device *adev)
 {
        switch (adev->ip_versions[GC_HWIP][0]) {
        case IP_VERSION(11, 0, 0):
+               return amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__UMC);
        case IP_VERSION(11, 0, 2):
                return false;
        default:
@@ -494,6 +495,20 @@ static void soc21_pre_asic_init(struct amdgpu_device *adev)
 {
 }
 
+static int soc21_update_umd_stable_pstate(struct amdgpu_device *adev,
+                                         bool enter)
+{
+       if (enter)
+               amdgpu_gfx_rlc_enter_safe_mode(adev);
+       else
+               amdgpu_gfx_rlc_exit_safe_mode(adev);
+
+       if (adev->gfx.funcs->update_perfmon_mgcg)
+               adev->gfx.funcs->update_perfmon_mgcg(adev, !enter);
+
+       return 0;
+}
+
 static const struct amdgpu_asic_funcs soc21_asic_funcs =
 {
        .read_disabled_bios = &soc21_read_disabled_bios,
@@ -513,6 +528,7 @@ static const struct amdgpu_asic_funcs soc21_asic_funcs =
        .supports_baco = &amdgpu_dpm_is_baco_supported,
        .pre_asic_init = &soc21_pre_asic_init,
        .query_video_codecs = &soc21_query_video_codecs,
+       .update_umd_stable_pstate = &soc21_update_umd_stable_pstate,
 };
 
 static int soc21_common_early_init(void *handle)
@@ -546,8 +562,10 @@ static int soc21_common_early_init(void *handle)
        case IP_VERSION(11, 0, 0):
                adev->cg_flags = AMD_CG_SUPPORT_GFX_CGCG |
                        AMD_CG_SUPPORT_GFX_CGLS |
+#if 0
                        AMD_CG_SUPPORT_GFX_3D_CGCG |
                        AMD_CG_SUPPORT_GFX_3D_CGLS |
+#endif
                        AMD_CG_SUPPORT_GFX_MGCG |
                        AMD_CG_SUPPORT_REPEATER_FGCG |
                        AMD_CG_SUPPORT_GFX_FGCG |
@@ -575,7 +593,9 @@ static int soc21_common_early_init(void *handle)
                        AMD_CG_SUPPORT_VCN_MGCG |
                        AMD_CG_SUPPORT_JPEG_MGCG |
                        AMD_CG_SUPPORT_ATHUB_MGCG |
-                       AMD_CG_SUPPORT_ATHUB_LS;
+                       AMD_CG_SUPPORT_ATHUB_LS |
+                       AMD_CG_SUPPORT_IH_CG |
+                       AMD_CG_SUPPORT_HDP_SD;
                adev->pg_flags =
                        AMD_PG_SUPPORT_VCN |
                        AMD_PG_SUPPORT_VCN_DPG |
@@ -586,9 +606,25 @@ static int soc21_common_early_init(void *handle)
                break;
        case IP_VERSION(11, 0, 1):
                adev->cg_flags =
+                       AMD_CG_SUPPORT_GFX_CGCG |
+                       AMD_CG_SUPPORT_GFX_CGLS |
+                       AMD_CG_SUPPORT_GFX_MGCG |
+                       AMD_CG_SUPPORT_GFX_FGCG |
+                       AMD_CG_SUPPORT_REPEATER_FGCG |
+                       AMD_CG_SUPPORT_GFX_PERF_CLK |
+                       AMD_CG_SUPPORT_MC_MGCG |
+                       AMD_CG_SUPPORT_MC_LS |
+                       AMD_CG_SUPPORT_HDP_MGCG |
+                       AMD_CG_SUPPORT_HDP_LS |
+                       AMD_CG_SUPPORT_ATHUB_MGCG |
+                       AMD_CG_SUPPORT_ATHUB_LS |
+                       AMD_CG_SUPPORT_IH_CG |
+                       AMD_CG_SUPPORT_BIF_MGCG |
+                       AMD_CG_SUPPORT_BIF_LS |
                        AMD_CG_SUPPORT_VCN_MGCG |
                        AMD_CG_SUPPORT_JPEG_MGCG;
                adev->pg_flags =
+                       AMD_PG_SUPPORT_GFX_PG |
                        AMD_PG_SUPPORT_JPEG;
                adev->external_rev_id = adev->rev_id + 0x1;
                break;
@@ -683,6 +719,8 @@ static int soc21_common_set_clockgating_state(void *handle,
 
        switch (adev->ip_versions[NBIO_HWIP][0]) {
        case IP_VERSION(4, 3, 0):
+       case IP_VERSION(4, 3, 1):
+       case IP_VERSION(7, 7, 0):
                adev->nbio.funcs->update_medium_grain_clock_gating(adev,
                                state == AMD_CG_STATE_GATE);
                adev->nbio.funcs->update_medium_grain_light_sleep(adev,
index ca14c3e..fb2d74f 100644 (file)
@@ -1115,7 +1115,7 @@ static int vcn_v4_0_start(struct amdgpu_device *adev)
  *
  * Stop VCN block with dpg mode
  */
-static int vcn_v4_0_stop_dpg_mode(struct amdgpu_device *adev, int inst_idx)
+static void vcn_v4_0_stop_dpg_mode(struct amdgpu_device *adev, int inst_idx)
 {
        uint32_t tmp;
 
@@ -1133,7 +1133,6 @@ static int vcn_v4_0_stop_dpg_mode(struct amdgpu_device *adev, int inst_idx)
        /* disable dynamic power gating mode */
        WREG32_P(SOC15_REG_OFFSET(VCN, inst_idx, regUVD_POWER_STATUS), 0,
                ~UVD_POWER_STATUS__UVD_PG_MODE_MASK);
-       return 0;
 }
 
 /**
@@ -1154,7 +1153,7 @@ static int vcn_v4_0_stop(struct amdgpu_device *adev)
                fw_shared->sq.queue_mode |= FW_QUEUE_DPG_HOLD_OFF;
 
                if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
-                       r = vcn_v4_0_stop_dpg_mode(adev, i);
+                       vcn_v4_0_stop_dpg_mode(adev, i);
                        continue;
                }
 
index cdd599a..1e83db0 100644 (file)
@@ -289,6 +289,10 @@ static int vega10_ih_irq_init(struct amdgpu_device *adev)
                }
        }
 
+       if (!amdgpu_sriov_vf(adev))
+               adev->nbio.funcs->ih_doorbell_range(adev, adev->irq.ih.use_doorbell,
+                                                   adev->irq.ih.doorbell_index);
+
        pci_set_master(adev->pdev);
 
        /* enable interrupts */
@@ -334,9 +338,11 @@ static u32 vega10_ih_get_wptr(struct amdgpu_device *adev,
        u32 wptr, tmp;
        struct amdgpu_ih_regs *ih_regs;
 
-       if (ih == &adev->irq.ih) {
+       if (ih == &adev->irq.ih || ih == &adev->irq.ih_soft) {
                /* Only ring0 supports writeback. On other rings fall back
                 * to register-based code with overflow checking below.
+                * ih_soft ring doesn't have any backing hardware registers,
+                * update wptr and return.
                 */
                wptr = le32_to_cpu(*ih->wptr_cpu);
 
@@ -409,6 +415,9 @@ static void vega10_ih_set_rptr(struct amdgpu_device *adev,
 {
        struct amdgpu_ih_regs *ih_regs;
 
+       if (ih == &adev->irq.ih_soft)
+               return;
+
        if (ih->use_doorbell) {
                /* XXX check if swapping is necessary on BE */
                *ih->rptr_cpu = ih->rptr;
index 3b4eb82..59dfca0 100644 (file)
@@ -340,6 +340,10 @@ static int vega20_ih_irq_init(struct amdgpu_device *adev)
                }
        }
 
+       if (!amdgpu_sriov_vf(adev))
+               adev->nbio.funcs->ih_doorbell_range(adev, adev->irq.ih.use_doorbell,
+                                                   adev->irq.ih.doorbell_index);
+
        pci_set_master(adev->pdev);
 
        /* enable interrupts */
@@ -385,9 +389,11 @@ static u32 vega20_ih_get_wptr(struct amdgpu_device *adev,
        u32 wptr, tmp;
        struct amdgpu_ih_regs *ih_regs;
 
-       if (ih == &adev->irq.ih) {
+       if (ih == &adev->irq.ih || ih == &adev->irq.ih_soft) {
                /* Only ring0 supports writeback. On other rings fall back
                 * to register-based code with overflow checking below.
+                * ih_soft ring doesn't have any backing hardware registers,
+                * update wptr and return.
                 */
                wptr = le32_to_cpu(*ih->wptr_cpu);
 
@@ -461,6 +467,9 @@ static void vega20_ih_set_rptr(struct amdgpu_device *adev,
 {
        struct amdgpu_ih_regs *ih_regs;
 
+       if (ih == &adev->irq.ih_soft)
+               return;
+
        if (ih->use_doorbell) {
                /* XXX check if swapping is necessary on BE */
                *ih->rptr_cpu = ih->rptr;
index 2b3d8bc..dc774dd 100644 (file)
@@ -874,7 +874,7 @@ static int kfd_ioctl_wait_events(struct file *filp, struct kfd_process *p,
        err = kfd_wait_on_events(p, args->num_events,
                        (void __user *)args->events_ptr,
                        (args->wait_for_all != 0),
-                       args->timeout, &args->wait_result);
+                       &args->timeout, &args->wait_result);
 
        return err;
 }
index f585383..22c0929 100644 (file)
@@ -102,13 +102,18 @@ static void kfd_device_info_set_sdma_info(struct kfd_dev *kfd)
 
        switch (sdma_version) {
        case IP_VERSION(6, 0, 0):
-       case IP_VERSION(6, 0, 1):
        case IP_VERSION(6, 0, 2):
                /* Reserve 1 for paging and 1 for gfx */
                kfd->device_info.num_reserved_sdma_queues_per_engine = 2;
                /* BIT(0)=engine-0 queue-0; BIT(1)=engine-1 queue-0; BIT(2)=engine-0 queue-1; ... */
                kfd->device_info.reserved_sdma_queues_bitmap = 0xFULL;
                break;
+       case IP_VERSION(6, 0, 1):
+               /* Reserve 1 for paging and 1 for gfx */
+               kfd->device_info.num_reserved_sdma_queues_per_engine = 2;
+               /* BIT(0)=engine-0 queue-0; BIT(1)=engine-0 queue-1; ... */
+               kfd->device_info.reserved_sdma_queues_bitmap = 0x3ULL;
+               break;
        default:
                break;
        }
@@ -377,12 +382,8 @@ struct kfd_dev *kgd2kfd_probe(struct amdgpu_device *adev, bool vf)
                                f2g = &gfx_v10_3_kfd2kgd;
                        break;
                case IP_VERSION(10, 3, 6):
-                       gfx_target_version = 100306;
-                       if (!vf)
-                               f2g = &gfx_v10_3_kfd2kgd;
-                       break;
                case IP_VERSION(10, 3, 7):
-                       gfx_target_version = 100307;
+                       gfx_target_version = 100306;
                        if (!vf)
                                f2g = &gfx_v10_3_kfd2kgd;
                        break;
index 3942a56..83e3ce9 100644 (file)
@@ -894,7 +894,8 @@ static long user_timeout_to_jiffies(uint32_t user_timeout_ms)
        return msecs_to_jiffies(user_timeout_ms) + 1;
 }
 
-static void free_waiters(uint32_t num_events, struct kfd_event_waiter *waiters)
+static void free_waiters(uint32_t num_events, struct kfd_event_waiter *waiters,
+                        bool undo_auto_reset)
 {
        uint32_t i;
 
@@ -903,6 +904,9 @@ static void free_waiters(uint32_t num_events, struct kfd_event_waiter *waiters)
                        spin_lock(&waiters[i].event->lock);
                        remove_wait_queue(&waiters[i].event->wq,
                                          &waiters[i].wait);
+                       if (undo_auto_reset && waiters[i].activated &&
+                           waiters[i].event && waiters[i].event->auto_reset)
+                               set_event(waiters[i].event);
                        spin_unlock(&waiters[i].event->lock);
                }
 
@@ -911,7 +915,7 @@ static void free_waiters(uint32_t num_events, struct kfd_event_waiter *waiters)
 
 int kfd_wait_on_events(struct kfd_process *p,
                       uint32_t num_events, void __user *data,
-                      bool all, uint32_t user_timeout_ms,
+                      bool all, uint32_t *user_timeout_ms,
                       uint32_t *wait_result)
 {
        struct kfd_event_data __user *events =
@@ -920,7 +924,7 @@ int kfd_wait_on_events(struct kfd_process *p,
        int ret = 0;
 
        struct kfd_event_waiter *event_waiters = NULL;
-       long timeout = user_timeout_to_jiffies(user_timeout_ms);
+       long timeout = user_timeout_to_jiffies(*user_timeout_ms);
 
        event_waiters = alloc_event_waiters(num_events);
        if (!event_waiters) {
@@ -970,15 +974,11 @@ int kfd_wait_on_events(struct kfd_process *p,
                }
 
                if (signal_pending(current)) {
-                       /*
-                        * This is wrong when a nonzero, non-infinite timeout
-                        * is specified. We need to use
-                        * ERESTARTSYS_RESTARTBLOCK, but struct restart_block
-                        * contains a union with data for each user and it's
-                        * in generic kernel code that I don't want to
-                        * touch yet.
-                        */
                        ret = -ERESTARTSYS;
+                       if (*user_timeout_ms != KFD_EVENT_TIMEOUT_IMMEDIATE &&
+                           *user_timeout_ms != KFD_EVENT_TIMEOUT_INFINITE)
+                               *user_timeout_ms = jiffies_to_msecs(
+                                       max(0l, timeout-1));
                        break;
                }
 
@@ -1019,7 +1019,7 @@ int kfd_wait_on_events(struct kfd_process *p,
                                               event_waiters, events);
 
 out_unlock:
-       free_waiters(num_events, event_waiters);
+       free_waiters(num_events, event_waiters, ret == -ERESTARTSYS);
        mutex_unlock(&p->event_mutex);
 out:
        if (ret)
index d03a3b9..bf610e3 100644 (file)
@@ -1317,7 +1317,7 @@ void kfd_event_free_process(struct kfd_process *p);
 int kfd_event_mmap(struct kfd_process *process, struct vm_area_struct *vma);
 int kfd_wait_on_events(struct kfd_process *p,
                       uint32_t num_events, void __user *data,
-                      bool all, uint32_t user_timeout_ms,
+                      bool all, uint32_t *user_timeout_ms,
                       uint32_t *wait_result);
 void kfd_signal_event_interrupt(u32 pasid, uint32_t partial_id,
                                uint32_t valid_id_bits);
index a67ba88..11074cc 100644 (file)
@@ -541,7 +541,6 @@ svm_range_vram_node_new(struct amdgpu_device *adev, struct svm_range *prange,
                kfree(svm_bo);
                return -ESRCH;
        }
-       svm_bo->svms = prange->svms;
        svm_bo->eviction_fence =
                amdgpu_amdkfd_fence_create(dma_fence_context_alloc(1),
                                           mm,
@@ -3273,7 +3272,6 @@ int svm_range_schedule_evict_svm_bo(struct amdgpu_amdkfd_fence *fence)
 static void svm_range_evict_svm_bo_worker(struct work_struct *work)
 {
        struct svm_range_bo *svm_bo;
-       struct kfd_process *p;
        struct mm_struct *mm;
        int r = 0;
 
@@ -3281,13 +3279,12 @@ static void svm_range_evict_svm_bo_worker(struct work_struct *work)
        if (!svm_bo_ref_unless_zero(svm_bo))
                return; /* svm_bo was freed while eviction was pending */
 
-       /* svm_range_bo_release destroys this worker thread. So during
-        * the lifetime of this thread, kfd_process and mm will be valid.
-        */
-       p = container_of(svm_bo->svms, struct kfd_process, svms);
-       mm = p->mm;
-       if (!mm)
+       if (mmget_not_zero(svm_bo->eviction_fence->mm)) {
+               mm = svm_bo->eviction_fence->mm;
+       } else {
+               svm_range_bo_unref(svm_bo);
                return;
+       }
 
        mmap_read_lock(mm);
        spin_lock(&svm_bo->list_lock);
@@ -3305,8 +3302,7 @@ static void svm_range_evict_svm_bo_worker(struct work_struct *work)
 
                mutex_lock(&prange->migrate_mutex);
                do {
-                       r = svm_migrate_vram_to_ram(prange,
-                                               svm_bo->eviction_fence->mm,
+                       r = svm_migrate_vram_to_ram(prange, mm,
                                                KFD_MIGRATE_TRIGGER_TTM_EVICTION);
                } while (!r && prange->actual_loc && --retries);
 
@@ -3324,6 +3320,7 @@ static void svm_range_evict_svm_bo_worker(struct work_struct *work)
        }
        spin_unlock(&svm_bo->list_lock);
        mmap_read_unlock(mm);
+       mmput(mm);
 
        dma_fence_signal(&svm_bo->eviction_fence->base);
 
index 9156b04..cfac13a 100644 (file)
@@ -46,7 +46,6 @@ struct svm_range_bo {
        spinlock_t                      list_lock;
        struct amdgpu_amdkfd_fence      *eviction_fence;
        struct work_struct              eviction_work;
-       struct svm_range_list           *svms;
        uint32_t                        evicting;
        struct work_struct              release_work;
 };
index 25990be..3f0a4a4 100644 (file)
@@ -1392,8 +1392,8 @@ static int kfd_build_p2p_node_entry(struct kfd_topology_device *dev,
 
 static int kfd_create_indirect_link_prop(struct kfd_topology_device *kdev, int gpu_node)
 {
+       struct kfd_iolink_properties *gpu_link, *tmp_link, *cpu_link;
        struct kfd_iolink_properties *props = NULL, *props2 = NULL;
-       struct kfd_iolink_properties *gpu_link, *cpu_link;
        struct kfd_topology_device *cpu_dev;
        int ret = 0;
        int i, num_cpu;
@@ -1416,16 +1416,19 @@ static int kfd_create_indirect_link_prop(struct kfd_topology_device *kdev, int g
                        continue;
 
                /* find CPU <-->  CPU links */
+               cpu_link = NULL;
                cpu_dev = kfd_topology_device_by_proximity_domain(i);
                if (cpu_dev) {
-                       list_for_each_entry(cpu_link,
+                       list_for_each_entry(tmp_link,
                                        &cpu_dev->io_link_props, list) {
-                               if (cpu_link->node_to == gpu_link->node_to)
+                               if (tmp_link->node_to == gpu_link->node_to) {
+                                       cpu_link = tmp_link;
                                        break;
+                               }
                        }
                }
 
-               if (cpu_link->node_to != gpu_link->node_to)
+               if (!cpu_link)
                        return -ENOMEM;
 
                /* CPU <--> CPU <--> GPU, GPU node*/
index 8660d93..5140d9c 100644 (file)
@@ -3825,8 +3825,11 @@ static int amdgpu_dm_mode_config_init(struct amdgpu_device *adev)
        adev_to_drm(adev)->mode_config.max_height = 16384;
 
        adev_to_drm(adev)->mode_config.preferred_depth = 24;
-       /* disable prefer shadow for now due to hibernation issues */
-       adev_to_drm(adev)->mode_config.prefer_shadow = 0;
+       if (adev->asic_type == CHIP_HAWAII)
+               /* disable prefer shadow for now due to hibernation issues */
+               adev_to_drm(adev)->mode_config.prefer_shadow = 0;
+       else
+               adev_to_drm(adev)->mode_config.prefer_shadow = 1;
        /* indicates support for immediate flip */
        adev_to_drm(adev)->mode_config.async_page_flip = true;
 
@@ -4135,6 +4138,7 @@ static void register_backlight_device(struct amdgpu_display_manager *dm,
        }
 }
 
+static void amdgpu_set_panel_orientation(struct drm_connector *connector);
 
 /*
  * In this architecture, the association
@@ -4326,6 +4330,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
                                        adev_to_drm(adev)->vblank_disable_immediate = false;
                        }
                }
+               amdgpu_set_panel_orientation(&aconnector->base);
        }
 
        /* Software is initialized. Now we can register interrupt handlers. */
@@ -6684,6 +6689,10 @@ static void amdgpu_set_panel_orientation(struct drm_connector *connector)
            connector->connector_type != DRM_MODE_CONNECTOR_LVDS)
                return;
 
+       mutex_lock(&connector->dev->mode_config.mutex);
+       amdgpu_dm_connector_get_modes(connector);
+       mutex_unlock(&connector->dev->mode_config.mutex);
+
        encoder = amdgpu_dm_connector_to_encoder(connector);
        if (!encoder)
                return;
@@ -6728,8 +6737,6 @@ static void amdgpu_dm_connector_ddc_get_modes(struct drm_connector *connector,
                 * restored here.
                 */
                amdgpu_dm_update_freesync_caps(connector, edid);
-
-               amdgpu_set_panel_orientation(connector);
        } else {
                amdgpu_dm_connector->num_modes = 0;
        }
index 0e48824..ee242d9 100644 (file)
@@ -3288,6 +3288,7 @@ void crtc_debugfs_init(struct drm_crtc *crtc)
                                   &crc_win_y_end_fops);
        debugfs_create_file_unsafe("crc_win_update", 0644, dir, crtc,
                                   &crc_win_update_fops);
+       dput(dir);
 #endif
        debugfs_create_file("amdgpu_current_bpc", 0644, crtc->debugfs_entry,
                            crtc, &amdgpu_current_bpc_fops);
index b841b8b..987bde4 100644 (file)
@@ -34,6 +34,7 @@
 #include "dal_asic_id.h"
 #include "amdgpu_display.h"
 #include "amdgpu_dm_trace.h"
+#include "amdgpu_dm_plane.h"
 #include "gc/gc_11_0_0_offset.h"
 #include "gc/gc_11_0_0_sh_mask.h"
 
@@ -149,12 +150,12 @@ static void add_modifier(uint64_t **mods, uint64_t *size, uint64_t *cap, uint64_
        *size += 1;
 }
 
-bool modifier_has_dcc(uint64_t modifier)
+static bool modifier_has_dcc(uint64_t modifier)
 {
        return IS_AMD_FMT_MOD(modifier) && AMD_FMT_MOD_GET(DCC, modifier);
 }
 
-unsigned modifier_gfx9_swizzle_mode(uint64_t modifier)
+static unsigned modifier_gfx9_swizzle_mode(uint64_t modifier)
 {
        if (modifier == DRM_FORMAT_MOD_LINEAR)
                return 0;
@@ -660,7 +661,7 @@ static int get_plane_modifiers(struct amdgpu_device *adev, unsigned int plane_ty
                        add_gfx10_1_modifiers(adev, mods, &size, &capacity);
                break;
        case AMDGPU_FAMILY_GC_11_0_0:
-       case AMDGPU_FAMILY_GC_11_0_2:
+       case AMDGPU_FAMILY_GC_11_0_1:
                add_gfx11_modifiers(adev, mods, &size, &capacity);
                break;
        }
@@ -1412,7 +1413,7 @@ static bool dm_plane_format_mod_supported(struct drm_plane *plane,
                }
                break;
        case AMDGPU_FAMILY_GC_11_0_0:
-       case AMDGPU_FAMILY_GC_11_0_2:
+       case AMDGPU_FAMILY_GC_11_0_1:
                switch (AMD_FMT_MOD_GET(TILE, modifier)) {
                case AMD_FMT_MOD_TILE_GFX11_256K_R_X:
                case AMD_FMT_MOD_TILE_GFX9_64K_R_X:
index 95168c2..286981a 100644 (file)
@@ -36,17 +36,9 @@ int fill_dc_scaling_info(struct amdgpu_device *adev,
                         const struct drm_plane_state *state,
                         struct dc_scaling_info *scaling_info);
 
-void get_min_max_dc_plane_scaling(struct drm_device *dev,
-                                 struct drm_framebuffer *fb,
-                                 int *min_downscale, int *max_upscale);
-
 int dm_plane_helper_check_state(struct drm_plane_state *state,
                                struct drm_crtc_state *new_crtc_state);
 
-bool modifier_has_dcc(uint64_t modifier);
-
-unsigned int modifier_gfx9_swizzle_mode(uint64_t modifier);
-
 int fill_plane_buffer_attributes(struct amdgpu_device *adev,
                                 const struct amdgpu_framebuffer *afb,
                                 const enum surface_pixel_format format,
index 6767fab..352e9af 100644 (file)
@@ -100,3 +100,24 @@ void convert_float_matrix(
                matrix[i] = (uint16_t)reg_value;
        }
 }
+
+static uint32_t find_gcd(uint32_t a, uint32_t b)
+{
+       uint32_t remainder = 0;
+       while (b != 0) {
+               remainder = a % b;
+               a = b;
+               b = remainder;
+       }
+       return a;
+}
+
+void reduce_fraction(uint32_t num, uint32_t den,
+               uint32_t *out_num, uint32_t *out_den)
+{
+       uint32_t gcd = 0;
+
+       gcd = find_gcd(num, den);
+       *out_num = num / gcd;
+       *out_den = den / gcd;
+}
index ade785c..81da4e6 100644 (file)
@@ -38,6 +38,9 @@ void convert_float_matrix(
        struct fixed31_32 *flt,
        uint32_t buffer_size);
 
+void reduce_fraction(uint32_t num, uint32_t den,
+               uint32_t *out_num, uint32_t *out_den);
+
 static inline unsigned int log_2(unsigned int num)
 {
        return ilog2(num);
index 4c76091..f276abb 100644 (file)
@@ -337,7 +337,7 @@ struct clk_mgr *dc_clk_mgr_create(struct dc_context *ctx, struct pp_smu_funcs *p
            break;
        }
 
-       case AMDGPU_FAMILY_GC_11_0_2: {
+       case AMDGPU_FAMILY_GC_11_0_1: {
                struct clk_mgr_dcn314 *clk_mgr = kzalloc(sizeof(*clk_mgr), GFP_KERNEL);
 
                if (clk_mgr == NULL) {
@@ -397,7 +397,7 @@ void dc_destroy_clk_mgr(struct clk_mgr *clk_mgr_base)
                dcn32_clk_mgr_destroy(clk_mgr);
                break;
 
-       case AMDGPU_FAMILY_GC_11_0_2:
+       case AMDGPU_FAMILY_GC_11_0_1:
                dcn314_clk_mgr_destroy(clk_mgr);
                break;
 
index 0202dc6..ca6dfd2 100644 (file)
  */
 
 #include "dccg.h"
-#include "clk_mgr_internal.h"
+#include "rn_clk_mgr.h"
 
 #include "dcn20/dcn20_clk_mgr.h"
-#include "rn_clk_mgr.h"
 #include "dml/dcn20/dcn20_fpu.h"
 
 #include "dce100/dce_clk_mgr.h"
index 2e088c5..f131995 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "clk_mgr.h"
 #include "dm_pp_smu.h"
+#include "clk_mgr_internal.h"
 
 extern struct wm_table ddr4_wm_table_gs;
 extern struct wm_table lpddr4_wm_table_gs;
index ee99974..9781a8d 100644 (file)
@@ -307,16 +307,6 @@ static void dcn314_enable_pme_wa(struct clk_mgr *clk_mgr_base)
        dcn314_smu_enable_pme_wa(clk_mgr);
 }
 
-void dcn314_init_clocks(struct clk_mgr *clk_mgr)
-{
-       memset(&(clk_mgr->clks), 0, sizeof(struct dc_clocks));
-       // Assumption is that boot state always supports pstate
-       clk_mgr->clks.p_state_change_support = true;
-       clk_mgr->clks.prev_p_state_change_support = true;
-       clk_mgr->clks.pwr_state = DCN_PWR_STATE_UNKNOWN;
-       clk_mgr->clks.zstate_support = DCN_ZSTATE_SUPPORT_UNKNOWN;
-}
-
 bool dcn314_are_clock_states_equal(struct dc_clocks *a,
                struct dc_clocks *b)
 {
@@ -425,7 +415,7 @@ static struct wm_table lpddr5_wm_table = {
        }
 };
 
-static DpmClocks_t dummy_clocks;
+static DpmClocks314_t dummy_clocks;
 
 static struct dcn314_watermarks dummy_wms = { 0 };
 
@@ -510,7 +500,7 @@ static void dcn314_notify_wm_ranges(struct clk_mgr *clk_mgr_base)
 static void dcn314_get_dpm_table_from_smu(struct clk_mgr_internal *clk_mgr,
                struct dcn314_smu_dpm_clks *smu_dpm_clks)
 {
-       DpmClocks_t *table = smu_dpm_clks->dpm_clks;
+       DpmClocks314_t *table = smu_dpm_clks->dpm_clks;
 
        if (!clk_mgr->smu_ver)
                return;
@@ -527,6 +517,26 @@ static void dcn314_get_dpm_table_from_smu(struct clk_mgr_internal *clk_mgr,
        dcn314_smu_transfer_dpm_table_smu_2_dram(clk_mgr);
 }
 
+static inline bool is_valid_clock_value(uint32_t clock_value)
+{
+       return clock_value > 1 && clock_value < 100000;
+}
+
+static unsigned int convert_wck_ratio(uint8_t wck_ratio)
+{
+       switch (wck_ratio) {
+       case WCK_RATIO_1_2:
+               return 2;
+
+       case WCK_RATIO_1_4:
+               return 4;
+
+       default:
+               break;
+       }
+       return 1;
+}
+
 static uint32_t find_max_clk_value(const uint32_t clocks[], uint32_t num_clocks)
 {
        uint32_t max = 0;
@@ -540,89 +550,129 @@ static uint32_t find_max_clk_value(const uint32_t clocks[], uint32_t num_clocks)
        return max;
 }
 
-static unsigned int find_clk_for_voltage(
-               const DpmClocks_t *clock_table,
-               const uint32_t clocks[],
-               unsigned int voltage)
-{
-       int i;
-       int max_voltage = 0;
-       int clock = 0;
-
-       for (i = 0; i < NUM_SOC_VOLTAGE_LEVELS; i++) {
-               if (clock_table->SocVoltage[i] == voltage) {
-                       return clocks[i];
-               } else if (clock_table->SocVoltage[i] >= max_voltage &&
-                               clock_table->SocVoltage[i] < voltage) {
-                       max_voltage = clock_table->SocVoltage[i];
-                       clock = clocks[i];
-               }
-       }
-
-       ASSERT(clock);
-       return clock;
-}
-
 static void dcn314_clk_mgr_helper_populate_bw_params(struct clk_mgr_internal *clk_mgr,
                                                    struct integrated_info *bios_info,
-                                                   const DpmClocks_t *clock_table)
+                                                   const DpmClocks314_t *clock_table)
 {
-       int i, j;
        struct clk_bw_params *bw_params = clk_mgr->base.bw_params;
-       uint32_t max_dispclk = 0, max_dppclk = 0;
-
-       j = -1;
-
-       ASSERT(NUM_DF_PSTATE_LEVELS <= MAX_NUM_DPM_LVL);
-
-       /* Find lowest DPM, FCLK is filled in reverse order*/
+       struct clk_limit_table_entry def_max = bw_params->clk_table.entries[bw_params->clk_table.num_entries - 1];
+       uint32_t max_pstate = 0,  max_fclk = 0,  min_pstate = 0, max_dispclk = 0, max_dppclk = 0;
+       int i;
 
-       for (i = NUM_DF_PSTATE_LEVELS - 1; i >= 0; i--) {
-               if (clock_table->DfPstateTable[i].FClk != 0) {
-                       j = i;
-                       break;
+       /* Find highest valid fclk pstate */
+       for (i = 0; i < clock_table->NumDfPstatesEnabled; i++) {
+               if (is_valid_clock_value(clock_table->DfPstateTable[i].FClk) &&
+                   clock_table->DfPstateTable[i].FClk > max_fclk) {
+                       max_fclk = clock_table->DfPstateTable[i].FClk;
+                       max_pstate = i;
                }
        }
 
-       if (j == -1) {
-               /* clock table is all 0s, just use our own hardcode */
-               ASSERT(0);
-               return;
-       }
+       /* We expect the table to contain at least one valid fclk entry. */
+       ASSERT(is_valid_clock_value(max_fclk));
 
-       bw_params->clk_table.num_entries = j + 1;
-
-       /* dispclk and dppclk can be max at any voltage, same number of levels for both */
+       /* Dispclk and dppclk can be max at any voltage, same number of levels for both */
        if (clock_table->NumDispClkLevelsEnabled <= NUM_DISPCLK_DPM_LEVELS &&
            clock_table->NumDispClkLevelsEnabled <= NUM_DPPCLK_DPM_LEVELS) {
                max_dispclk = find_max_clk_value(clock_table->DispClocks, clock_table->NumDispClkLevelsEnabled);
                max_dppclk = find_max_clk_value(clock_table->DppClocks, clock_table->NumDispClkLevelsEnabled);
        } else {
+               /* Invalid number of entries in the table from PMFW. */
                ASSERT(0);
        }
 
-       for (i = 0; i < bw_params->clk_table.num_entries; i++, j--) {
-               bw_params->clk_table.entries[i].fclk_mhz = clock_table->DfPstateTable[j].FClk;
-               bw_params->clk_table.entries[i].memclk_mhz = clock_table->DfPstateTable[j].MemClk;
-               bw_params->clk_table.entries[i].voltage = clock_table->DfPstateTable[j].Voltage;
-               switch (clock_table->DfPstateTable[j].WckRatio) {
-               case WCK_RATIO_1_2:
-                       bw_params->clk_table.entries[i].wck_ratio = 2;
-                       break;
-               case WCK_RATIO_1_4:
-                       bw_params->clk_table.entries[i].wck_ratio = 4;
-                       break;
-               default:
-                       bw_params->clk_table.entries[i].wck_ratio = 1;
+       /* Base the clock table on dcfclk, need at least one entry regardless of pmfw table */
+       for (i = 0; i < clock_table->NumDcfClkLevelsEnabled; i++) {
+               uint32_t min_fclk = clock_table->DfPstateTable[0].FClk;
+               int j;
+
+               for (j = 1; j < clock_table->NumDfPstatesEnabled; j++) {
+                       if (is_valid_clock_value(clock_table->DfPstateTable[j].FClk) &&
+                           clock_table->DfPstateTable[j].FClk < min_fclk &&
+                           clock_table->DfPstateTable[j].Voltage <= clock_table->SocVoltage[i]) {
+                               min_fclk = clock_table->DfPstateTable[j].FClk;
+                               min_pstate = j;
+                       }
                }
-               bw_params->clk_table.entries[i].dcfclk_mhz = find_clk_for_voltage(clock_table, clock_table->DcfClocks, clock_table->DfPstateTable[j].Voltage);
-               bw_params->clk_table.entries[i].socclk_mhz = find_clk_for_voltage(clock_table, clock_table->SocClocks, clock_table->DfPstateTable[j].Voltage);
+
+               /* First search defaults for the clocks we don't read using closest lower or equal default dcfclk */
+               for (j = bw_params->clk_table.num_entries - 1; j > 0; j--)
+                       if (bw_params->clk_table.entries[j].dcfclk_mhz <= clock_table->DcfClocks[i])
+                               break;
+
+               bw_params->clk_table.entries[i].phyclk_mhz = bw_params->clk_table.entries[j].phyclk_mhz;
+               bw_params->clk_table.entries[i].phyclk_d18_mhz = bw_params->clk_table.entries[j].phyclk_d18_mhz;
+               bw_params->clk_table.entries[i].dtbclk_mhz = bw_params->clk_table.entries[j].dtbclk_mhz;
+
+               /* Now update clocks we do read */
+               bw_params->clk_table.entries[i].fclk_mhz = min_fclk;
+               bw_params->clk_table.entries[i].memclk_mhz = clock_table->DfPstateTable[min_pstate].MemClk;
+               bw_params->clk_table.entries[i].voltage = clock_table->DfPstateTable[min_pstate].Voltage;
+               bw_params->clk_table.entries[i].dcfclk_mhz = clock_table->DcfClocks[i];
+               bw_params->clk_table.entries[i].socclk_mhz = clock_table->SocClocks[i];
+               bw_params->clk_table.entries[i].dispclk_mhz = max_dispclk;
+               bw_params->clk_table.entries[i].dppclk_mhz = max_dppclk;
+               bw_params->clk_table.entries[i].wck_ratio = convert_wck_ratio(
+                       clock_table->DfPstateTable[min_pstate].WckRatio);
+       };
+
+       /* Make sure to include at least one entry at highest pstate */
+       if (max_pstate != min_pstate || i == 0) {
+               if (i > MAX_NUM_DPM_LVL - 1)
+                       i = MAX_NUM_DPM_LVL - 1;
+
+               bw_params->clk_table.entries[i].fclk_mhz = max_fclk;
+               bw_params->clk_table.entries[i].memclk_mhz = clock_table->DfPstateTable[max_pstate].MemClk;
+               bw_params->clk_table.entries[i].voltage = clock_table->DfPstateTable[max_pstate].Voltage;
+               bw_params->clk_table.entries[i].dcfclk_mhz = find_max_clk_value(clock_table->DcfClocks, NUM_DCFCLK_DPM_LEVELS);
+               bw_params->clk_table.entries[i].socclk_mhz = find_max_clk_value(clock_table->SocClocks, NUM_SOCCLK_DPM_LEVELS);
                bw_params->clk_table.entries[i].dispclk_mhz = max_dispclk;
                bw_params->clk_table.entries[i].dppclk_mhz = max_dppclk;
+               bw_params->clk_table.entries[i].wck_ratio = convert_wck_ratio(
+                       clock_table->DfPstateTable[max_pstate].WckRatio);
+               i++;
        }
+       bw_params->clk_table.num_entries = i--;
 
+       /* Make sure all highest clocks are included*/
+       bw_params->clk_table.entries[i].socclk_mhz = find_max_clk_value(clock_table->SocClocks, NUM_SOCCLK_DPM_LEVELS);
+       bw_params->clk_table.entries[i].dispclk_mhz = find_max_clk_value(clock_table->DispClocks, NUM_DISPCLK_DPM_LEVELS);
+       bw_params->clk_table.entries[i].dppclk_mhz = find_max_clk_value(clock_table->DppClocks, NUM_DPPCLK_DPM_LEVELS);
+       ASSERT(clock_table->DcfClocks[i] == find_max_clk_value(clock_table->DcfClocks, NUM_DCFCLK_DPM_LEVELS));
+       bw_params->clk_table.entries[i].phyclk_mhz = def_max.phyclk_mhz;
+       bw_params->clk_table.entries[i].phyclk_d18_mhz = def_max.phyclk_d18_mhz;
+       bw_params->clk_table.entries[i].dtbclk_mhz = def_max.dtbclk_mhz;
+
+       /*
+        * Set any 0 clocks to max default setting. Not an issue for
+        * power since we aren't doing switching in such case anyway
+        */
+       for (i = 0; i < bw_params->clk_table.num_entries; i++) {
+               if (!bw_params->clk_table.entries[i].fclk_mhz) {
+                       bw_params->clk_table.entries[i].fclk_mhz = def_max.fclk_mhz;
+                       bw_params->clk_table.entries[i].memclk_mhz = def_max.memclk_mhz;
+                       bw_params->clk_table.entries[i].voltage = def_max.voltage;
+               }
+               if (!bw_params->clk_table.entries[i].dcfclk_mhz)
+                       bw_params->clk_table.entries[i].dcfclk_mhz = def_max.dcfclk_mhz;
+               if (!bw_params->clk_table.entries[i].socclk_mhz)
+                       bw_params->clk_table.entries[i].socclk_mhz = def_max.socclk_mhz;
+               if (!bw_params->clk_table.entries[i].dispclk_mhz)
+                       bw_params->clk_table.entries[i].dispclk_mhz = def_max.dispclk_mhz;
+               if (!bw_params->clk_table.entries[i].dppclk_mhz)
+                       bw_params->clk_table.entries[i].dppclk_mhz = def_max.dppclk_mhz;
+               if (!bw_params->clk_table.entries[i].phyclk_mhz)
+                       bw_params->clk_table.entries[i].phyclk_mhz = def_max.phyclk_mhz;
+               if (!bw_params->clk_table.entries[i].phyclk_d18_mhz)
+                       bw_params->clk_table.entries[i].phyclk_d18_mhz = def_max.phyclk_d18_mhz;
+               if (!bw_params->clk_table.entries[i].dtbclk_mhz)
+                       bw_params->clk_table.entries[i].dtbclk_mhz = def_max.dtbclk_mhz;
+       }
+       ASSERT(bw_params->clk_table.entries[i-1].dcfclk_mhz);
        bw_params->vram_type = bios_info->memory_type;
-       bw_params->num_channels = bios_info->ma_channel_number;
+
+       bw_params->dram_channel_width_bytes = bios_info->memory_type == 0x22 ? 8 : 4;
+       bw_params->num_channels = bios_info->ma_channel_number ? bios_info->ma_channel_number : 4;
 
        for (i = 0; i < WM_SET_COUNT; i++) {
                bw_params->wm_table.entries[i].wm_inst = i;
@@ -641,7 +691,7 @@ static struct clk_mgr_funcs dcn314_funcs = {
        .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
        .get_dtb_ref_clk_frequency = dcn31_get_dtb_ref_freq_khz,
        .update_clocks = dcn314_update_clocks,
-       .init_clocks = dcn314_init_clocks,
+       .init_clocks = dcn31_init_clocks,
        .enable_pme_wa = dcn314_enable_pme_wa,
        .are_clock_states_equal = dcn314_are_clock_states_equal,
        .notify_wm_ranges = dcn314_notify_wm_ranges
@@ -681,10 +731,10 @@ void dcn314_clk_mgr_construct(
        }
        ASSERT(clk_mgr->smu_wm_set.wm_set);
 
-       smu_dpm_clks.dpm_clks = (DpmClocks_t *)dm_helpers_allocate_gpu_mem(
+       smu_dpm_clks.dpm_clks = (DpmClocks314_t *)dm_helpers_allocate_gpu_mem(
                                clk_mgr->base.base.ctx,
                                DC_MEM_ALLOC_TYPE_FRAME_BUFFER,
-                               sizeof(DpmClocks_t),
+                               sizeof(DpmClocks314_t),
                                &smu_dpm_clks.mc_address.quad_part);
 
        if (smu_dpm_clks.dpm_clks == NULL) {
@@ -729,7 +779,7 @@ void dcn314_clk_mgr_construct(
        if (clk_mgr->base.base.ctx->dc->debug.pstate_enabled) {
                dcn314_get_dpm_table_from_smu(&clk_mgr->base, &smu_dpm_clks);
 
-               if (ctx->dc_bios && ctx->dc_bios->integrated_info) {
+               if (ctx->dc_bios && ctx->dc_bios->integrated_info && ctx->dc->config.use_default_clock_table == false) {
                        dcn314_clk_mgr_helper_populate_bw_params(
                                        &clk_mgr->base,
                                        ctx->dc_bios->integrated_info,
index c695a44..171f843 100644 (file)
@@ -42,7 +42,7 @@ struct clk_mgr_dcn314 {
 
 bool dcn314_are_clock_states_equal(struct dc_clocks *a,
                struct dc_clocks *b);
-void dcn314_init_clocks(struct clk_mgr *clk_mgr);
+
 void dcn314_update_clocks(struct clk_mgr *clk_mgr_base,
                        struct dc_state *context,
                        bool safe_to_lower);
index a7958dc..047d19e 100644 (file)
@@ -36,6 +36,37 @@ typedef enum {
        WCK_RATIO_MAX
 } WCK_RATIO_e;
 
+typedef struct {
+  uint32_t FClk;
+  uint32_t MemClk;
+  uint32_t Voltage;
+  uint8_t  WckRatio;
+  uint8_t  Spare[3];
+} DfPstateTable314_t;
+
+//Freq in MHz
+//Voltage in milli volts with 2 fractional bits
+typedef struct {
+  uint32_t DcfClocks[NUM_DCFCLK_DPM_LEVELS];
+  uint32_t DispClocks[NUM_DISPCLK_DPM_LEVELS];
+  uint32_t DppClocks[NUM_DPPCLK_DPM_LEVELS];
+  uint32_t SocClocks[NUM_SOCCLK_DPM_LEVELS];
+  uint32_t VClocks[NUM_VCN_DPM_LEVELS];
+  uint32_t DClocks[NUM_VCN_DPM_LEVELS];
+  uint32_t SocVoltage[NUM_SOC_VOLTAGE_LEVELS];
+  DfPstateTable314_t DfPstateTable[NUM_DF_PSTATE_LEVELS];
+
+  uint8_t  NumDcfClkLevelsEnabled;
+  uint8_t  NumDispClkLevelsEnabled; //Applies to both Dispclk and Dppclk
+  uint8_t  NumSocClkLevelsEnabled;
+  uint8_t  VcnClkLevelsEnabled;     //Applies to both Vclk and Dclk
+  uint8_t  NumDfPstatesEnabled;
+  uint8_t  spare[3];
+
+  uint32_t MinGfxClk;
+  uint32_t MaxGfxClk;
+} DpmClocks314_t;
+
 struct dcn314_watermarks {
        // Watermarks
        WatermarkRowGeneric_t WatermarkRow[WM_COUNT][NUM_WM_RANGES];
@@ -43,7 +74,7 @@ struct dcn314_watermarks {
 };
 
 struct dcn314_smu_dpm_clks {
-       DpmClocks_t *dpm_clks;
+       DpmClocks314_t *dpm_clks;
        union large_integer mc_address;
 };
 
index e42f44f..fb22c3d 100644 (file)
@@ -1074,8 +1074,15 @@ static void disable_dangling_plane(struct dc *dc, struct dc_state *context)
                struct dc_stream_state *old_stream =
                                dc->current_state->res_ctx.pipe_ctx[i].stream;
                bool should_disable = true;
-               bool pipe_split_change =
-                       context->res_ctx.pipe_ctx[i].top_pipe != dc->current_state->res_ctx.pipe_ctx[i].top_pipe;
+               bool pipe_split_change = false;
+
+               if ((context->res_ctx.pipe_ctx[i].top_pipe) &&
+                       (dc->current_state->res_ctx.pipe_ctx[i].top_pipe))
+                       pipe_split_change = context->res_ctx.pipe_ctx[i].top_pipe->pipe_idx !=
+                               dc->current_state->res_ctx.pipe_ctx[i].top_pipe->pipe_idx;
+               else
+                       pipe_split_change = context->res_ctx.pipe_ctx[i].top_pipe !=
+                               dc->current_state->res_ctx.pipe_ctx[i].top_pipe;
 
                for (j = 0; j < context->stream_count; j++) {
                        if (old_stream == context->streams[j]) {
@@ -1087,7 +1094,8 @@ static void disable_dangling_plane(struct dc *dc, struct dc_state *context)
                                dc->current_state->stream_count != context->stream_count)
                        should_disable = true;
 
-               if (old_stream && !dc->current_state->res_ctx.pipe_ctx[i].top_pipe) {
+               if (old_stream && !dc->current_state->res_ctx.pipe_ctx[i].top_pipe &&
+                               !dc->current_state->res_ctx.pipe_ctx[i].prev_odm_pipe) {
                        struct pipe_ctx *old_pipe, *new_pipe;
 
                        old_pipe = &dc->current_state->res_ctx.pipe_ctx[i];
@@ -3229,7 +3237,7 @@ static void commit_planes_for_stream(struct dc *dc,
                                odm_pipe->ttu_regs.min_ttu_vblank = MAX_TTU;
        }
 
-       if ((update_type != UPDATE_TYPE_FAST) && stream->update_flags.bits.dsc_changed) {
+       if ((update_type != UPDATE_TYPE_FAST) && stream->update_flags.bits.dsc_changed)
                if (top_pipe_to_program &&
                        top_pipe_to_program->stream_res.tg->funcs->lock_doublebuffer_enable) {
                        if (should_use_dmub_lock(stream->link)) {
@@ -3247,7 +3255,6 @@ static void commit_planes_for_stream(struct dc *dc,
                                top_pipe_to_program->stream_res.tg->funcs->lock_doublebuffer_enable(
                                                top_pipe_to_program->stream_res.tg);
                }
-       }
 
        if (should_lock_all_pipes && dc->hwss.interdependent_update_lock) {
                if (dc->hwss.subvp_pipe_control_lock)
@@ -3466,7 +3473,7 @@ static void commit_planes_for_stream(struct dc *dc,
                dc->hwss.pipe_control_lock(dc, top_pipe_to_program, false);
        }
 
-       if ((update_type != UPDATE_TYPE_FAST) && stream->update_flags.bits.dsc_changed) {
+       if ((update_type != UPDATE_TYPE_FAST) && stream->update_flags.bits.dsc_changed)
                if (top_pipe_to_program->stream_res.tg->funcs->lock_doublebuffer_enable) {
                        top_pipe_to_program->stream_res.tg->funcs->wait_for_state(
                                top_pipe_to_program->stream_res.tg,
@@ -3493,21 +3500,19 @@ static void commit_planes_for_stream(struct dc *dc,
                                top_pipe_to_program->stream_res.tg->funcs->lock_doublebuffer_disable(
                                        top_pipe_to_program->stream_res.tg);
                }
-       }
 
-       if (update_type != UPDATE_TYPE_FAST) {
+       if (update_type != UPDATE_TYPE_FAST)
                dc->hwss.post_unlock_program_front_end(dc, context);
 
-               /* Since phantom pipe programming is moved to post_unlock_program_front_end,
-                * move the SubVP lock to after the phantom pipes have been setup
-                */
-               if (should_lock_all_pipes && dc->hwss.interdependent_update_lock) {
-                       if (dc->hwss.subvp_pipe_control_lock)
-                               dc->hwss.subvp_pipe_control_lock(dc, context, false, should_lock_all_pipes, NULL, subvp_prev_use);
-               } else {
-                       if (dc->hwss.subvp_pipe_control_lock)
-                               dc->hwss.subvp_pipe_control_lock(dc, context, false, should_lock_all_pipes, top_pipe_to_program, subvp_prev_use);
-               }
+       /* Since phantom pipe programming is moved to post_unlock_program_front_end,
+        * move the SubVP lock to after the phantom pipes have been setup
+        */
+       if (should_lock_all_pipes && dc->hwss.interdependent_update_lock) {
+               if (dc->hwss.subvp_pipe_control_lock)
+                       dc->hwss.subvp_pipe_control_lock(dc, context, false, should_lock_all_pipes, NULL, subvp_prev_use);
+       } else {
+               if (dc->hwss.subvp_pipe_control_lock)
+                       dc->hwss.subvp_pipe_control_lock(dc, context, false, should_lock_all_pipes, top_pipe_to_program, subvp_prev_use);
        }
 
        // Fire manual trigger only when bottom plane is flipped
@@ -4292,7 +4297,7 @@ bool dc_is_dmub_outbox_supported(struct dc *dc)
            !dc->debug.dpia_debug.bits.disable_dpia)
                return true;
 
-       if (dc->ctx->asic_id.chip_family == AMDGPU_FAMILY_GC_11_0_2 &&
+       if (dc->ctx->asic_id.chip_family == AMDGPU_FAMILY_GC_11_0_1 &&
            !dc->debug.dpia_debug.bits.disable_dpia)
                return true;
 
@@ -4340,6 +4345,7 @@ void dc_enable_dmub_outbox(struct dc *dc)
        struct dc_context *dc_ctx = dc->ctx;
 
        dmub_enable_outbox_notification(dc_ctx->dmub_srv);
+       DC_LOG_DC("%s: dmub outbox notifications enabled\n", __func__);
 }
 
 /**
index 9e51338..66d2ae7 100644 (file)
@@ -3372,7 +3372,7 @@ bool dc_link_setup_psr(struct dc_link *link,
                switch(link->ctx->asic_id.chip_family) {
                case FAMILY_YELLOW_CARP:
                case AMDGPU_FAMILY_GC_10_3_6:
-               case AMDGPU_FAMILY_GC_11_0_2:
+               case AMDGPU_FAMILY_GC_11_0_1:
                        if(!dc->debug.disable_z10)
                                psr_context->psr_level.bits.SKIP_CRTC_DISABLE = false;
                        break;
index ffc0f1c..7dbab15 100644 (file)
@@ -169,7 +169,7 @@ enum dce_version resource_parse_asic_id(struct hw_asic_id asic_id)
                if (ASICREV_IS_GC_11_0_2(asic_id.hw_internal_rev))
                        dc_version = DCN_VERSION_3_21;
                break;
-       case AMDGPU_FAMILY_GC_11_0_2:
+       case AMDGPU_FAMILY_GC_11_0_1:
                dc_version = DCN_VERSION_3_14;
                break;
        default:
index f62d509..0c85ab5 100644 (file)
@@ -329,7 +329,7 @@ bool dc_stream_set_cursor_attributes(
 
        dc = stream->ctx->dc;
 
-       if (attributes->height * attributes->width * 4 > 16384)
+       if (dc->debug.allow_sw_cursor_fallback && attributes->height * attributes->width * 4 > 16384)
                if (stream->mall_stream_config.type == SUBVP_MAIN)
                        return false;
 
index 8e1e400..dbf8158 100644 (file)
@@ -47,7 +47,7 @@ struct aux_payload;
 struct set_config_cmd_payload;
 struct dmub_notification;
 
-#define DC_VER "3.2.196"
+#define DC_VER "3.2.198"
 
 #define MAX_SURFACES 3
 #define MAX_PLANES 6
@@ -213,6 +213,7 @@ struct dc_caps {
        uint32_t cache_num_ways;
        uint16_t subvp_fw_processing_delay_us;
        uint16_t subvp_prefetch_end_to_mall_start_us;
+       uint8_t subvp_swath_height_margin_lines; // subvp start line must be aligned to 2 x swath height
        uint16_t subvp_pstate_allow_width_us;
        uint16_t subvp_vertical_int_margin_us;
        bool seamless_odm;
@@ -352,6 +353,7 @@ struct dc_config {
        bool use_pipe_ctx_sync_logic;
        bool ignore_dpref_ss;
        bool enable_mipi_converter_optimization;
+       bool use_default_clock_table;
 };
 
 enum visual_confirm {
@@ -609,6 +611,7 @@ struct dc_bounding_box_overrides {
        int percent_of_ideal_drambw;
        int dram_clock_change_latency_ns;
        int dummy_clock_change_latency_ns;
+       int fclk_clock_change_latency_ns;
        /* This forces a hard min on the DCFCLK we use
         * for DML.  Unlike the debug option for forcing
         * DCFCLK, this override affects watermark calculations
@@ -742,6 +745,7 @@ struct dc_debug_options {
        bool disable_fixed_vs_aux_timeout_wa;
        bool force_disable_subvp;
        bool force_subvp_mclk_switch;
+       bool allow_sw_cursor_fallback;
        bool force_usr_allow;
        /* uses value at boot and disables switch */
        bool disable_dtb_ref_clk_switch;
@@ -751,6 +755,7 @@ struct dc_debug_options {
        uint32_t mst_start_top_delay;
        uint8_t psr_power_use_phy_fsm;
        enum dml_hostvm_override_opts dml_hostvm_override;
+       bool dml_disallow_alternate_prefetch_modes;
        bool use_legacy_soc_bb_mechanism;
        bool exit_idle_opt_for_cursor_updates;
        bool enable_single_display_2to1_odm_policy;
index 2d61c2a..52a61b3 100644 (file)
@@ -29,6 +29,7 @@
 #include "dm_helpers.h"
 #include "dc_hw_types.h"
 #include "core_types.h"
+#include "../basics/conversion.h"
 
 #define CTX dc_dmub_srv->ctx
 #define DC_LOGGER CTX->logger
@@ -275,8 +276,7 @@ void dc_dmub_srv_set_drr_manual_trigger_cmd(struct dc *dc, uint32_t tg_inst)
        union dmub_rb_cmd cmd = { 0 };
 
        cmd.drr_update.header.type = DMUB_CMD__FW_ASSISTED_MCLK_SWITCH;
-       // TODO: Uncomment once FW headers are promoted
-       //cmd.drr_update.header.sub_type = DMUB_CMD__FAMS_SET_MANUAL_TRIGGER;
+       cmd.drr_update.header.sub_type = DMUB_CMD__FAMS_SET_MANUAL_TRIGGER;
        cmd.drr_update.dmub_optc_state_req.tg_inst = tg_inst;
 
        cmd.drr_update.header.payload_bytes = sizeof(cmd.drr_update) - sizeof(cmd.drr_update.header);
@@ -417,44 +417,42 @@ static void populate_subvp_cmd_drr_info(struct dc *dc,
        struct dc_crtc_timing *main_timing = &subvp_pipe->stream->timing;
        struct dc_crtc_timing *phantom_timing = &subvp_pipe->stream->mall_stream_config.paired_stream->timing;
        struct dc_crtc_timing *drr_timing = &vblank_pipe->stream->timing;
-       int16_t drr_frame_us = 0;
-       int16_t min_drr_supported_us = 0;
-       int16_t max_drr_supported_us = 0;
-       int16_t max_drr_vblank_us = 0;
-       int16_t max_drr_mallregion_us = 0;
-       int16_t mall_region_us = 0;
-       int16_t prefetch_us = 0;
-       int16_t subvp_active_us = 0;
-       int16_t drr_active_us = 0;
-       int16_t min_vtotal_supported = 0;
-       int16_t max_vtotal_supported = 0;
+       uint16_t drr_frame_us = 0;
+       uint16_t min_drr_supported_us = 0;
+       uint16_t max_drr_supported_us = 0;
+       uint16_t max_drr_vblank_us = 0;
+       uint16_t max_drr_mallregion_us = 0;
+       uint16_t mall_region_us = 0;
+       uint16_t prefetch_us = 0;
+       uint16_t subvp_active_us = 0;
+       uint16_t drr_active_us = 0;
+       uint16_t min_vtotal_supported = 0;
+       uint16_t max_vtotal_supported = 0;
 
        pipe_data->pipe_config.vblank_data.drr_info.drr_in_use = true;
        pipe_data->pipe_config.vblank_data.drr_info.use_ramping = false; // for now don't use ramping
        pipe_data->pipe_config.vblank_data.drr_info.drr_window_size_ms = 4; // hardcode 4ms DRR window for now
 
-       drr_frame_us = div64_s64(drr_timing->v_total * drr_timing->h_total,
-                                (int64_t)(drr_timing->pix_clk_100hz * 100) * 1000000);
+       drr_frame_us = div64_u64(((uint64_t)drr_timing->v_total * drr_timing->h_total * 1000000),
+                       (((uint64_t)drr_timing->pix_clk_100hz * 100)));
        // P-State allow width and FW delays already included phantom_timing->v_addressable
-       mall_region_us = div64_s64(phantom_timing->v_addressable * phantom_timing->h_total,
-                                  (int64_t)(phantom_timing->pix_clk_100hz * 100) * 1000000);
+       mall_region_us = div64_u64(((uint64_t)phantom_timing->v_addressable * phantom_timing->h_total * 1000000),
+                       (((uint64_t)phantom_timing->pix_clk_100hz * 100)));
        min_drr_supported_us = drr_frame_us + mall_region_us + SUBVP_DRR_MARGIN_US;
-       min_vtotal_supported = div64_s64(drr_timing->pix_clk_100hz * 100 *
-                                        (div64_s64((int64_t)min_drr_supported_us, 1000000)),
-                                        (int64_t)drr_timing->h_total);
-
-       prefetch_us = div64_s64((phantom_timing->v_total - phantom_timing->v_front_porch) * phantom_timing->h_total,
-                               (int64_t)(phantom_timing->pix_clk_100hz * 100) * 1000000 +
-                               dc->caps.subvp_prefetch_end_to_mall_start_us);
-       subvp_active_us = div64_s64(main_timing->v_addressable * main_timing->h_total,
-                                   (int64_t)(main_timing->pix_clk_100hz * 100) * 1000000);
-       drr_active_us = div64_s64(drr_timing->v_addressable * drr_timing->h_total,
-                                 (int64_t)(drr_timing->pix_clk_100hz * 100) * 1000000);
-       max_drr_vblank_us = div64_s64((int64_t)(subvp_active_us - prefetch_us - drr_active_us), 2) + drr_active_us;
+       min_vtotal_supported = div64_u64(((uint64_t)drr_timing->pix_clk_100hz * 100 * min_drr_supported_us),
+                       (((uint64_t)drr_timing->h_total * 1000000)));
+
+       prefetch_us = div64_u64(((uint64_t)(phantom_timing->v_total - phantom_timing->v_front_porch) * phantom_timing->h_total * 1000000),
+                       (((uint64_t)phantom_timing->pix_clk_100hz * 100) + dc->caps.subvp_prefetch_end_to_mall_start_us));
+       subvp_active_us = div64_u64(((uint64_t)main_timing->v_addressable * main_timing->h_total * 1000000),
+                       (((uint64_t)main_timing->pix_clk_100hz * 100)));
+       drr_active_us = div64_u64(((uint64_t)drr_timing->v_addressable * drr_timing->h_total * 1000000),
+                       (((uint64_t)drr_timing->pix_clk_100hz * 100)));
+       max_drr_vblank_us = div64_u64((subvp_active_us - prefetch_us - drr_active_us), 2) + drr_active_us;
        max_drr_mallregion_us = subvp_active_us - prefetch_us - mall_region_us;
        max_drr_supported_us = max_drr_vblank_us > max_drr_mallregion_us ? max_drr_vblank_us : max_drr_mallregion_us;
-       max_vtotal_supported = div64_s64(drr_timing->pix_clk_100hz * 100 * (div64_s64((int64_t)max_drr_supported_us, 1000000)),
-                                        (int64_t)drr_timing->h_total);
+       max_vtotal_supported = div64_u64(((uint64_t)drr_timing->pix_clk_100hz * 100 * max_drr_supported_us),
+                       (((uint64_t)drr_timing->h_total * 1000000)));
 
        pipe_data->pipe_config.vblank_data.drr_info.min_vtotal_supported = min_vtotal_supported;
        pipe_data->pipe_config.vblank_data.drr_info.max_vtotal_supported = max_vtotal_supported;
@@ -548,10 +546,12 @@ static void update_subvp_prefetch_end_to_mall_start(struct dc *dc,
        struct dc_crtc_timing *phantom_timing1 = &subvp_pipes[1]->stream->mall_stream_config.paired_stream->timing;
        struct dmub_cmd_fw_assisted_mclk_switch_pipe_data_v2 *pipe_data = NULL;
 
-       subvp0_prefetch_us = div64_s64((phantom_timing0->v_total - phantom_timing0->v_front_porch) * phantom_timing0->h_total,
-                                      (int64_t)(phantom_timing0->pix_clk_100hz * 100) * 1000000 + dc->caps.subvp_prefetch_end_to_mall_start_us);
-       subvp1_prefetch_us = div64_s64((phantom_timing1->v_total - phantom_timing1->v_front_porch) * phantom_timing1->h_total,
-                                      (int64_t)(phantom_timing1->pix_clk_100hz * 100) * 1000000 + dc->caps.subvp_prefetch_end_to_mall_start_us);
+       subvp0_prefetch_us = div64_u64(((uint64_t)(phantom_timing0->v_total - phantom_timing0->v_front_porch) *
+                       (uint64_t)phantom_timing0->h_total * 1000000),
+                       (((uint64_t)phantom_timing0->pix_clk_100hz * 100) + dc->caps.subvp_prefetch_end_to_mall_start_us));
+       subvp1_prefetch_us = div64_u64(((uint64_t)(phantom_timing1->v_total - phantom_timing1->v_front_porch) *
+                       (uint64_t)phantom_timing1->h_total * 1000000),
+                       (((uint64_t)phantom_timing1->pix_clk_100hz * 100) + dc->caps.subvp_prefetch_end_to_mall_start_us));
 
        // Whichever SubVP PIPE has the smaller prefetch (including the prefetch end to mall start time)
        // should increase it's prefetch time to match the other
@@ -559,16 +559,17 @@ static void update_subvp_prefetch_end_to_mall_start(struct dc *dc,
                pipe_data = &cmd->fw_assisted_mclk_switch_v2.config_data.pipe_data[1];
                prefetch_delta_us = subvp0_prefetch_us - subvp1_prefetch_us;
                pipe_data->pipe_config.subvp_data.prefetch_to_mall_start_lines =
-                       div64_s64(((div64_s64((int64_t)(dc->caps.subvp_prefetch_end_to_mall_start_us + prefetch_delta_us), 1000000)) *
-                                  (phantom_timing1->pix_clk_100hz * 100) + phantom_timing1->h_total - 1),
-                                 (int64_t)phantom_timing1->h_total);
+                               div64_u64(((uint64_t)(dc->caps.subvp_prefetch_end_to_mall_start_us + prefetch_delta_us) *
+                                       ((uint64_t)phantom_timing1->pix_clk_100hz * 100) + ((uint64_t)phantom_timing1->h_total * 1000000 - 1)),
+                                       ((uint64_t)phantom_timing1->h_total * 1000000));
+
        } else if (subvp1_prefetch_us >  subvp0_prefetch_us) {
                pipe_data = &cmd->fw_assisted_mclk_switch_v2.config_data.pipe_data[0];
                prefetch_delta_us = subvp1_prefetch_us - subvp0_prefetch_us;
                pipe_data->pipe_config.subvp_data.prefetch_to_mall_start_lines =
-                       div64_s64(((div64_s64((int64_t)(dc->caps.subvp_prefetch_end_to_mall_start_us + prefetch_delta_us), 1000000)) *
-                                  (phantom_timing0->pix_clk_100hz * 100) + phantom_timing0->h_total - 1),
-                                 (int64_t)phantom_timing0->h_total);
+                               div64_u64(((uint64_t)(dc->caps.subvp_prefetch_end_to_mall_start_us + prefetch_delta_us) *
+                                       ((uint64_t)phantom_timing0->pix_clk_100hz * 100) + ((uint64_t)phantom_timing0->h_total * 1000000 - 1)),
+                                       ((uint64_t)phantom_timing0->h_total * 1000000));
        }
 }
 
@@ -601,6 +602,7 @@ static void populate_subvp_cmd_pipe_info(struct dc *dc,
                        &cmd->fw_assisted_mclk_switch_v2.config_data.pipe_data[cmd_pipe_index];
        struct dc_crtc_timing *main_timing = &subvp_pipe->stream->timing;
        struct dc_crtc_timing *phantom_timing = &subvp_pipe->stream->mall_stream_config.paired_stream->timing;
+       uint32_t out_num, out_den;
 
        pipe_data->mode = SUBVP;
        pipe_data->pipe_config.subvp_data.pix_clk_100hz = subvp_pipe->stream->timing.pix_clk_100hz;
@@ -612,6 +614,16 @@ static void populate_subvp_cmd_pipe_info(struct dc *dc,
                        main_timing->v_total - main_timing->v_front_porch - main_timing->v_addressable;
        pipe_data->pipe_config.subvp_data.mall_region_lines = phantom_timing->v_addressable;
        pipe_data->pipe_config.subvp_data.main_pipe_index = subvp_pipe->pipe_idx;
+       pipe_data->pipe_config.subvp_data.is_drr = subvp_pipe->stream->ignore_msa_timing_param;
+
+       /* Calculate the scaling factor from the src and dst height.
+        * e.g. If 3840x2160 being downscaled to 1920x1080, the scaling factor is 1/2.
+        * Reduce the fraction 1080/2160 = 1/2 for the "scaling factor"
+        */
+       reduce_fraction(subvp_pipe->stream->src.height, subvp_pipe->stream->dst.height, &out_num, &out_den);
+       // TODO: Uncomment below lines once DMCUB include headers are promoted
+       //pipe_data->pipe_config.subvp_data.scale_factor_numerator = out_num;
+       //pipe_data->pipe_config.subvp_data.scale_factor_denominator = out_den;
 
        // Prefetch lines is equal to VACTIVE + BP + VSYNC
        pipe_data->pipe_config.subvp_data.prefetch_lines =
@@ -619,13 +631,11 @@ static void populate_subvp_cmd_pipe_info(struct dc *dc,
 
        // Round up
        pipe_data->pipe_config.subvp_data.prefetch_to_mall_start_lines =
-               div64_s64(((div64_s64((int64_t)dc->caps.subvp_prefetch_end_to_mall_start_us, 1000000)) *
-                          (phantom_timing->pix_clk_100hz * 100) + phantom_timing->h_total - 1),
-                         (int64_t)phantom_timing->h_total);
+                       div64_u64(((uint64_t)dc->caps.subvp_prefetch_end_to_mall_start_us * ((uint64_t)phantom_timing->pix_clk_100hz * 100) +
+                                       ((uint64_t)phantom_timing->h_total * 1000000 - 1)), ((uint64_t)phantom_timing->h_total * 1000000));
        pipe_data->pipe_config.subvp_data.processing_delay_lines =
-               div64_s64(((div64_s64((int64_t)dc->caps.subvp_fw_processing_delay_us, 1000000)) *
-                          (phantom_timing->pix_clk_100hz * 100) + phantom_timing->h_total - 1),
-                         (int64_t)phantom_timing->h_total);
+                       div64_u64(((uint64_t)(dc->caps.subvp_fw_processing_delay_us) * ((uint64_t)phantom_timing->pix_clk_100hz * 100) +
+                                       ((uint64_t)phantom_timing->h_total * 1000000 - 1)), ((uint64_t)phantom_timing->h_total * 1000000));
        // Find phantom pipe index based on phantom stream
        for (j = 0; j < dc->res_pool->pipe_count; j++) {
                struct pipe_ctx *phantom_pipe = &context->res_ctx.pipe_ctx[j];
index a0af0f6..9544abf 100644 (file)
@@ -344,6 +344,7 @@ enum dc_detect_reason {
        DETECT_REASON_HPDRX,
        DETECT_REASON_FALLBACK,
        DETECT_REASON_RETRAIN,
+       DETECT_REASON_TDR,
 };
 
 bool dc_link_detect(struct dc_link *dc_link, enum dc_detect_reason reason);
index 213de8c..1653923 100644 (file)
@@ -543,9 +543,11 @@ static void dce112_get_pix_clk_dividers_helper (
                switch (pix_clk_params->color_depth) {
                case COLOR_DEPTH_101010:
                        actual_pixel_clock_100hz = (actual_pixel_clock_100hz * 5) >> 2;
+                       actual_pixel_clock_100hz -= actual_pixel_clock_100hz % 10;
                        break;
                case COLOR_DEPTH_121212:
                        actual_pixel_clock_100hz = (actual_pixel_clock_100hz * 6) >> 2;
+                       actual_pixel_clock_100hz -= actual_pixel_clock_100hz % 10;
                        break;
                case COLOR_DEPTH_161616:
                        actual_pixel_clock_100hz = actual_pixel_clock_100hz * 2;
index d4a6504..db7ca4b 100644 (file)
@@ -361,8 +361,6 @@ void dpp1_cnv_setup (
                select = INPUT_CSC_SELECT_ICSC;
                break;
        case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
-               pixel_format = 22;
-               break;
        case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616:
                pixel_format = 26; /* ARGB16161616_UNORM */
                break;
index b54c124..564e061 100644 (file)
@@ -278,9 +278,6 @@ void hubp1_program_pixel_format(
                                SURFACE_PIXEL_FORMAT, 10);
                break;
        case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
-               REG_UPDATE(DCSURF_SURFACE_CONFIG,
-                               SURFACE_PIXEL_FORMAT, 22);
-               break;
        case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616: /*we use crossbar already*/
                REG_UPDATE(DCSURF_SURFACE_CONFIG,
                                SURFACE_PIXEL_FORMAT, 26); /* ARGB16161616_UNORM */
index bed7837..5b5d952 100644 (file)
@@ -110,6 +110,7 @@ void dcn10_lock_all_pipes(struct dc *dc,
                 */
                if (pipe_ctx->top_pipe ||
                    !pipe_ctx->stream ||
+                   !pipe_ctx->plane_state ||
                    !tg->funcs->is_tg_enabled(tg))
                        continue;
 
index 7699743..8e93840 100644 (file)
@@ -131,6 +131,12 @@ struct mpcc *mpc1_get_mpcc_for_dpp(struct mpc_tree *tree, int dpp_id)
        while (tmp_mpcc != NULL) {
                if (tmp_mpcc->dpp_id == dpp_id)
                        return tmp_mpcc;
+
+               /* avoid circular linked list */
+               ASSERT(tmp_mpcc != tmp_mpcc->mpcc_bot);
+               if (tmp_mpcc == tmp_mpcc->mpcc_bot)
+                       break;
+
                tmp_mpcc = tmp_mpcc->mpcc_bot;
        }
        return NULL;
index e1a9a45..3fc300c 100644 (file)
@@ -465,6 +465,11 @@ void optc1_enable_optc_clock(struct timing_generator *optc, bool enable)
                                OTG_CLOCK_ON, 1,
                                1, 1000);
        } else  {
+
+               //last chance to clear underflow, otherwise, it will always there due to clock is off.
+               if (optc->funcs->is_optc_underflow_occurred(optc) == true)
+                       optc->funcs->clear_optc_underflow(optc);
+
                REG_UPDATE_2(OTG_CLOCK_CONTROL,
                                OTG_CLOCK_GATE_DIS, 0,
                                OTG_CLOCK_EN, 0);
index ea1f14a..eaa7032 100644 (file)
@@ -166,8 +166,6 @@ static void dpp2_cnv_setup (
                select = DCN2_ICSC_SELECT_ICSC_A;
                break;
        case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
-               pixel_format = 22;
-               break;
        case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616:
                pixel_format = 26; /* ARGB16161616_UNORM */
                break;
index 936af65..9570c21 100644 (file)
@@ -463,9 +463,6 @@ void hubp2_program_pixel_format(
                                SURFACE_PIXEL_FORMAT, 10);
                break;
        case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
-               REG_UPDATE(DCSURF_SURFACE_CONFIG,
-                               SURFACE_PIXEL_FORMAT, 22);
-               break;
        case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616: /*we use crossbar already*/
                REG_UPDATE(DCSURF_SURFACE_CONFIG,
                                SURFACE_PIXEL_FORMAT, 26); /* ARGB16161616_UNORM */
index 3d307dd..116f67a 100644 (file)
@@ -531,6 +531,12 @@ static struct mpcc *mpc2_get_mpcc_for_dpp(struct mpc_tree *tree, int dpp_id)
        while (tmp_mpcc != NULL) {
                if (tmp_mpcc->dpp_id == 0xf || tmp_mpcc->dpp_id == dpp_id)
                        return tmp_mpcc;
+
+               /* avoid circular linked list */
+               ASSERT(tmp_mpcc != tmp_mpcc->mpcc_bot);
+               if (tmp_mpcc == tmp_mpcc->mpcc_bot)
+                       break;
+
                tmp_mpcc = tmp_mpcc->mpcc_bot;
        }
        return NULL;
index c5e200d..5752271 100644 (file)
@@ -67,9 +67,15 @@ static uint32_t convert_and_clamp(
 void dcn21_dchvm_init(struct hubbub *hubbub)
 {
        struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
-       uint32_t riommu_active;
+       uint32_t riommu_active, prefetch_done;
        int i;
 
+       REG_GET(DCHVM_RIOMMU_STAT0, HOSTVM_PREFETCH_DONE, &prefetch_done);
+
+       if (prefetch_done) {
+               hubbub->riommu_active = true;
+               return;
+       }
        //Init DCHVM block
        REG_UPDATE(DCHVM_CTRL0, HOSTVM_INIT_REQ, 1);
 
index 77b00f8..4a668d6 100644 (file)
@@ -244,8 +244,6 @@ void dpp3_cnv_setup (
                select = INPUT_CSC_SELECT_ICSC;
                break;
        case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
-               pixel_format = 22;
-               break;
        case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616:
                pixel_format = 26; /* ARGB16161616_UNORM */
                break;
index 6a4dcaf..dc3e8df 100644 (file)
@@ -86,7 +86,7 @@ bool hubp3_program_surface_flip_and_addr(
                        VMID, address->vmid);
 
        if (address->type == PLN_ADDR_TYPE_GRPH_STEREO) {
-               REG_UPDATE(DCSURF_FLIP_CONTROL, SURFACE_FLIP_MODE_FOR_STEREOSYNC, 0x1);
+               REG_UPDATE(DCSURF_FLIP_CONTROL, SURFACE_FLIP_MODE_FOR_STEREOSYNC, 0);
                REG_UPDATE(DCSURF_FLIP_CONTROL, SURFACE_FLIP_IN_STEREOSYNC, 0x1);
 
        } else {
index 0a67f8a..d970766 100644 (file)
@@ -372,7 +372,7 @@ static struct stream_encoder *dcn303_stream_encoder_create(enum engine_id eng_id
        int afmt_inst;
 
        /* Mapping of VPG, AFMT, DME register blocks to DIO block instance */
-       if (eng_id <= ENGINE_ID_DIGE) {
+       if (eng_id <= ENGINE_ID_DIGB) {
                vpg_inst = eng_id;
                afmt_inst = eng_id;
        } else
index a788d16..ab70ebd 100644 (file)
@@ -104,6 +104,9 @@ static bool has_query_dp_alt(struct link_encoder *enc)
 {
        struct dc_dmub_srv *dc_dmub_srv = enc->ctx->dmub_srv;
 
+       if (enc->ctx->dce_version >= DCN_VERSION_3_15)
+               return true;
+
        /* Supports development firmware and firmware >= 4.0.11 */
        return dc_dmub_srv &&
               !(dc_dmub_srv->dmub->fw_version >= DMUB_FW_VERSION(4, 0, 0) &&
index 7c77c71..82c3b3a 100644 (file)
        SE_SF(DP_SYM32_ENC0_DP_SYM32_ENC_SDP_AUDIO_CONTROL0, AIP_ENABLE, mask_sh),\
        SE_SF(DP_SYM32_ENC0_DP_SYM32_ENC_SDP_AUDIO_CONTROL0, ACM_ENABLE, mask_sh),\
        SE_SF(DP_SYM32_ENC0_DP_SYM32_ENC_VID_CRC_CONTROL, CRC_ENABLE, mask_sh),\
-       SE_SF(DP_SYM32_ENC0_DP_SYM32_ENC_VID_CRC_CONTROL, CRC_CONT_MODE_ENABLE, mask_sh)
+       SE_SF(DP_SYM32_ENC0_DP_SYM32_ENC_VID_CRC_CONTROL, CRC_CONT_MODE_ENABLE, mask_sh),\
+       SE_SF(DP_SYM32_ENC0_DP_SYM32_ENC_HBLANK_CONTROL, HBLANK_MINIMUM_SYMBOL_WIDTH, mask_sh)
 
 
 #define DCN3_1_HPO_DP_STREAM_ENC_REG_FIELD_LIST(type) \
index 468a893..aedff18 100644 (file)
@@ -2153,7 +2153,7 @@ static bool dcn31_resource_construct(
                pool->base.usb4_dpia_count = 4;
        }
 
-       if (dc->ctx->asic_id.chip_family == AMDGPU_FAMILY_GC_11_0_2)
+       if (dc->ctx->asic_id.chip_family == AMDGPU_FAMILY_GC_11_0_1)
                pool->base.usb4_dpia_count = 4;
 
        /* Audio, Stream Encoders including HPO and virtual, MPC 3D LUTs */
index 41f8ec9..9014365 100644 (file)
@@ -32,7 +32,6 @@
        container_of(pool, struct dcn31_resource_pool, base)
 
 extern struct _vcs_dpi_ip_params_st dcn3_1_ip;
-extern struct _vcs_dpi_soc_bounding_box_st dcn3_1_soc;
 
 struct dcn31_resource_pool {
        struct resource_pool base;
index e3b5a95..702c28c 100644 (file)
 DCN314 = dcn314_resource.o dcn314_hwseq.o dcn314_init.o \
                dcn314_dio_stream_encoder.o dcn314_dccg.o dcn314_optc.o
 
-ifdef CONFIG_X86
-CFLAGS_$(AMDDALPATH)/dc/dcn314/dcn314_resource.o := -mhard-float -msse
-endif
-
-ifdef CONFIG_PPC64
-CFLAGS_$(AMDDALPATH)/dc/dcn314/dcn314_resource.o := -mhard-float -maltivec
-endif
-
-ifdef CONFIG_CC_IS_GCC
-ifeq ($(call cc-ifversion, -lt, 0701, y), y)
-IS_OLD_GCC = 1
-endif
-endif
-
-ifdef CONFIG_X86
-ifdef IS_OLD_GCC
-# Stack alignment mismatch, proceed with caution.
-# GCC < 7.1 cannot compile code using `double` and -mpreferred-stack-boundary=3
-# (8B stack alignment).
-CFLAGS_$(AMDDALPATH)/dc/dcn314/dcn314_resource.o += -mpreferred-stack-boundary=4
-else
-CFLAGS_$(AMDDALPATH)/dc/dcn314/dcn314_resource.o += -msse2
-endif
-endif
-
 AMD_DAL_DCN314 = $(addprefix $(AMDDALPATH)/dc/dcn314/,$(DCN314))
 
 AMD_DISPLAY_FILES += $(AMD_DAL_DCN314)
index b384f30..06d8638 100644 (file)
@@ -67,8 +67,7 @@ static void enc314_disable_fifo(struct stream_encoder *enc)
 {
        struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
 
-       REG_UPDATE_2(DIG_FIFO_CTRL0, DIG_FIFO_ENABLE, 0,
-                    DIG_FIFO_READ_START_LEVEL, 0);
+       REG_UPDATE(DIG_FIFO_CTRL0, DIG_FIFO_ENABLE, 0);
 }
 
 static void enc314_dp_set_odm_combine(
@@ -317,6 +316,7 @@ static void enc314_stream_encoder_dp_unblank(
        /* switch DP encoder to CRTC data, but reset it the fifo first. It may happen
         * that it overflows during mode transition, and sometimes doesn't recover.
         */
+       REG_UPDATE(DIG_FIFO_CTRL0, DIG_FIFO_READ_START_LEVEL, 0x7);
        REG_UPDATE(DP_STEER_FIFO, DP_STEER_FIFO_RESET, 1);
        udelay(10);
 
index 755c715..39931d4 100644 (file)
@@ -343,7 +343,10 @@ unsigned int dcn314_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsig
 {
        struct dc_stream_state *stream = pipe_ctx->stream;
        unsigned int odm_combine_factor = 0;
+       struct dc *dc = pipe_ctx->stream->ctx->dc;
+       bool two_pix_per_container = false;
 
+       two_pix_per_container = optc2_is_two_pixels_per_containter(&stream->timing);
        odm_combine_factor = get_odm_config(pipe_ctx, NULL);
 
        if (is_dp_128b_132b_signal(pipe_ctx)) {
@@ -355,16 +358,13 @@ unsigned int dcn314_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsig
                else
                        *k2_div = PIXEL_RATE_DIV_BY_4;
        } else if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
-               if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) {
+               if (two_pix_per_container) {
                        *k1_div = PIXEL_RATE_DIV_BY_1;
                        *k2_div = PIXEL_RATE_DIV_BY_2;
-               } else if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR422) {
-                       *k1_div = PIXEL_RATE_DIV_BY_2;
-                       *k2_div = PIXEL_RATE_DIV_BY_2;
                } else {
-                       if (odm_combine_factor == 1)
-                               *k2_div = PIXEL_RATE_DIV_BY_4;
-                       else if (odm_combine_factor == 2)
+                       *k1_div = PIXEL_RATE_DIV_BY_1;
+                       *k2_div = PIXEL_RATE_DIV_BY_4;
+                       if ((odm_combine_factor == 2) || dc->debug.enable_dp_dig_pixel_rate_div_policy)
                                *k2_div = PIXEL_RATE_DIV_BY_2;
                }
        }
@@ -374,3 +374,31 @@ unsigned int dcn314_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsig
 
        return odm_combine_factor;
 }
+
+void dcn314_set_pixels_per_cycle(struct pipe_ctx *pipe_ctx)
+{
+       uint32_t pix_per_cycle = 1;
+       uint32_t odm_combine_factor = 1;
+
+       if (!pipe_ctx || !pipe_ctx->stream || !pipe_ctx->stream_res.stream_enc)
+               return;
+
+       odm_combine_factor = get_odm_config(pipe_ctx, NULL);
+       if (optc2_is_two_pixels_per_containter(&pipe_ctx->stream->timing) || odm_combine_factor > 1
+               || dcn314_is_dp_dig_pixel_rate_div_policy(pipe_ctx))
+               pix_per_cycle = 2;
+
+       if (pipe_ctx->stream_res.stream_enc->funcs->set_input_mode)
+               pipe_ctx->stream_res.stream_enc->funcs->set_input_mode(pipe_ctx->stream_res.stream_enc,
+                               pix_per_cycle);
+}
+
+bool dcn314_is_dp_dig_pixel_rate_div_policy(struct pipe_ctx *pipe_ctx)
+{
+       struct dc *dc = pipe_ctx->stream->ctx->dc;
+
+       if (dc_is_dp_signal(pipe_ctx->stream->signal) && !is_dp_128b_132b_signal(pipe_ctx) &&
+               dc->debug.enable_dp_dig_pixel_rate_div_policy)
+               return true;
+       return false;
+}
index be0f5e4..d014580 100644 (file)
@@ -39,4 +39,8 @@ void dcn314_enable_power_gating_plane(struct dce_hwseq *hws, bool enable);
 
 unsigned int dcn314_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsigned int *k1_div, unsigned int *k2_div);
 
+void dcn314_set_pixels_per_cycle(struct pipe_ctx *pipe_ctx);
+
+bool dcn314_is_dp_dig_pixel_rate_div_policy(struct pipe_ctx *pipe_ctx);
+
 #endif /* __DC_HWSS_DCN314_H__ */
index b9debeb..fcf67eb 100644 (file)
@@ -145,6 +145,8 @@ static const struct hwseq_private_funcs dcn314_private_funcs = {
        .set_shaper_3dlut = dcn20_set_shaper_3dlut,
        .setup_hpo_hw_control = dcn31_setup_hpo_hw_control,
        .calculate_dccg_k1_k2_values = dcn314_calculate_dccg_k1_k2_values,
+       .set_pixels_per_cycle = dcn314_set_pixels_per_cycle,
+       .is_dp_dig_pixel_rate_div_policy = dcn314_is_dp_dig_pixel_rate_div_policy,
 };
 
 void dcn314_hw_sequencer_construct(struct dc *dc)
index 0c79802..38aa28e 100644 (file)
@@ -98,7 +98,8 @@ static void optc314_set_odm_combine(struct timing_generator *optc, int *opp_id,
        REG_UPDATE(OPTC_WIDTH_CONTROL,
                        OPTC_SEGMENT_WIDTH, mpcc_hactive);
 
-       REG_SET(OTG_H_TIMING_CNTL, 0, OTG_H_TIMING_DIV_MODE, opp_cnt - 1);
+       REG_UPDATE(OTG_H_TIMING_CNTL,
+                       OTG_H_TIMING_DIV_MODE, opp_cnt - 1);
        optc1->opp_count = opp_cnt;
 }
 
index 63861cd..2a2a4a9 100644 (file)
@@ -70,6 +70,7 @@
 #include "dce110/dce110_resource.h"
 #include "dml/display_mode_vba.h"
 #include "dml/dcn31/dcn31_fpu.h"
+#include "dml/dcn314/dcn314_fpu.h"
 #include "dcn314/dcn314_dccg.h"
 #include "dcn10/dcn10_resource.h"
 #include "dcn31/dcn31_panel_cntl.h"
@@ -132,155 +133,6 @@ static const struct IP_BASE DCN_BASE = { { { { 0x00000012, 0x000000C0, 0x000034C
 
 #define DC_LOGGER_INIT(logger)
 
-#define DCN3_14_DEFAULT_DET_SIZE 384
-#define DCN3_14_MAX_DET_SIZE 384
-#define DCN3_14_MIN_COMPBUF_SIZE_KB 128
-#define DCN3_14_CRB_SEGMENT_SIZE_KB 64
-struct _vcs_dpi_ip_params_st dcn3_14_ip = {
-       .VBlankNomDefaultUS = 668,
-       .gpuvm_enable = 1,
-       .gpuvm_max_page_table_levels = 1,
-       .hostvm_enable = 1,
-       .hostvm_max_page_table_levels = 2,
-       .rob_buffer_size_kbytes = 64,
-       .det_buffer_size_kbytes = DCN3_14_DEFAULT_DET_SIZE,
-       .config_return_buffer_size_in_kbytes = 1792,
-       .compressed_buffer_segment_size_in_kbytes = 64,
-       .meta_fifo_size_in_kentries = 32,
-       .zero_size_buffer_entries = 512,
-       .compbuf_reserved_space_64b = 256,
-       .compbuf_reserved_space_zs = 64,
-       .dpp_output_buffer_pixels = 2560,
-       .opp_output_buffer_lines = 1,
-       .pixel_chunk_size_kbytes = 8,
-       .meta_chunk_size_kbytes = 2,
-       .min_meta_chunk_size_bytes = 256,
-       .writeback_chunk_size_kbytes = 8,
-       .ptoi_supported = false,
-       .num_dsc = 4,
-       .maximum_dsc_bits_per_component = 10,
-       .dsc422_native_support = false,
-       .is_line_buffer_bpp_fixed = true,
-       .line_buffer_fixed_bpp = 48,
-       .line_buffer_size_bits = 789504,
-       .max_line_buffer_lines = 12,
-       .writeback_interface_buffer_size_kbytes = 90,
-       .max_num_dpp = 4,
-       .max_num_otg = 4,
-       .max_num_hdmi_frl_outputs = 1,
-       .max_num_wb = 1,
-       .max_dchub_pscl_bw_pix_per_clk = 4,
-       .max_pscl_lb_bw_pix_per_clk = 2,
-       .max_lb_vscl_bw_pix_per_clk = 4,
-       .max_vscl_hscl_bw_pix_per_clk = 4,
-       .max_hscl_ratio = 6,
-       .max_vscl_ratio = 6,
-       .max_hscl_taps = 8,
-       .max_vscl_taps = 8,
-       .dpte_buffer_size_in_pte_reqs_luma = 64,
-       .dpte_buffer_size_in_pte_reqs_chroma = 34,
-       .dispclk_ramp_margin_percent = 1,
-       .max_inter_dcn_tile_repeaters = 8,
-       .cursor_buffer_size = 16,
-       .cursor_chunk_size = 2,
-       .writeback_line_buffer_buffer_size = 0,
-       .writeback_min_hscl_ratio = 1,
-       .writeback_min_vscl_ratio = 1,
-       .writeback_max_hscl_ratio = 1,
-       .writeback_max_vscl_ratio = 1,
-       .writeback_max_hscl_taps = 1,
-       .writeback_max_vscl_taps = 1,
-       .dppclk_delay_subtotal = 46,
-       .dppclk_delay_scl = 50,
-       .dppclk_delay_scl_lb_only = 16,
-       .dppclk_delay_cnvc_formatter = 27,
-       .dppclk_delay_cnvc_cursor = 6,
-       .dispclk_delay_subtotal = 119,
-       .dynamic_metadata_vm_enabled = false,
-       .odm_combine_4to1_supported = false,
-       .dcc_supported = true,
-};
-
-struct _vcs_dpi_soc_bounding_box_st dcn3_14_soc = {
-               /*TODO: correct dispclk/dppclk voltage level determination*/
-       .clock_limits = {
-               {
-                       .state = 0,
-                       .dispclk_mhz = 1200.0,
-                       .dppclk_mhz = 1200.0,
-                       .phyclk_mhz = 600.0,
-                       .phyclk_d18_mhz = 667.0,
-                       .dscclk_mhz = 186.0,
-                       .dtbclk_mhz = 625.0,
-               },
-               {
-                       .state = 1,
-                       .dispclk_mhz = 1200.0,
-                       .dppclk_mhz = 1200.0,
-                       .phyclk_mhz = 810.0,
-                       .phyclk_d18_mhz = 667.0,
-                       .dscclk_mhz = 209.0,
-                       .dtbclk_mhz = 625.0,
-               },
-               {
-                       .state = 2,
-                       .dispclk_mhz = 1200.0,
-                       .dppclk_mhz = 1200.0,
-                       .phyclk_mhz = 810.0,
-                       .phyclk_d18_mhz = 667.0,
-                       .dscclk_mhz = 209.0,
-                       .dtbclk_mhz = 625.0,
-               },
-               {
-                       .state = 3,
-                       .dispclk_mhz = 1200.0,
-                       .dppclk_mhz = 1200.0,
-                       .phyclk_mhz = 810.0,
-                       .phyclk_d18_mhz = 667.0,
-                       .dscclk_mhz = 371.0,
-                       .dtbclk_mhz = 625.0,
-               },
-               {
-                       .state = 4,
-                       .dispclk_mhz = 1200.0,
-                       .dppclk_mhz = 1200.0,
-                       .phyclk_mhz = 810.0,
-                       .phyclk_d18_mhz = 667.0,
-                       .dscclk_mhz = 417.0,
-                       .dtbclk_mhz = 625.0,
-               },
-       },
-       .num_states = 5,
-       .sr_exit_time_us = 9.0,
-       .sr_enter_plus_exit_time_us = 11.0,
-       .sr_exit_z8_time_us = 442.0,
-       .sr_enter_plus_exit_z8_time_us = 560.0,
-       .writeback_latency_us = 12.0,
-       .dram_channel_width_bytes = 4,
-       .round_trip_ping_latency_dcfclk_cycles = 106,
-       .urgent_latency_pixel_data_only_us = 4.0,
-       .urgent_latency_pixel_mixed_with_vm_data_us = 4.0,
-       .urgent_latency_vm_data_only_us = 4.0,
-       .urgent_out_of_order_return_per_channel_pixel_only_bytes = 4096,
-       .urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 4096,
-       .urgent_out_of_order_return_per_channel_vm_only_bytes = 4096,
-       .pct_ideal_sdp_bw_after_urgent = 80.0,
-       .pct_ideal_dram_sdp_bw_after_urgent_pixel_only = 65.0,
-       .pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm = 60.0,
-       .pct_ideal_dram_sdp_bw_after_urgent_vm_only = 30.0,
-       .max_avg_sdp_bw_use_normal_percent = 60.0,
-       .max_avg_dram_bw_use_normal_percent = 60.0,
-       .fabric_datapath_to_dcn_data_return_bytes = 32,
-       .return_bus_width_bytes = 64,
-       .downspread_percent = 0.38,
-       .dcn_downspread_percent = 0.5,
-       .gpuvm_min_page_size_bytes = 4096,
-       .hostvm_min_page_size_bytes = 4096,
-       .do_urgent_latency_adjustment = false,
-       .urgent_latency_adjustment_fabric_clock_component_us = 0,
-       .urgent_latency_adjustment_fabric_clock_reference_mhz = 0,
-};
-
 enum dcn31_clk_src_array_id {
        DCN31_CLK_SRC_PLL0,
        DCN31_CLK_SRC_PLL1,
@@ -602,6 +454,7 @@ static const struct dcn31_hpo_dp_stream_encoder_registers hpo_dp_stream_enc_regs
        hpo_dp_stream_encoder_reg_list(0),
        hpo_dp_stream_encoder_reg_list(1),
        hpo_dp_stream_encoder_reg_list(2),
+       hpo_dp_stream_encoder_reg_list(3)
 };
 
 static const struct dcn31_hpo_dp_stream_encoder_shift hpo_dp_se_shift = {
@@ -1402,7 +1255,7 @@ static struct stream_encoder *dcn314_stream_encoder_create(
        int afmt_inst;
 
        /* Mapping of VPG, AFMT, DME register blocks to DIO block instance */
-       if (eng_id <= ENGINE_ID_DIGF) {
+       if (eng_id < ENGINE_ID_DIGF) {
                vpg_inst = eng_id;
                afmt_inst = eng_id;
        } else
@@ -1447,7 +1300,8 @@ static struct hpo_dp_stream_encoder *dcn31_hpo_dp_stream_encoder_create(
         * VPG[8] -> HPO_DP[2]
         * VPG[9] -> HPO_DP[3]
         */
-       vpg_inst = hpo_dp_inst + 6;
+       //Uses offset index 5-8, but actually maps to vpg_inst 6-9
+       vpg_inst = hpo_dp_inst + 5;
 
        /* Mapping of APG register blocks to HPO DP block instance:
         * APG[0] -> HPO_DP[0]
@@ -1793,109 +1647,16 @@ static struct clock_source *dcn31_clock_source_create(
        return NULL;
 }
 
-static bool is_dual_plane(enum surface_pixel_format format)
-{
-       return format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN || format == SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA;
-}
-
 static int dcn314_populate_dml_pipes_from_context(
        struct dc *dc, struct dc_state *context,
        display_e2e_pipe_params_st *pipes,
        bool fast_validate)
 {
-       int i, pipe_cnt;
-       struct resource_context *res_ctx = &context->res_ctx;
-       struct pipe_ctx *pipe;
-       bool upscaled = false;
-
-       dcn20_populate_dml_pipes_from_context(dc, context, pipes, fast_validate);
-
-       for (i = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) {
-               struct dc_crtc_timing *timing;
-
-               if (!res_ctx->pipe_ctx[i].stream)
-                       continue;
-               pipe = &res_ctx->pipe_ctx[i];
-               timing = &pipe->stream->timing;
-
-               if (dc_extended_blank_supported(dc) && pipe->stream->adjust.v_total_max == pipe->stream->adjust.v_total_min
-                       && pipe->stream->adjust.v_total_min > timing->v_total)
-                       pipes[pipe_cnt].pipe.dest.vtotal = pipe->stream->adjust.v_total_min;
-
-               if (pipe->plane_state &&
-                               (pipe->plane_state->src_rect.height < pipe->plane_state->dst_rect.height ||
-                               pipe->plane_state->src_rect.width < pipe->plane_state->dst_rect.width))
-                       upscaled = true;
-
-               /*
-                * Immediate flip can be set dynamically after enabling the plane.
-                * We need to require support for immediate flip or underflow can be
-                * intermittently experienced depending on peak b/w requirements.
-                */
-               pipes[pipe_cnt].pipe.src.immediate_flip = true;
-
-               pipes[pipe_cnt].pipe.src.unbounded_req_mode = false;
-               pipes[pipe_cnt].pipe.src.hostvm = dc->res_pool->hubbub->riommu_active;
-               pipes[pipe_cnt].pipe.src.gpuvm = true;
-               pipes[pipe_cnt].pipe.src.dcc_fraction_of_zs_req_luma = 0;
-               pipes[pipe_cnt].pipe.src.dcc_fraction_of_zs_req_chroma = 0;
-               pipes[pipe_cnt].pipe.dest.vfront_porch = timing->v_front_porch;
-               pipes[pipe_cnt].pipe.src.dcc_rate = 3;
-               pipes[pipe_cnt].dout.dsc_input_bpc = 0;
-
-               if (pipes[pipe_cnt].dout.dsc_enable) {
-                       switch (timing->display_color_depth) {
-                       case COLOR_DEPTH_888:
-                               pipes[pipe_cnt].dout.dsc_input_bpc = 8;
-                               break;
-                       case COLOR_DEPTH_101010:
-                               pipes[pipe_cnt].dout.dsc_input_bpc = 10;
-                               break;
-                       case COLOR_DEPTH_121212:
-                               pipes[pipe_cnt].dout.dsc_input_bpc = 12;
-                               break;
-                       default:
-                               ASSERT(0);
-                               break;
-                       }
-               }
-
-               pipe_cnt++;
-       }
-       context->bw_ctx.dml.ip.det_buffer_size_kbytes = DCN3_14_DEFAULT_DET_SIZE;
-
-       dc->config.enable_4to1MPC = false;
-       if (pipe_cnt == 1 && pipe->plane_state && !dc->debug.disable_z9_mpc) {
-               if (is_dual_plane(pipe->plane_state->format)
-                               && pipe->plane_state->src_rect.width <= 1920 && pipe->plane_state->src_rect.height <= 1080) {
-                       dc->config.enable_4to1MPC = true;
-               } else if (!is_dual_plane(pipe->plane_state->format) && pipe->plane_state->src_rect.width <= 5120) {
-                       /* Limit to 5k max to avoid forced pipe split when there is not enough detile for swath */
-                       context->bw_ctx.dml.ip.det_buffer_size_kbytes = 192;
-                       pipes[0].pipe.src.unbounded_req_mode = true;
-               }
-       } else if (context->stream_count >= dc->debug.crb_alloc_policy_min_disp_count
-                       && dc->debug.crb_alloc_policy > DET_SIZE_DEFAULT) {
-               context->bw_ctx.dml.ip.det_buffer_size_kbytes = dc->debug.crb_alloc_policy * 64;
-       } else if (context->stream_count >= 3 && upscaled) {
-               context->bw_ctx.dml.ip.det_buffer_size_kbytes = 192;
-       }
-
-       for (i = 0; i < dc->res_pool->pipe_count; i++) {
-               struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
-
-               if (!pipe->stream)
-                       continue;
+       int pipe_cnt;
 
-               if (pipe->stream->signal == SIGNAL_TYPE_EDP && dc->debug.seamless_boot_odm_combine &&
-                               pipe->stream->apply_seamless_boot_optimization) {
-
-                       if (pipe->stream->apply_boot_odm_mode == dm_odm_combine_policy_2to1) {
-                               context->bw_ctx.dml.vba.ODMCombinePolicy = dm_odm_combine_policy_2to1;
-                               break;
-                       }
-               }
-       }
+       DC_FP_START();
+       pipe_cnt = dcn314_populate_dml_pipes_from_context_fpu(dc, context, pipes, fast_validate);
+       DC_FP_END();
 
        return pipe_cnt;
 }
@@ -1906,88 +1667,9 @@ static struct dc_cap_funcs cap_funcs = {
 
 static void dcn314_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params)
 {
-       struct clk_limit_table *clk_table = &bw_params->clk_table;
-       struct _vcs_dpi_voltage_scaling_st *clock_tmp = dcn3_14_soc._clock_tmp;
-       unsigned int i, closest_clk_lvl;
-       int max_dispclk_mhz = 0, max_dppclk_mhz = 0;
-       int j;
-
-       // Default clock levels are used for diags, which may lead to overclocking.
-       if (!IS_DIAG_DC(dc->ctx->dce_environment)) {
-
-               dcn3_14_ip.max_num_otg = dc->res_pool->res_cap->num_timing_generator;
-               dcn3_14_ip.max_num_dpp = dc->res_pool->pipe_count;
-
-               if (bw_params->num_channels > 0)
-                       dcn3_14_soc.num_chans = bw_params->num_channels;
-
-               ASSERT(dcn3_14_soc.num_chans);
-               ASSERT(clk_table->num_entries);
-
-               /* Prepass to find max clocks independent of voltage level. */
-               for (i = 0; i < clk_table->num_entries; ++i) {
-                       if (clk_table->entries[i].dispclk_mhz > max_dispclk_mhz)
-                               max_dispclk_mhz = clk_table->entries[i].dispclk_mhz;
-                       if (clk_table->entries[i].dppclk_mhz > max_dppclk_mhz)
-                               max_dppclk_mhz = clk_table->entries[i].dppclk_mhz;
-               }
-
-               for (i = 0; i < clk_table->num_entries; i++) {
-                       /* loop backwards*/
-                       for (closest_clk_lvl = 0, j = dcn3_14_soc.num_states - 1; j >= 0; j--) {
-                               if ((unsigned int) dcn3_14_soc.clock_limits[j].dcfclk_mhz <= clk_table->entries[i].dcfclk_mhz) {
-                                       closest_clk_lvl = j;
-                                       break;
-                               }
-                       }
-                       if (clk_table->num_entries == 1) {
-                               /*smu gives one DPM level, let's take the highest one*/
-                               closest_clk_lvl = dcn3_14_soc.num_states - 1;
-                       }
-
-                       clock_tmp[i].state = i;
-
-                       /* Clocks dependent on voltage level. */
-                       clock_tmp[i].dcfclk_mhz = clk_table->entries[i].dcfclk_mhz;
-                       if (clk_table->num_entries == 1 &&
-                               clock_tmp[i].dcfclk_mhz < dcn3_14_soc.clock_limits[closest_clk_lvl].dcfclk_mhz) {
-                               /*SMU fix not released yet*/
-                               clock_tmp[i].dcfclk_mhz = dcn3_14_soc.clock_limits[closest_clk_lvl].dcfclk_mhz;
-                       }
-                       clock_tmp[i].fabricclk_mhz = clk_table->entries[i].fclk_mhz;
-                       clock_tmp[i].socclk_mhz = clk_table->entries[i].socclk_mhz;
-
-                       if (clk_table->entries[i].memclk_mhz && clk_table->entries[i].wck_ratio)
-                               clock_tmp[i].dram_speed_mts = clk_table->entries[i].memclk_mhz * 2 * clk_table->entries[i].wck_ratio;
-
-                       /* Clocks independent of voltage level. */
-                       clock_tmp[i].dispclk_mhz = max_dispclk_mhz ? max_dispclk_mhz :
-                               dcn3_14_soc.clock_limits[closest_clk_lvl].dispclk_mhz;
-
-                       clock_tmp[i].dppclk_mhz = max_dppclk_mhz ? max_dppclk_mhz :
-                               dcn3_14_soc.clock_limits[closest_clk_lvl].dppclk_mhz;
-
-                       clock_tmp[i].dram_bw_per_chan_gbps = dcn3_14_soc.clock_limits[closest_clk_lvl].dram_bw_per_chan_gbps;
-                       clock_tmp[i].dscclk_mhz = dcn3_14_soc.clock_limits[closest_clk_lvl].dscclk_mhz;
-                       clock_tmp[i].dtbclk_mhz = dcn3_14_soc.clock_limits[closest_clk_lvl].dtbclk_mhz;
-                       clock_tmp[i].phyclk_d18_mhz = dcn3_14_soc.clock_limits[closest_clk_lvl].phyclk_d18_mhz;
-                       clock_tmp[i].phyclk_mhz = dcn3_14_soc.clock_limits[closest_clk_lvl].phyclk_mhz;
-               }
-               for (i = 0; i < clk_table->num_entries; i++)
-                       dcn3_14_soc.clock_limits[i] = clock_tmp[i];
-               if (clk_table->num_entries)
-                       dcn3_14_soc.num_states = clk_table->num_entries;
-       }
-
-       if (max_dispclk_mhz) {
-               dcn3_14_soc.dispclk_dppclk_vco_speed_mhz = max_dispclk_mhz * 2;
-               dc->dml.soc.dispclk_dppclk_vco_speed_mhz = max_dispclk_mhz * 2;
-       }
-
-       if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
-               dml_init_instance(&dc->dml, &dcn3_14_soc, &dcn3_14_ip, DML_PROJECT_DCN31);
-       else
-               dml_init_instance(&dc->dml, &dcn3_14_soc, &dcn3_14_ip, DML_PROJECT_DCN31_FPGA);
+       DC_FP_START();
+       dcn314_update_bw_bounding_box_fpu(dc, bw_params);
+       DC_FP_END();
 }
 
 static struct resource_funcs dcn314_res_pool_funcs = {
@@ -2069,6 +1751,7 @@ static bool dcn314_resource_construct(
        dc->caps.post_blend_color_processing = true;
        dc->caps.force_dp_tps4_for_cp2520 = true;
        dc->caps.dp_hpo = true;
+       dc->caps.dp_hdmi21_pcon_support = true;
        dc->caps.edp_dsc_support = true;
        dc->caps.extended_aux_timeout_support = true;
        dc->caps.dmcub_support = true;
index c411088..0dd3153 100644 (file)
@@ -29,6 +29,9 @@
 
 #include "core_types.h"
 
+extern struct _vcs_dpi_ip_params_st dcn3_14_ip;
+extern struct _vcs_dpi_soc_bounding_box_st dcn3_14_soc;
+
 #define TO_DCN314_RES_POOL(pool)\
        container_of(pool, struct dcn314_resource_pool, base)
 
index 39929fa..22849ea 100644 (file)
@@ -32,7 +32,6 @@
        container_of(pool, struct dcn315_resource_pool, base)
 
 extern struct _vcs_dpi_ip_params_st dcn3_15_ip;
-extern struct _vcs_dpi_ip_params_st dcn3_15_soc;
 
 struct dcn315_resource_pool {
        struct resource_pool base;
index 0dc5a6c..aba6d63 100644 (file)
@@ -32,7 +32,6 @@
        container_of(pool, struct dcn316_resource_pool, base)
 
 extern struct _vcs_dpi_ip_params_st dcn3_16_ip;
-extern struct _vcs_dpi_ip_params_st dcn3_16_soc;
 
 struct dcn316_resource_pool {
        struct resource_pool base;
index a31c64b..0d5e8a4 100644 (file)
@@ -225,19 +225,19 @@ void dccg32_set_dpstreamclk(
        case 0:
                REG_UPDATE_2(DPSTREAMCLK_CNTL,
                             DPSTREAMCLK0_EN,
-                            (src == REFCLK) ? 0 : 1, DPSTREAMCLK0_SRC_SEL, 0);
+                            (src == REFCLK) ? 0 : 1, DPSTREAMCLK0_SRC_SEL, otg_inst);
                break;
        case 1:
                REG_UPDATE_2(DPSTREAMCLK_CNTL, DPSTREAMCLK1_EN,
-                            (src == REFCLK) ? 0 : 1, DPSTREAMCLK1_SRC_SEL, 1);
+                            (src == REFCLK) ? 0 : 1, DPSTREAMCLK1_SRC_SEL, otg_inst);
                break;
        case 2:
                REG_UPDATE_2(DPSTREAMCLK_CNTL, DPSTREAMCLK2_EN,
-                            (src == REFCLK) ? 0 : 1, DPSTREAMCLK2_SRC_SEL, 2);
+                            (src == REFCLK) ? 0 : 1, DPSTREAMCLK2_SRC_SEL, otg_inst);
                break;
        case 3:
                REG_UPDATE_2(DPSTREAMCLK_CNTL, DPSTREAMCLK3_EN,
-                            (src == REFCLK) ? 0 : 1, DPSTREAMCLK3_SRC_SEL, 3);
+                            (src == REFCLK) ? 0 : 1, DPSTREAMCLK3_SRC_SEL, otg_inst);
                break;
        default:
                BREAK_TO_DEBUGGER();
index 26648ce..38a4898 100644 (file)
@@ -310,6 +310,11 @@ static void enc32_stream_encoder_dp_unblank(
        // TODO: Confirm if we need to wait for DIG_SYMCLK_FE_ON
        REG_WAIT(DIG_FE_CNTL, DIG_SYMCLK_FE_ON, 1, 10, 5000);
 
+       /* read start level = 0 will bring underflow / overflow and DIG_FIFO_ERROR = 1
+        * so set it to 1/2 full = 7 before reset as suggested by hardware team.
+        */
+       REG_UPDATE(DIG_FIFO_CTRL0, DIG_FIFO_READ_START_LEVEL, 0x7);
+
        REG_UPDATE(DIG_FIFO_CTRL0, DIG_FIFO_RESET, 1);
 
        REG_WAIT(DIG_FIFO_CTRL0, DIG_FIFO_RESET_DONE, 1, 10, 5000);
index 6ec1c52..2038cbd 100644 (file)
@@ -103,6 +103,11 @@ void hubp32_cursor_set_attributes(
        enum cursor_lines_per_chunk lpc = hubp2_get_lines_per_chunk(
                        attr->width, attr->color_format);
 
+       //Round cursor width up to next multiple of 64
+       uint32_t cursor_width = ((attr->width + 63) / 64) * 64;
+       uint32_t cursor_height = attr->height;
+       uint32_t cursor_size = cursor_width * cursor_height;
+
        hubp->curs_attr = *attr;
 
        REG_UPDATE(CURSOR_SURFACE_ADDRESS_HIGH,
@@ -126,7 +131,24 @@ void hubp32_cursor_set_attributes(
                         /* used to shift the cursor chunk request deadline */
                        CURSOR0_CHUNK_HDL_ADJUST, 3);
 
-       if (attr->width * attr->height * 4 > 16384)
+       switch (attr->color_format) {
+       case CURSOR_MODE_MONO:
+               cursor_size /= 2;
+               break;
+       case CURSOR_MODE_COLOR_1BIT_AND:
+       case CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA:
+       case CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA:
+               cursor_size *= 4;
+               break;
+
+       case CURSOR_MODE_COLOR_64BIT_FP_PRE_MULTIPLIED:
+       case CURSOR_MODE_COLOR_64BIT_FP_UN_PRE_MULTIPLIED:
+       default:
+               cursor_size *= 8;
+               break;
+       }
+
+       if (cursor_size > 16384)
                REG_UPDATE(DCHUBP_MALL_CONFIG, USE_MALL_FOR_CURSOR, true);
        else
                REG_UPDATE(DCHUBP_MALL_CONFIG, USE_MALL_FOR_CURSOR, false);
index d38341f..344fe75 100644 (file)
@@ -250,6 +250,7 @@ static uint32_t dcn32_calculate_cab_allocation(struct dc *dc, struct dc_state *c
        uint32_t total_lines = 0;
        uint32_t lines_per_way = 0;
        uint32_t num_ways = 0;
+       uint32_t prev_addr_low = 0;
 
        for (i = 0; i < ctx->stream_count; i++) {
                stream = ctx->streams[i];
@@ -267,10 +268,20 @@ static uint32_t dcn32_calculate_cab_allocation(struct dc *dc, struct dc_state *c
                        plane = ctx->stream_status[i].plane_states[j];
 
                        // Calculate total surface size
-                       surface_size = plane->plane_size.surface_pitch *
+                       if (prev_addr_low != plane->address.grph.addr.u.low_part) {
+                               /* if plane address are different from prev FB, then userspace allocated separate FBs*/
+                               surface_size += plane->plane_size.surface_pitch *
                                        plane->plane_size.surface_size.height *
                                        (plane->format >= SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616 ? 8 : 4);
 
+                               prev_addr_low = plane->address.grph.addr.u.low_part;
+                       } else {
+                               /* We have the same fb for all the planes.
+                                * Xorg always creates one giant fb that holds all surfaces,
+                                * so allocating it once is sufficient.
+                                * */
+                               continue;
+                       }
                        // Convert surface size + starting address to number of cache lines required
                        // (alignment accounted for)
                        cache_lines_used += dcn32_cache_lines_for_surface(dc, surface_size,
@@ -284,24 +295,38 @@ static uint32_t dcn32_calculate_cab_allocation(struct dc *dc, struct dc_state *c
                }
 
                // Include cursor size for CAB allocation
-               if (stream->cursor_position.enable && plane->address.grph.cursor_cache_addr.quad_part) {
-                       cursor_size = dc->caps.max_cursor_size * dc->caps.max_cursor_size;
-                       switch (stream->cursor_attributes.color_format) {
-                       case CURSOR_MODE_MONO:
-                               cursor_size /= 2;
-                               break;
-                       case CURSOR_MODE_COLOR_1BIT_AND:
-                       case CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA:
-                       case CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA:
-                               cursor_size *= 4;
-                               break;
+               for (j = 0; j < dc->res_pool->pipe_count; j++) {
+                       struct pipe_ctx *pipe = &ctx->res_ctx.pipe_ctx[j];
+                       struct hubp *hubp = pipe->plane_res.hubp;
 
-                       case CURSOR_MODE_COLOR_64BIT_FP_PRE_MULTIPLIED:
-                       case CURSOR_MODE_COLOR_64BIT_FP_UN_PRE_MULTIPLIED:
-                               cursor_size *= 8;
-                               break;
-                       }
-                       cache_lines_used += dcn32_cache_lines_for_surface(dc, surface_size,
+                       if (pipe->stream && pipe->plane_state && hubp)
+                               /* Find the cursor plane and use the exact size instead of
+                                * using the max for calculation
+                                */
+                               if (hubp->curs_attr.width > 0) {
+                                       cursor_size = hubp->curs_attr.width * hubp->curs_attr.height;
+                                       break;
+                               }
+               }
+
+               switch (stream->cursor_attributes.color_format) {
+               case CURSOR_MODE_MONO:
+                       cursor_size /= 2;
+                       break;
+               case CURSOR_MODE_COLOR_1BIT_AND:
+               case CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA:
+               case CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA:
+                       cursor_size *= 4;
+                       break;
+
+               case CURSOR_MODE_COLOR_64BIT_FP_PRE_MULTIPLIED:
+               case CURSOR_MODE_COLOR_64BIT_FP_UN_PRE_MULTIPLIED:
+                       cursor_size *= 8;
+                       break;
+               }
+
+               if (stream->cursor_position.enable && plane->address.grph.cursor_cache_addr.quad_part) {
+                       cache_lines_used += dcn32_cache_lines_for_surface(dc, cursor_size,
                                        plane->address.grph.cursor_cache_addr.quad_part);
                }
        }
@@ -314,13 +339,36 @@ static uint32_t dcn32_calculate_cab_allocation(struct dc *dc, struct dc_state *c
        if (cache_lines_used % lines_per_way > 0)
                num_ways++;
 
+       for (i = 0; i < ctx->stream_count; i++) {
+               stream = ctx->streams[i];
+               for (j = 0; j < ctx->stream_status[i].plane_count; j++) {
+                       plane = ctx->stream_status[i].plane_states[j];
+
+                       if (stream->cursor_position.enable && plane &&
+                               !plane->address.grph.cursor_cache_addr.quad_part &&
+                               cursor_size > 16384) {
+                               /* Cursor caching is not supported since it won't be on the same line.
+                                * So we need an extra line to accommodate it. With large cursors and a single 4k monitor
+                                * this case triggers corruption. If we're at the edge, then dont trigger display refresh
+                                * from MALL. We only need to cache cursor if its greater that 64x64 at 4 bpp.
+                                */
+                               num_ways++;
+                               /* We only expect one cursor plane */
+                               break;
+                       }
+               }
+       }
+
        return num_ways;
 }
 
 bool dcn32_apply_idle_power_optimizations(struct dc *dc, bool enable)
 {
        union dmub_rb_cmd cmd;
-       uint8_t ways;
+       uint8_t ways, i;
+       int j;
+       bool stereo_in_use = false;
+       struct dc_plane_state *plane = NULL;
 
        if (!dc->ctx->dmub_srv)
                return false;
@@ -349,7 +397,23 @@ bool dcn32_apply_idle_power_optimizations(struct dc *dc, bool enable)
                         * and configure HUBP's to fetch from MALL
                         */
                        ways = dcn32_calculate_cab_allocation(dc, dc->current_state);
-                       if (ways <= dc->caps.cache_num_ways) {
+
+                       /* MALL not supported with Stereo3D. If any plane is using stereo,
+                        * don't try to enter MALL.
+                        */
+                       for (i = 0; i < dc->current_state->stream_count; i++) {
+                               for (j = 0; j < dc->current_state->stream_status[i].plane_count; j++) {
+                                       plane = dc->current_state->stream_status[i].plane_states[j];
+
+                                       if (plane->address.type == PLN_ADDR_TYPE_GRPH_STEREO) {
+                                               stereo_in_use = true;
+                                               break;
+                                       }
+                               }
+                               if (stereo_in_use)
+                                       break;
+                       }
+                       if (ways <= dc->caps.cache_num_ways && !stereo_in_use) {
                                memset(&cmd, 0, sizeof(cmd));
                                cmd.cab.header.type = DMUB_CMD__CAB_FOR_SS;
                                cmd.cab.header.sub_type = DMUB_CMD__CAB_DCN_SS_FIT_IN_CAB;
@@ -677,15 +741,39 @@ void dcn32_update_mall_sel(struct dc *dc, struct dc_state *context)
                struct hubp *hubp = pipe->plane_res.hubp;
 
                if (pipe->stream && pipe->plane_state && hubp && hubp->funcs->hubp_update_mall_sel) {
-                       if (hubp->curs_attr.width * hubp->curs_attr.height * 4 > 16384)
+                       //Round cursor width up to next multiple of 64
+                       int cursor_width = ((hubp->curs_attr.width + 63) / 64) * 64;
+                       int cursor_height = hubp->curs_attr.height;
+                       int cursor_size = cursor_width * cursor_height;
+
+                       switch (hubp->curs_attr.color_format) {
+                       case CURSOR_MODE_MONO:
+                               cursor_size /= 2;
+                               break;
+                       case CURSOR_MODE_COLOR_1BIT_AND:
+                       case CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA:
+                       case CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA:
+                               cursor_size *= 4;
+                               break;
+
+                       case CURSOR_MODE_COLOR_64BIT_FP_PRE_MULTIPLIED:
+                       case CURSOR_MODE_COLOR_64BIT_FP_UN_PRE_MULTIPLIED:
+                       default:
+                               cursor_size *= 8;
+                               break;
+                       }
+
+                       if (cursor_size > 16384)
                                cache_cursor = true;
 
                        if (pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) {
                                        hubp->funcs->hubp_update_mall_sel(hubp, 1, false);
                        } else {
+                               // MALL not supported with Stereo3D
                                hubp->funcs->hubp_update_mall_sel(hubp,
                                        num_ways <= dc->caps.cache_num_ways &&
-                                       pipe->stream->link->psr_settings.psr_version == DC_PSR_VERSION_UNSUPPORTED ? 2 : 0,
+                                       pipe->stream->link->psr_settings.psr_version == DC_PSR_VERSION_UNSUPPORTED &&
+                                       pipe->plane_state->address.type !=  PLN_ADDR_TYPE_GRPH_STEREO ? 2 : 0,
                                                        cache_cursor);
                        }
                }
index eff1f4e..1fad7b4 100644 (file)
@@ -281,7 +281,7 @@ static struct timing_generator_funcs dcn32_tg_funcs = {
                .lock_doublebuffer_enable = optc3_lock_doublebuffer_enable,
                .lock_doublebuffer_disable = optc3_lock_doublebuffer_disable,
                .enable_optc_clock = optc1_enable_optc_clock,
-               .set_drr = optc31_set_drr, // TODO: Update to optc32_set_drr once FW headers are promoted
+               .set_drr = optc32_set_drr,
                .get_last_used_drr_vtotal = optc2_get_last_used_drr_vtotal,
                .set_vtotal_min_max = optc3_set_vtotal_min_max,
                .set_static_screen_control = optc1_set_static_screen_control,
index 9a26d24..c3b783c 100644 (file)
@@ -867,10 +867,11 @@ static const struct dc_debug_options debug_defaults_drv = {
                }
        },
        .use_max_lb = true,
-       .force_disable_subvp = true,
+       .force_disable_subvp = false,
        .exit_idle_opt_for_cursor_updates = true,
        .enable_single_display_2to1_odm_policy = true,
        .enable_dp_dig_pixel_rate_div_policy = 1,
+       .allow_sw_cursor_fallback = false,
 };
 
 static const struct dc_debug_options debug_defaults_diags = {
@@ -2039,7 +2040,8 @@ static bool dcn32_resource_construct(
        dc->caps.max_downscale_ratio = 600;
        dc->caps.i2c_speed_in_khz = 100;
        dc->caps.i2c_speed_in_khz_hdcp = 100; /*1.4 w/a applied by default*/
-       dc->caps.max_cursor_size = 256;
+       /* TODO: Bring max_cursor_size back to 256 after subvp cursor corruption is fixed*/
+       dc->caps.max_cursor_size = 64;
        dc->caps.min_horizontal_blanking_period = 80;
        dc->caps.dmdata_alloc_size = 2048;
        dc->caps.mall_size_per_mem_channel = 0;
@@ -2051,6 +2053,7 @@ static bool dcn32_resource_construct(
        dc->caps.max_cab_allocation_bytes = 67108864; // 64MB = 1024 * 1024 * 64
        dc->caps.subvp_fw_processing_delay_us = 15;
        dc->caps.subvp_prefetch_end_to_mall_start_us = 15;
+       dc->caps.subvp_swath_height_margin_lines = 16;
        dc->caps.subvp_pstate_allow_width_us = 20;
        dc->caps.subvp_vertical_int_margin_us = 30;
 
index 1e7e620..cf15d0e 100644 (file)
@@ -30,6 +30,9 @@
 
 #define DCN3_2_DET_SEG_SIZE 64
 #define DCN3_2_MALL_MBLK_SIZE_BYTES 65536 // 64 * 1024
+#define DCN3_2_MBLK_WIDTH 128
+#define DCN3_2_MBLK_HEIGHT_4BPE 128
+#define DCN3_2_MBLK_HEIGHT_8BPE 64
 
 #define TO_DCN32_RES_POOL(pool)\
        container_of(pool, struct dcn32_resource_pool, base)
index b3f8503..1f195c5 100644 (file)
@@ -46,7 +46,6 @@
 uint32_t dcn32_helper_calculate_num_ways_for_subvp(struct dc *dc, struct dc_state *context)
 {
        uint32_t num_ways = 0;
-       uint32_t mall_region_pixels = 0;
        uint32_t bytes_per_pixel = 0;
        uint32_t cache_lines_used = 0;
        uint32_t lines_per_way = 0;
@@ -54,20 +53,64 @@ uint32_t dcn32_helper_calculate_num_ways_for_subvp(struct dc *dc, struct dc_stat
        uint32_t bytes_in_mall = 0;
        uint32_t num_mblks = 0;
        uint32_t cache_lines_per_plane = 0;
-       uint32_t i = 0;
+       uint32_t i = 0, j = 0;
+       uint32_t mblk_width = 0;
+       uint32_t mblk_height = 0;
+       uint32_t full_vp_width_blk_aligned = 0;
+       uint32_t full_vp_height_blk_aligned = 0;
+       uint32_t mall_alloc_width_blk_aligned = 0;
+       uint32_t mall_alloc_height_blk_aligned = 0;
+       uint32_t full_vp_height = 0;
 
        for (i = 0; i < dc->res_pool->pipe_count; i++) {
                struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
 
                // Find the phantom pipes
-               if (pipe->stream && pipe->plane_state && !pipe->top_pipe &&
+               if (pipe->stream && pipe->plane_state && !pipe->top_pipe && !pipe->prev_odm_pipe &&
                                pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) {
-                       bytes_per_pixel = pipe->plane_state->format >= SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616 ? 8 : 4;
-                       mall_region_pixels = pipe->stream->timing.h_addressable * pipe->stream->timing.v_addressable;
+                       struct pipe_ctx *main_pipe = NULL;
 
-                       // For bytes required in MALL, calculate based on number of MBlks required
-                       num_mblks = (mall_region_pixels * bytes_per_pixel +
-                                       DCN3_2_MALL_MBLK_SIZE_BYTES - 1) / DCN3_2_MALL_MBLK_SIZE_BYTES;
+                       /* Get full viewport height from main pipe (required for MBLK calculation) */
+                       for (j = 0; j < dc->res_pool->pipe_count; j++) {
+                               main_pipe = &context->res_ctx.pipe_ctx[j];
+                               if (main_pipe->stream == pipe->stream->mall_stream_config.paired_stream) {
+                                       full_vp_height = main_pipe->plane_res.scl_data.viewport.height;
+                                       break;
+                               }
+                       }
+
+                       bytes_per_pixel = pipe->plane_state->format >= SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616 ? 8 : 4;
+                       mblk_width = DCN3_2_MBLK_WIDTH;
+                       mblk_height = bytes_per_pixel == 4 ? DCN3_2_MBLK_HEIGHT_4BPE : DCN3_2_MBLK_HEIGHT_8BPE;
+
+                       /* full_vp_width_blk_aligned = FLOOR(vp_x_start + full_vp_width + blk_width - 1, blk_width) -
+                        * FLOOR(vp_x_start, blk_width)
+                        */
+                       full_vp_width_blk_aligned = ((pipe->plane_res.scl_data.viewport.x +
+                                       pipe->plane_res.scl_data.viewport.width + mblk_width - 1) / mblk_width * mblk_width) +
+                                       (pipe->plane_res.scl_data.viewport.x / mblk_width * mblk_width);
+
+                       /* full_vp_height_blk_aligned = FLOOR(vp_y_start + full_vp_height + blk_height - 1, blk_height) -
+                        * FLOOR(vp_y_start, blk_height)
+                        */
+                       full_vp_height_blk_aligned = ((pipe->plane_res.scl_data.viewport.y +
+                                       full_vp_height + mblk_height - 1) / mblk_height * mblk_height) +
+                                       (pipe->plane_res.scl_data.viewport.y / mblk_height * mblk_height);
+
+                       /* mall_alloc_width_blk_aligned_l/c = full_vp_width_blk_aligned_l/c */
+                       mall_alloc_width_blk_aligned = full_vp_width_blk_aligned;
+
+                       /* mall_alloc_height_blk_aligned_l/c = CEILING(sub_vp_height_l/c - 1, blk_height_l/c) + blk_height_l/c */
+                       mall_alloc_height_blk_aligned = (pipe->stream->timing.v_addressable - 1 + mblk_height - 1) /
+                                       mblk_height * mblk_height + mblk_height;
+
+                       /* full_mblk_width_ub_l/c = mall_alloc_width_blk_aligned_l/c;
+                        * full_mblk_height_ub_l/c = mall_alloc_height_blk_aligned_l/c;
+                        * num_mblk_l/c = (full_mblk_width_ub_l/c / mblk_width_l/c) * (full_mblk_height_ub_l/c / mblk_height_l/c);
+                        * (Should be divisible, but round up if not)
+                        */
+                       num_mblks = ((mall_alloc_width_blk_aligned + mblk_width - 1) / mblk_width) *
+                                       ((mall_alloc_height_blk_aligned + mblk_height - 1) / mblk_height);
                        bytes_in_mall = num_mblks * DCN3_2_MALL_MBLK_SIZE_BYTES;
                        // cache lines used is total bytes / cache_line size. Add +2 for worst case alignment
                        // (MALL is 64-byte aligned)
@@ -144,7 +187,7 @@ bool dcn32_all_pipes_have_stream_and_plane(struct dc *dc,
                struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
 
                if (!pipe->stream)
-                       continue;
+                       return false;
 
                if (!pipe->plane_state)
                        return false;
index 8157e40..7309eed 100644 (file)
@@ -868,10 +868,11 @@ static const struct dc_debug_options debug_defaults_drv = {
                }
        },
        .use_max_lb = true,
-       .force_disable_subvp = true,
+       .force_disable_subvp = false,
        .exit_idle_opt_for_cursor_updates = true,
        .enable_single_display_2to1_odm_policy = true,
        .enable_dp_dig_pixel_rate_div_policy = 1,
+       .allow_sw_cursor_fallback = false,
 };
 
 static const struct dc_debug_options debug_defaults_diags = {
@@ -1651,7 +1652,8 @@ static bool dcn321_resource_construct(
        dc->caps.max_downscale_ratio = 600;
        dc->caps.i2c_speed_in_khz = 100;
        dc->caps.i2c_speed_in_khz_hdcp = 100; /*1.4 w/a applied by default*/
-       dc->caps.max_cursor_size = 256;
+       /* TODO: Bring max cursor size back to 256 after subvp cursor corruption is fixed*/
+       dc->caps.max_cursor_size = 64;
        dc->caps.min_horizontal_blanking_period = 80;
        dc->caps.dmdata_alloc_size = 2048;
        dc->caps.mall_size_per_mem_channel = 0;
@@ -1662,8 +1664,9 @@ static bool dcn321_resource_construct(
        dc->caps.max_cab_allocation_bytes = 33554432; // 32MB = 1024 * 1024 * 32
        dc->caps.subvp_fw_processing_delay_us = 15;
        dc->caps.subvp_prefetch_end_to_mall_start_us = 15;
+       dc->caps.subvp_swath_height_margin_lines = 16;
        dc->caps.subvp_pstate_allow_width_us = 20;
-
+       dc->caps.subvp_vertical_int_margin_us = 30;
        dc->caps.max_slave_planes = 1;
        dc->caps.max_slave_yuv_planes = 1;
        dc->caps.max_slave_rgb_planes = 1;
index 359f6e9..cb81ed2 100644 (file)
@@ -61,7 +61,6 @@ CFLAGS_$(AMDDALPATH)/dc/dml/display_mode_vba.o := $(dml_ccflags)
 CFLAGS_$(AMDDALPATH)/dc/dml/dcn10/dcn10_fpu.o := $(dml_ccflags)
 CFLAGS_$(AMDDALPATH)/dc/dml/dcn20/dcn20_fpu.o := $(dml_ccflags)
 CFLAGS_$(AMDDALPATH)/dc/dml/dcn20/display_mode_vba_20.o := $(dml_ccflags)
-CFLAGS_$(AMDDALPATH)/dc/dml/dcn20/display_mode_vba_20.o := $(dml_ccflags)
 CFLAGS_$(AMDDALPATH)/dc/dml/dcn20/display_rq_dlg_calc_20.o := $(dml_ccflags)
 CFLAGS_$(AMDDALPATH)/dc/dml/dcn20/display_mode_vba_20v2.o := $(dml_ccflags)
 CFLAGS_$(AMDDALPATH)/dc/dml/dcn20/display_rq_dlg_calc_20v2.o := $(dml_ccflags)
@@ -71,6 +70,9 @@ CFLAGS_$(AMDDALPATH)/dc/dml/dcn30/display_mode_vba_30.o := $(dml_ccflags) $(fram
 CFLAGS_$(AMDDALPATH)/dc/dml/dcn30/display_rq_dlg_calc_30.o := $(dml_ccflags)
 CFLAGS_$(AMDDALPATH)/dc/dml/dcn31/display_mode_vba_31.o := $(dml_ccflags) $(frame_warn_flag)
 CFLAGS_$(AMDDALPATH)/dc/dml/dcn31/display_rq_dlg_calc_31.o := $(dml_ccflags)
+CFLAGS_$(AMDDALPATH)/dc/dml/dcn314/display_mode_vba_314.o := $(dml_ccflags) $(frame_warn_flag)
+CFLAGS_$(AMDDALPATH)/dc/dml/dcn314/display_rq_dlg_calc_314.o := $(dml_ccflags)
+CFLAGS_$(AMDDALPATH)/dc/dml/dcn314/dcn314_fpu.o := $(dml_ccflags)
 CFLAGS_$(AMDDALPATH)/dc/dml/dcn30/dcn30_fpu.o := $(dml_ccflags)
 CFLAGS_$(AMDDALPATH)/dc/dml/dcn32/dcn32_fpu.o := $(dml_ccflags)
 CFLAGS_$(AMDDALPATH)/dc/dml/dcn32/display_mode_vba_32.o := $(dml_ccflags) $(frame_warn_flag)
@@ -82,7 +84,6 @@ CFLAGS_$(AMDDALPATH)/dc/dml/dcn301/dcn301_fpu.o := $(dml_ccflags)
 CFLAGS_$(AMDDALPATH)/dc/dml/dcn302/dcn302_fpu.o := $(dml_ccflags)
 CFLAGS_$(AMDDALPATH)/dc/dml/dcn303/dcn303_fpu.o := $(dml_ccflags)
 CFLAGS_$(AMDDALPATH)/dc/dml/dsc/rc_calc_fpu.o := $(dml_ccflags)
-CFLAGS_$(AMDDALPATH)/dc/dml/display_mode_lib.o := $(dml_ccflags)
 CFLAGS_$(AMDDALPATH)/dc/dml/calcs/dcn_calcs.o := $(dml_ccflags)
 CFLAGS_$(AMDDALPATH)/dc/dml/calcs/dcn_calc_auto.o := $(dml_ccflags)
 CFLAGS_$(AMDDALPATH)/dc/dml/calcs/dcn_calc_math.o := $(dml_ccflags) -Wno-tautological-compare
@@ -124,6 +125,7 @@ DML += dcn20/display_rq_dlg_calc_20v2.o dcn20/display_mode_vba_20v2.o
 DML += dcn21/display_rq_dlg_calc_21.o dcn21/display_mode_vba_21.o
 DML += dcn30/dcn30_fpu.o dcn30/display_mode_vba_30.o dcn30/display_rq_dlg_calc_30.o
 DML += dcn31/display_mode_vba_31.o dcn31/display_rq_dlg_calc_31.o
+DML += dcn314/display_mode_vba_314.o dcn314/display_rq_dlg_calc_314.o
 DML += dcn32/display_mode_vba_32.o dcn32/display_rq_dlg_calc_32.o dcn32/display_mode_vba_util_32.o
 DML += dcn31/dcn31_fpu.o
 DML += dcn32/dcn32_fpu.o
@@ -131,6 +133,7 @@ DML += dcn321/dcn321_fpu.o
 DML += dcn301/dcn301_fpu.o
 DML += dcn302/dcn302_fpu.o
 DML += dcn303/dcn303_fpu.o
+DML += dcn314/dcn314_fpu.o
 DML += dsc/rc_calc_fpu.o
 DML += calcs/dcn_calcs.o calcs/dcn_calc_math.o calcs/dcn_calc_auto.o
 endif
index ca44df4..d34e0f1 100644 (file)
@@ -30,6 +30,7 @@
 #include "dchubbub.h"
 #include "dcn20/dcn20_resource.h"
 #include "dcn21/dcn21_resource.h"
+#include "clk_mgr/dcn21/rn_clk_mgr.h"
 
 #include "dcn20_fpu.h"
 
index 876b321..1cb858d 100644 (file)
@@ -6610,8 +6610,7 @@ static double CalculateUrgentLatency(
        return ret;
 }
 
-
-static void UseMinimumDCFCLK(
+static noinline_for_stack void UseMinimumDCFCLK(
                struct display_mode_lib *mode_lib,
                int MaxInterDCNTileRepeaters,
                int MaxPrefetchMode,
index 7ef66e5..d211cf6 100644 (file)
@@ -26,6 +26,7 @@
 #include "clk_mgr.h"
 #include "dcn20/dcn20_resource.h"
 #include "dcn301/dcn301_resource.h"
+#include "clk_mgr/dcn301/vg_clk_mgr.h"
 
 #include "dml/dcn20/dcn20_fpu.h"
 #include "dcn301_fpu.h"
index e36cfa5..149a1b1 100644 (file)
@@ -25,6 +25,9 @@
 
 #include "resource.h"
 #include "clk_mgr.h"
+#include "dcn31/dcn31_resource.h"
+#include "dcn315/dcn315_resource.h"
+#include "dcn316/dcn316_resource.h"
 
 #include "dml/dcn20/dcn20_fpu.h"
 #include "dcn31_fpu.h"
@@ -114,7 +117,7 @@ struct _vcs_dpi_ip_params_st dcn3_1_ip = {
        .dcc_supported = true,
 };
 
-struct _vcs_dpi_soc_bounding_box_st dcn3_1_soc = {
+static struct _vcs_dpi_soc_bounding_box_st dcn3_1_soc = {
                /*TODO: correct dispclk/dppclk voltage level determination*/
        .clock_limits = {
                {
@@ -259,7 +262,7 @@ struct _vcs_dpi_ip_params_st dcn3_15_ip = {
        .dcc_supported = true,
 };
 
-struct _vcs_dpi_soc_bounding_box_st dcn3_15_soc = {
+static struct _vcs_dpi_soc_bounding_box_st dcn3_15_soc = {
        .sr_exit_time_us = 9.0,
        .sr_enter_plus_exit_time_us = 11.0,
        .sr_exit_z8_time_us = 50.0,
@@ -355,7 +358,7 @@ struct _vcs_dpi_ip_params_st dcn3_16_ip = {
        .dcc_supported = true,
 };
 
-struct _vcs_dpi_soc_bounding_box_st dcn3_16_soc = {
+static struct _vcs_dpi_soc_bounding_box_st dcn3_16_soc = {
                /*TODO: correct dispclk/dppclk voltage level determination*/
        .clock_limits = {
                {
index 3fab191..8ca66f1 100644 (file)
@@ -26,7 +26,7 @@
 #include "dc.h"
 #include "dc_link.h"
 #include "../display_mode_lib.h"
-#include "dml/dcn30/display_mode_vba_30.h"
+#include "../dcn30/display_mode_vba_30.h"
 #include "display_mode_vba_31.h"
 #include "../dml_inline_defs.h"
 
@@ -251,33 +251,13 @@ static void CalculateRowBandwidth(
 
 static void CalculateFlipSchedule(
                struct display_mode_lib *mode_lib,
+               unsigned int k,
                double HostVMInefficiencyFactor,
                double UrgentExtraLatency,
                double UrgentLatency,
-               unsigned int GPUVMMaxPageTableLevels,
-               bool HostVMEnable,
-               unsigned int HostVMMaxNonCachedPageTableLevels,
-               bool GPUVMEnable,
-               double HostVMMinPageSize,
                double PDEAndMetaPTEBytesPerFrame,
                double MetaRowBytes,
-               double DPTEBytesPerRow,
-               double BandwidthAvailableForImmediateFlip,
-               unsigned int TotImmediateFlipBytes,
-               enum source_format_class SourcePixelFormat,
-               double LineTime,
-               double VRatio,
-               double VRatioChroma,
-               double Tno_bw,
-               bool DCCEnable,
-               unsigned int dpte_row_height,
-               unsigned int meta_row_height,
-               unsigned int dpte_row_height_chroma,
-               unsigned int meta_row_height_chroma,
-               double *DestinationLinesToRequestVMInImmediateFlip,
-               double *DestinationLinesToRequestRowInImmediateFlip,
-               double *final_flip_bw,
-               bool *ImmediateFlipSupportedForPipe);
+               double DPTEBytesPerRow);
 static double CalculateWriteBackDelay(
                enum source_format_class WritebackPixelFormat,
                double WritebackHRatio,
@@ -311,64 +291,28 @@ static void CalculateVupdateAndDynamicMetadataParameters(
 static void CalculateWatermarksAndDRAMSpeedChangeSupport(
                struct display_mode_lib *mode_lib,
                unsigned int PrefetchMode,
-               unsigned int NumberOfActivePlanes,
-               unsigned int MaxLineBufferLines,
-               unsigned int LineBufferSize,
-               unsigned int WritebackInterfaceBufferSize,
                double DCFCLK,
                double ReturnBW,
-               bool SynchronizedVBlank,
-               unsigned int dpte_group_bytes[],
-               unsigned int MetaChunkSize,
                double UrgentLatency,
                double ExtraLatency,
-               double WritebackLatency,
-               double WritebackChunkSize,
                double SOCCLK,
-               double DRAMClockChangeLatency,
-               double SRExitTime,
-               double SREnterPlusExitTime,
-               double SRExitZ8Time,
-               double SREnterPlusExitZ8Time,
                double DCFCLKDeepSleep,
                unsigned int DETBufferSizeY[],
                unsigned int DETBufferSizeC[],
                unsigned int SwathHeightY[],
                unsigned int SwathHeightC[],
-               unsigned int LBBitPerPixel[],
                double SwathWidthY[],
                double SwathWidthC[],
-               double HRatio[],
-               double HRatioChroma[],
-               unsigned int vtaps[],
-               unsigned int VTAPsChroma[],
-               double VRatio[],
-               double VRatioChroma[],
-               unsigned int HTotal[],
-               double PixelClock[],
-               unsigned int BlendingAndTiming[],
                unsigned int DPPPerPlane[],
                double BytePerPixelDETY[],
                double BytePerPixelDETC[],
-               double DSTXAfterScaler[],
-               double DSTYAfterScaler[],
-               bool WritebackEnable[],
-               enum source_format_class WritebackPixelFormat[],
-               double WritebackDestinationWidth[],
-               double WritebackDestinationHeight[],
-               double WritebackSourceHeight[],
                bool UnboundedRequestEnabled,
                int unsigned CompressedBufferSizeInkByte,
                enum clock_change_support *DRAMClockChangeSupport,
-               double *UrgentWatermark,
-               double *WritebackUrgentWatermark,
-               double *DRAMClockChangeWatermark,
-               double *WritebackDRAMClockChangeWatermark,
                double *StutterExitWatermark,
                double *StutterEnterPlusExitWatermark,
                double *Z8StutterExitWatermark,
-               double *Z8StutterEnterPlusExitWatermark,
-               double *MinActiveDRAMClockChangeLatencySupported);
+               double *Z8StutterEnterPlusExitWatermark);
 
 static void CalculateDCFCLKDeepSleep(
                struct display_mode_lib *mode_lib,
@@ -2904,33 +2848,13 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman
                        for (k = 0; k < v->NumberOfActivePlanes; ++k) {
                                CalculateFlipSchedule(
                                                mode_lib,
+                                               k,
                                                HostVMInefficiencyFactor,
                                                v->UrgentExtraLatency,
                                                v->UrgentLatency,
-                                               v->GPUVMMaxPageTableLevels,
-                                               v->HostVMEnable,
-                                               v->HostVMMaxNonCachedPageTableLevels,
-                                               v->GPUVMEnable,
-                                               v->HostVMMinPageSize,
                                                v->PDEAndMetaPTEBytesFrame[k],
                                                v->MetaRowByte[k],
-                                               v->PixelPTEBytesPerRow[k],
-                                               v->BandwidthAvailableForImmediateFlip,
-                                               v->TotImmediateFlipBytes,
-                                               v->SourcePixelFormat[k],
-                                               v->HTotal[k] / v->PixelClock[k],
-                                               v->VRatio[k],
-                                               v->VRatioChroma[k],
-                                               v->Tno_bw[k],
-                                               v->DCCEnable[k],
-                                               v->dpte_row_height[k],
-                                               v->meta_row_height[k],
-                                               v->dpte_row_height_chroma[k],
-                                               v->meta_row_height_chroma[k],
-                                               &v->DestinationLinesToRequestVMInImmediateFlip[k],
-                                               &v->DestinationLinesToRequestRowInImmediateFlip[k],
-                                               &v->final_flip_bw[k],
-                                               &v->ImmediateFlipSupportedForPipe[k]);
+                                               v->PixelPTEBytesPerRow[k]);
                        }
 
                        v->total_dcn_read_bw_with_flip = 0.0;
@@ -3017,64 +2941,28 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman
                CalculateWatermarksAndDRAMSpeedChangeSupport(
                                mode_lib,
                                PrefetchMode,
-                               v->NumberOfActivePlanes,
-                               v->MaxLineBufferLines,
-                               v->LineBufferSize,
-                               v->WritebackInterfaceBufferSize,
                                v->DCFCLK,
                                v->ReturnBW,
-                               v->SynchronizedVBlank,
-                               v->dpte_group_bytes,
-                               v->MetaChunkSize,
                                v->UrgentLatency,
                                v->UrgentExtraLatency,
-                               v->WritebackLatency,
-                               v->WritebackChunkSize,
                                v->SOCCLK,
-                               v->DRAMClockChangeLatency,
-                               v->SRExitTime,
-                               v->SREnterPlusExitTime,
-                               v->SRExitZ8Time,
-                               v->SREnterPlusExitZ8Time,
                                v->DCFCLKDeepSleep,
                                v->DETBufferSizeY,
                                v->DETBufferSizeC,
                                v->SwathHeightY,
                                v->SwathHeightC,
-                               v->LBBitPerPixel,
                                v->SwathWidthY,
                                v->SwathWidthC,
-                               v->HRatio,
-                               v->HRatioChroma,
-                               v->vtaps,
-                               v->VTAPsChroma,
-                               v->VRatio,
-                               v->VRatioChroma,
-                               v->HTotal,
-                               v->PixelClock,
-                               v->BlendingAndTiming,
                                v->DPPPerPlane,
                                v->BytePerPixelDETY,
                                v->BytePerPixelDETC,
-                               v->DSTXAfterScaler,
-                               v->DSTYAfterScaler,
-                               v->WritebackEnable,
-                               v->WritebackPixelFormat,
-                               v->WritebackDestinationWidth,
-                               v->WritebackDestinationHeight,
-                               v->WritebackSourceHeight,
                                v->UnboundedRequestEnabled,
                                v->CompressedBufferSizeInkByte,
                                &DRAMClockChangeSupport,
-                               &v->UrgentWatermark,
-                               &v->WritebackUrgentWatermark,
-                               &v->DRAMClockChangeWatermark,
-                               &v->WritebackDRAMClockChangeWatermark,
                                &v->StutterExitWatermark,
                                &v->StutterEnterPlusExitWatermark,
                                &v->Z8StutterExitWatermark,
-                               &v->Z8StutterEnterPlusExitWatermark,
-                               &v->MinActiveDRAMClockChangeLatencySupported);
+                               &v->Z8StutterEnterPlusExitWatermark);
 
                for (k = 0; k < v->NumberOfActivePlanes; ++k) {
                        if (v->WritebackEnable[k] == true) {
@@ -3598,61 +3486,43 @@ static void CalculateRowBandwidth(
 
 static void CalculateFlipSchedule(
                struct display_mode_lib *mode_lib,
+               unsigned int k,
                double HostVMInefficiencyFactor,
                double UrgentExtraLatency,
                double UrgentLatency,
-               unsigned int GPUVMMaxPageTableLevels,
-               bool HostVMEnable,
-               unsigned int HostVMMaxNonCachedPageTableLevels,
-               bool GPUVMEnable,
-               double HostVMMinPageSize,
                double PDEAndMetaPTEBytesPerFrame,
                double MetaRowBytes,
-               double DPTEBytesPerRow,
-               double BandwidthAvailableForImmediateFlip,
-               unsigned int TotImmediateFlipBytes,
-               enum source_format_class SourcePixelFormat,
-               double LineTime,
-               double VRatio,
-               double VRatioChroma,
-               double Tno_bw,
-               bool DCCEnable,
-               unsigned int dpte_row_height,
-               unsigned int meta_row_height,
-               unsigned int dpte_row_height_chroma,
-               unsigned int meta_row_height_chroma,
-               double *DestinationLinesToRequestVMInImmediateFlip,
-               double *DestinationLinesToRequestRowInImmediateFlip,
-               double *final_flip_bw,
-               bool *ImmediateFlipSupportedForPipe)
+               double DPTEBytesPerRow)
 {
+       struct vba_vars_st *v = &mode_lib->vba;
        double min_row_time = 0.0;
        unsigned int HostVMDynamicLevelsTrips;
        double TimeForFetchingMetaPTEImmediateFlip;
        double TimeForFetchingRowInVBlankImmediateFlip;
        double ImmediateFlipBW;
+       double LineTime = v->HTotal[k] / v->PixelClock[k];
 
-       if (GPUVMEnable == true && HostVMEnable == true) {
-               HostVMDynamicLevelsTrips = HostVMMaxNonCachedPageTableLevels;
+       if (v->GPUVMEnable == true && v->HostVMEnable == true) {
+               HostVMDynamicLevelsTrips = v->HostVMMaxNonCachedPageTableLevels;
        } else {
                HostVMDynamicLevelsTrips = 0;
        }
 
-       if (GPUVMEnable == true || DCCEnable == true) {
-               ImmediateFlipBW = (PDEAndMetaPTEBytesPerFrame + MetaRowBytes + DPTEBytesPerRow) * BandwidthAvailableForImmediateFlip / TotImmediateFlipBytes;
+       if (v->GPUVMEnable == true || v->DCCEnable[k] == true) {
+               ImmediateFlipBW = (PDEAndMetaPTEBytesPerFrame + MetaRowBytes + DPTEBytesPerRow) * v->BandwidthAvailableForImmediateFlip / v->TotImmediateFlipBytes;
        }
 
-       if (GPUVMEnable == true) {
+       if (v->GPUVMEnable == true) {
                TimeForFetchingMetaPTEImmediateFlip = dml_max3(
-                               Tno_bw + PDEAndMetaPTEBytesPerFrame * HostVMInefficiencyFactor / ImmediateFlipBW,
-                               UrgentExtraLatency + UrgentLatency * (GPUVMMaxPageTableLevels * (HostVMDynamicLevelsTrips + 1) - 1),
+                               v->Tno_bw[k] + PDEAndMetaPTEBytesPerFrame * HostVMInefficiencyFactor / ImmediateFlipBW,
+                               UrgentExtraLatency + UrgentLatency * (v->GPUVMMaxPageTableLevels * (HostVMDynamicLevelsTrips + 1) - 1),
                                LineTime / 4.0);
        } else {
                TimeForFetchingMetaPTEImmediateFlip = 0;
        }
 
-       *DestinationLinesToRequestVMInImmediateFlip = dml_ceil(4.0 * (TimeForFetchingMetaPTEImmediateFlip / LineTime), 1) / 4.0;
-       if ((GPUVMEnable == true || DCCEnable == true)) {
+       v->DestinationLinesToRequestVMInImmediateFlip[k] = dml_ceil(4.0 * (TimeForFetchingMetaPTEImmediateFlip / LineTime), 1) / 4.0;
+       if ((v->GPUVMEnable == true || v->DCCEnable[k] == true)) {
                TimeForFetchingRowInVBlankImmediateFlip = dml_max3(
                                (MetaRowBytes + DPTEBytesPerRow * HostVMInefficiencyFactor) / ImmediateFlipBW,
                                UrgentLatency * (HostVMDynamicLevelsTrips + 1),
@@ -3661,54 +3531,54 @@ static void CalculateFlipSchedule(
                TimeForFetchingRowInVBlankImmediateFlip = 0;
        }
 
-       *DestinationLinesToRequestRowInImmediateFlip = dml_ceil(4.0 * (TimeForFetchingRowInVBlankImmediateFlip / LineTime), 1) / 4.0;
+       v->DestinationLinesToRequestRowInImmediateFlip[k] = dml_ceil(4.0 * (TimeForFetchingRowInVBlankImmediateFlip / LineTime), 1) / 4.0;
 
-       if (GPUVMEnable == true) {
-               *final_flip_bw = dml_max(
-                               PDEAndMetaPTEBytesPerFrame * HostVMInefficiencyFactor / (*DestinationLinesToRequestVMInImmediateFlip * LineTime),
-                               (MetaRowBytes + DPTEBytesPerRow * HostVMInefficiencyFactor) / (*DestinationLinesToRequestRowInImmediateFlip * LineTime));
-       } else if ((GPUVMEnable == true || DCCEnable == true)) {
-               *final_flip_bw = (MetaRowBytes + DPTEBytesPerRow * HostVMInefficiencyFactor) / (*DestinationLinesToRequestRowInImmediateFlip * LineTime);
+       if (v->GPUVMEnable == true) {
+               v->final_flip_bw[k] = dml_max(
+                               PDEAndMetaPTEBytesPerFrame * HostVMInefficiencyFactor / (v->DestinationLinesToRequestVMInImmediateFlip[k] * LineTime),
+                               (MetaRowBytes + DPTEBytesPerRow * HostVMInefficiencyFactor) / (v->DestinationLinesToRequestRowInImmediateFlip[k] * LineTime));
+       } else if ((v->GPUVMEnable == true || v->DCCEnable[k] == true)) {
+               v->final_flip_bw[k] = (MetaRowBytes + DPTEBytesPerRow * HostVMInefficiencyFactor) / (v->DestinationLinesToRequestRowInImmediateFlip[k] * LineTime);
        } else {
-               *final_flip_bw = 0;
+               v->final_flip_bw[k] = 0;
        }
 
-       if (SourcePixelFormat == dm_420_8 || SourcePixelFormat == dm_420_10 || SourcePixelFormat == dm_rgbe_alpha) {
-               if (GPUVMEnable == true && DCCEnable != true) {
-                       min_row_time = dml_min(dpte_row_height * LineTime / VRatio, dpte_row_height_chroma * LineTime / VRatioChroma);
-               } else if (GPUVMEnable != true && DCCEnable == true) {
-                       min_row_time = dml_min(meta_row_height * LineTime / VRatio, meta_row_height_chroma * LineTime / VRatioChroma);
+       if (v->SourcePixelFormat[k] == dm_420_8 || v->SourcePixelFormat[k] == dm_420_10 || v->SourcePixelFormat[k] == dm_rgbe_alpha) {
+               if (v->GPUVMEnable == true && v->DCCEnable[k] != true) {
+                       min_row_time = dml_min(v->dpte_row_height[k] * LineTime / v->VRatio[k], v->dpte_row_height_chroma[k] * LineTime / v->VRatioChroma[k]);
+               } else if (v->GPUVMEnable != true && v->DCCEnable[k] == true) {
+                       min_row_time = dml_min(v->meta_row_height[k] * LineTime / v->VRatio[k], v->meta_row_height_chroma[k] * LineTime / v->VRatioChroma[k]);
                } else {
                        min_row_time = dml_min4(
-                                       dpte_row_height * LineTime / VRatio,
-                                       meta_row_height * LineTime / VRatio,
-                                       dpte_row_height_chroma * LineTime / VRatioChroma,
-                                       meta_row_height_chroma * LineTime / VRatioChroma);
+                                       v->dpte_row_height[k] * LineTime / v->VRatio[k],
+                                       v->meta_row_height[k] * LineTime / v->VRatio[k],
+                                       v->dpte_row_height_chroma[k] * LineTime / v->VRatioChroma[k],
+                                       v->meta_row_height_chroma[k] * LineTime / v->VRatioChroma[k]);
                }
        } else {
-               if (GPUVMEnable == true && DCCEnable != true) {
-                       min_row_time = dpte_row_height * LineTime / VRatio;
-               } else if (GPUVMEnable != true && DCCEnable == true) {
-                       min_row_time = meta_row_height * LineTime / VRatio;
+               if (v->GPUVMEnable == true && v->DCCEnable[k] != true) {
+                       min_row_time = v->dpte_row_height[k] * LineTime / v->VRatio[k];
+               } else if (v->GPUVMEnable != true && v->DCCEnable[k] == true) {
+                       min_row_time = v->meta_row_height[k] * LineTime / v->VRatio[k];
                } else {
-                       min_row_time = dml_min(dpte_row_height * LineTime / VRatio, meta_row_height * LineTime / VRatio);
+                       min_row_time = dml_min(v->dpte_row_height[k] * LineTime / v->VRatio[k], v->meta_row_height[k] * LineTime / v->VRatio[k]);
                }
        }
 
-       if (*DestinationLinesToRequestVMInImmediateFlip >= 32 || *DestinationLinesToRequestRowInImmediateFlip >= 16
+       if (v->DestinationLinesToRequestVMInImmediateFlip[k] >= 32 || v->DestinationLinesToRequestRowInImmediateFlip[k] >= 16
                        || TimeForFetchingMetaPTEImmediateFlip + 2 * TimeForFetchingRowInVBlankImmediateFlip > min_row_time) {
-               *ImmediateFlipSupportedForPipe = false;
+               v->ImmediateFlipSupportedForPipe[k] = false;
        } else {
-               *ImmediateFlipSupportedForPipe = true;
+               v->ImmediateFlipSupportedForPipe[k] = true;
        }
 
 #ifdef __DML_VBA_DEBUG__
-       dml_print("DML::%s: DestinationLinesToRequestVMInImmediateFlip = %f\n", __func__, *DestinationLinesToRequestVMInImmediateFlip);
-       dml_print("DML::%s: DestinationLinesToRequestRowInImmediateFlip = %f\n", __func__, *DestinationLinesToRequestRowInImmediateFlip);
+       dml_print("DML::%s: DestinationLinesToRequestVMInImmediateFlip = %f\n", __func__, v->DestinationLinesToRequestVMInImmediateFlip[k]);
+       dml_print("DML::%s: DestinationLinesToRequestRowInImmediateFlip = %f\n", __func__, v->DestinationLinesToRequestRowInImmediateFlip[k]);
        dml_print("DML::%s: TimeForFetchingMetaPTEImmediateFlip = %f\n", __func__, TimeForFetchingMetaPTEImmediateFlip);
        dml_print("DML::%s: TimeForFetchingRowInVBlankImmediateFlip = %f\n", __func__, TimeForFetchingRowInVBlankImmediateFlip);
        dml_print("DML::%s: min_row_time = %f\n", __func__, min_row_time);
-       dml_print("DML::%s: ImmediateFlipSupportedForPipe = %d\n", __func__, *ImmediateFlipSupportedForPipe);
+       dml_print("DML::%s: ImmediateFlipSupportedForPipe = %d\n", __func__, v->ImmediateFlipSupportedForPipe[k]);
 #endif
 
 }
@@ -5300,33 +5170,13 @@ void dml31_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
                                        for (k = 0; k < v->NumberOfActivePlanes; k++) {
                                                CalculateFlipSchedule(
                                                                mode_lib,
+                                                               k,
                                                                HostVMInefficiencyFactor,
                                                                v->ExtraLatency,
                                                                v->UrgLatency[i],
-                                                               v->GPUVMMaxPageTableLevels,
-                                                               v->HostVMEnable,
-                                                               v->HostVMMaxNonCachedPageTableLevels,
-                                                               v->GPUVMEnable,
-                                                               v->HostVMMinPageSize,
                                                                v->PDEAndMetaPTEBytesPerFrame[i][j][k],
                                                                v->MetaRowBytes[i][j][k],
-                                                               v->DPTEBytesPerRow[i][j][k],
-                                                               v->BandwidthAvailableForImmediateFlip,
-                                                               v->TotImmediateFlipBytes,
-                                                               v->SourcePixelFormat[k],
-                                                               v->HTotal[k] / v->PixelClock[k],
-                                                               v->VRatio[k],
-                                                               v->VRatioChroma[k],
-                                                               v->Tno_bw[k],
-                                                               v->DCCEnable[k],
-                                                               v->dpte_row_height[k],
-                                                               v->meta_row_height[k],
-                                                               v->dpte_row_height_chroma[k],
-                                                               v->meta_row_height_chroma[k],
-                                                               &v->DestinationLinesToRequestVMInImmediateFlip[k],
-                                                               &v->DestinationLinesToRequestRowInImmediateFlip[k],
-                                                               &v->final_flip_bw[k],
-                                                               &v->ImmediateFlipSupportedForPipe[k]);
+                                                               v->DPTEBytesPerRow[i][j][k]);
                                        }
                                        v->total_dcn_read_bw_with_flip = 0.0;
                                        for (k = 0; k < v->NumberOfActivePlanes; k++) {
@@ -5384,64 +5234,28 @@ void dml31_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
                        CalculateWatermarksAndDRAMSpeedChangeSupport(
                                        mode_lib,
                                        v->PrefetchModePerState[i][j],
-                                       v->NumberOfActivePlanes,
-                                       v->MaxLineBufferLines,
-                                       v->LineBufferSize,
-                                       v->WritebackInterfaceBufferSize,
                                        v->DCFCLKState[i][j],
                                        v->ReturnBWPerState[i][j],
-                                       v->SynchronizedVBlank,
-                                       v->dpte_group_bytes,
-                                       v->MetaChunkSize,
                                        v->UrgLatency[i],
                                        v->ExtraLatency,
-                                       v->WritebackLatency,
-                                       v->WritebackChunkSize,
                                        v->SOCCLKPerState[i],
-                                       v->DRAMClockChangeLatency,
-                                       v->SRExitTime,
-                                       v->SREnterPlusExitTime,
-                                       v->SRExitZ8Time,
-                                       v->SREnterPlusExitZ8Time,
                                        v->ProjectedDCFCLKDeepSleep[i][j],
                                        v->DETBufferSizeYThisState,
                                        v->DETBufferSizeCThisState,
                                        v->SwathHeightYThisState,
                                        v->SwathHeightCThisState,
-                                       v->LBBitPerPixel,
                                        v->SwathWidthYThisState,
                                        v->SwathWidthCThisState,
-                                       v->HRatio,
-                                       v->HRatioChroma,
-                                       v->vtaps,
-                                       v->VTAPsChroma,
-                                       v->VRatio,
-                                       v->VRatioChroma,
-                                       v->HTotal,
-                                       v->PixelClock,
-                                       v->BlendingAndTiming,
                                        v->NoOfDPPThisState,
                                        v->BytePerPixelInDETY,
                                        v->BytePerPixelInDETC,
-                                       v->DSTXAfterScaler,
-                                       v->DSTYAfterScaler,
-                                       v->WritebackEnable,
-                                       v->WritebackPixelFormat,
-                                       v->WritebackDestinationWidth,
-                                       v->WritebackDestinationHeight,
-                                       v->WritebackSourceHeight,
                                        UnboundedRequestEnabledThisState,
                                        CompressedBufferSizeInkByteThisState,
                                        &v->DRAMClockChangeSupport[i][j],
-                                       &v->UrgentWatermark,
-                                       &v->WritebackUrgentWatermark,
-                                       &v->DRAMClockChangeWatermark,
-                                       &v->WritebackDRAMClockChangeWatermark,
-                                       &dummy,
                                        &dummy,
                                        &dummy,
                                        &dummy,
-                                       &v->MinActiveDRAMClockChangeLatencySupported);
+                                       &dummy);
                }
        }
 
@@ -5566,64 +5380,28 @@ void dml31_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
 static void CalculateWatermarksAndDRAMSpeedChangeSupport(
                struct display_mode_lib *mode_lib,
                unsigned int PrefetchMode,
-               unsigned int NumberOfActivePlanes,
-               unsigned int MaxLineBufferLines,
-               unsigned int LineBufferSize,
-               unsigned int WritebackInterfaceBufferSize,
                double DCFCLK,
                double ReturnBW,
-               bool SynchronizedVBlank,
-               unsigned int dpte_group_bytes[],
-               unsigned int MetaChunkSize,
                double UrgentLatency,
                double ExtraLatency,
-               double WritebackLatency,
-               double WritebackChunkSize,
                double SOCCLK,
-               double DRAMClockChangeLatency,
-               double SRExitTime,
-               double SREnterPlusExitTime,
-               double SRExitZ8Time,
-               double SREnterPlusExitZ8Time,
                double DCFCLKDeepSleep,
                unsigned int DETBufferSizeY[],
                unsigned int DETBufferSizeC[],
                unsigned int SwathHeightY[],
                unsigned int SwathHeightC[],
-               unsigned int LBBitPerPixel[],
                double SwathWidthY[],
                double SwathWidthC[],
-               double HRatio[],
-               double HRatioChroma[],
-               unsigned int vtaps[],
-               unsigned int VTAPsChroma[],
-               double VRatio[],
-               double VRatioChroma[],
-               unsigned int HTotal[],
-               double PixelClock[],
-               unsigned int BlendingAndTiming[],
                unsigned int DPPPerPlane[],
                double BytePerPixelDETY[],
                double BytePerPixelDETC[],
-               double DSTXAfterScaler[],
-               double DSTYAfterScaler[],
-               bool WritebackEnable[],
-               enum source_format_class WritebackPixelFormat[],
-               double WritebackDestinationWidth[],
-               double WritebackDestinationHeight[],
-               double WritebackSourceHeight[],
                bool UnboundedRequestEnabled,
                int unsigned CompressedBufferSizeInkByte,
                enum clock_change_support *DRAMClockChangeSupport,
-               double *UrgentWatermark,
-               double *WritebackUrgentWatermark,
-               double *DRAMClockChangeWatermark,
-               double *WritebackDRAMClockChangeWatermark,
                double *StutterExitWatermark,
                double *StutterEnterPlusExitWatermark,
                double *Z8StutterExitWatermark,
-               double *Z8StutterEnterPlusExitWatermark,
-               double *MinActiveDRAMClockChangeLatencySupported)
+               double *Z8StutterEnterPlusExitWatermark)
 {
        struct vba_vars_st *v = &mode_lib->vba;
        double EffectiveLBLatencyHidingY;
@@ -5643,103 +5421,103 @@ static void CalculateWatermarksAndDRAMSpeedChangeSupport(
        double TotalPixelBW = 0.0;
        int k, j;
 
-       *UrgentWatermark = UrgentLatency + ExtraLatency;
+       v->UrgentWatermark = UrgentLatency + ExtraLatency;
 
 #ifdef __DML_VBA_DEBUG__
        dml_print("DML::%s: UrgentLatency = %f\n", __func__, UrgentLatency);
        dml_print("DML::%s: ExtraLatency = %f\n", __func__, ExtraLatency);
-       dml_print("DML::%s: UrgentWatermark = %f\n", __func__, *UrgentWatermark);
+       dml_print("DML::%s: UrgentWatermark = %f\n", __func__, v->UrgentWatermark);
 #endif
 
-       *DRAMClockChangeWatermark = DRAMClockChangeLatency + *UrgentWatermark;
+       v->DRAMClockChangeWatermark = v->DRAMClockChangeLatency + v->UrgentWatermark;
 
 #ifdef __DML_VBA_DEBUG__
-       dml_print("DML::%s: DRAMClockChangeLatency = %f\n", __func__, DRAMClockChangeLatency);
-       dml_print("DML::%s: DRAMClockChangeWatermark = %f\n", __func__, *DRAMClockChangeWatermark);
+       dml_print("DML::%s: v->DRAMClockChangeLatency = %f\n", __func__, v->DRAMClockChangeLatency);
+       dml_print("DML::%s: DRAMClockChangeWatermark = %f\n", __func__, v->DRAMClockChangeWatermark);
 #endif
 
        v->TotalActiveWriteback = 0;
-       for (k = 0; k < NumberOfActivePlanes; ++k) {
-               if (WritebackEnable[k] == true) {
+       for (k = 0; k < v->NumberOfActivePlanes; ++k) {
+               if (v->WritebackEnable[k] == true) {
                        v->TotalActiveWriteback = v->TotalActiveWriteback + 1;
                }
        }
 
        if (v->TotalActiveWriteback <= 1) {
-               *WritebackUrgentWatermark = WritebackLatency;
+               v->WritebackUrgentWatermark = v->WritebackLatency;
        } else {
-               *WritebackUrgentWatermark = WritebackLatency + WritebackChunkSize * 1024.0 / 32.0 / SOCCLK;
+               v->WritebackUrgentWatermark = v->WritebackLatency + v->WritebackChunkSize * 1024.0 / 32.0 / SOCCLK;
        }
 
        if (v->TotalActiveWriteback <= 1) {
-               *WritebackDRAMClockChangeWatermark = DRAMClockChangeLatency + WritebackLatency;
+               v->WritebackDRAMClockChangeWatermark = v->DRAMClockChangeLatency + v->WritebackLatency;
        } else {
-               *WritebackDRAMClockChangeWatermark = DRAMClockChangeLatency + WritebackLatency + WritebackChunkSize * 1024.0 / 32.0 / SOCCLK;
+               v->WritebackDRAMClockChangeWatermark = v->DRAMClockChangeLatency + v->WritebackLatency + v->WritebackChunkSize * 1024.0 / 32.0 / SOCCLK;
        }
 
-       for (k = 0; k < NumberOfActivePlanes; ++k) {
+       for (k = 0; k < v->NumberOfActivePlanes; ++k) {
                TotalPixelBW = TotalPixelBW
-                               + DPPPerPlane[k] * (SwathWidthY[k] * BytePerPixelDETY[k] * VRatio[k] + SwathWidthC[k] * BytePerPixelDETC[k] * VRatioChroma[k])
-                                               / (HTotal[k] / PixelClock[k]);
+                               + DPPPerPlane[k] * (SwathWidthY[k] * BytePerPixelDETY[k] * v->VRatio[k] + SwathWidthC[k] * BytePerPixelDETC[k] * v->VRatioChroma[k])
+                                               / (v->HTotal[k] / v->PixelClock[k]);
        }
 
-       for (k = 0; k < NumberOfActivePlanes; ++k) {
+       for (k = 0; k < v->NumberOfActivePlanes; ++k) {
                double EffectiveDETBufferSizeY = DETBufferSizeY[k];
 
                v->LBLatencyHidingSourceLinesY = dml_min(
-                               (double) MaxLineBufferLines,
-                               dml_floor(LineBufferSize / LBBitPerPixel[k] / (SwathWidthY[k] / dml_max(HRatio[k], 1.0)), 1)) - (vtaps[k] - 1);
+                               (double) v->MaxLineBufferLines,
+                               dml_floor(v->LineBufferSize / v->LBBitPerPixel[k] / (SwathWidthY[k] / dml_max(v->HRatio[k], 1.0)), 1)) - (v->vtaps[k] - 1);
 
                v->LBLatencyHidingSourceLinesC = dml_min(
-                               (double) MaxLineBufferLines,
-                               dml_floor(LineBufferSize / LBBitPerPixel[k] / (SwathWidthC[k] / dml_max(HRatioChroma[k], 1.0)), 1)) - (VTAPsChroma[k] - 1);
+                               (double) v->MaxLineBufferLines,
+                               dml_floor(v->LineBufferSize / v->LBBitPerPixel[k] / (SwathWidthC[k] / dml_max(v->HRatioChroma[k], 1.0)), 1)) - (v->VTAPsChroma[k] - 1);
 
-               EffectiveLBLatencyHidingY = v->LBLatencyHidingSourceLinesY / VRatio[k] * (HTotal[k] / PixelClock[k]);
+               EffectiveLBLatencyHidingY = v->LBLatencyHidingSourceLinesY / v->VRatio[k] * (v->HTotal[k] / v->PixelClock[k]);
 
-               EffectiveLBLatencyHidingC = v->LBLatencyHidingSourceLinesC / VRatioChroma[k] * (HTotal[k] / PixelClock[k]);
+               EffectiveLBLatencyHidingC = v->LBLatencyHidingSourceLinesC / v->VRatioChroma[k] * (v->HTotal[k] / v->PixelClock[k]);
 
                if (UnboundedRequestEnabled) {
                        EffectiveDETBufferSizeY = EffectiveDETBufferSizeY
-                                       + CompressedBufferSizeInkByte * 1024 * SwathWidthY[k] * BytePerPixelDETY[k] * VRatio[k] / (HTotal[k] / PixelClock[k]) / TotalPixelBW;
+                                       + CompressedBufferSizeInkByte * 1024 * SwathWidthY[k] * BytePerPixelDETY[k] * v->VRatio[k] / (v->HTotal[k] / v->PixelClock[k]) / TotalPixelBW;
                }
 
                LinesInDETY[k] = (double) EffectiveDETBufferSizeY / BytePerPixelDETY[k] / SwathWidthY[k];
                LinesInDETYRoundedDownToSwath[k] = dml_floor(LinesInDETY[k], SwathHeightY[k]);
-               FullDETBufferingTimeY = LinesInDETYRoundedDownToSwath[k] * (HTotal[k] / PixelClock[k]) / VRatio[k];
+               FullDETBufferingTimeY = LinesInDETYRoundedDownToSwath[k] * (v->HTotal[k] / v->PixelClock[k]) / v->VRatio[k];
                if (BytePerPixelDETC[k] > 0) {
                        LinesInDETC = v->DETBufferSizeC[k] / BytePerPixelDETC[k] / SwathWidthC[k];
                        LinesInDETCRoundedDownToSwath = dml_floor(LinesInDETC, SwathHeightC[k]);
-                       FullDETBufferingTimeC = LinesInDETCRoundedDownToSwath * (HTotal[k] / PixelClock[k]) / VRatioChroma[k];
+                       FullDETBufferingTimeC = LinesInDETCRoundedDownToSwath * (v->HTotal[k] / v->PixelClock[k]) / v->VRatioChroma[k];
                } else {
                        LinesInDETC = 0;
                        FullDETBufferingTimeC = 999999;
                }
 
                ActiveDRAMClockChangeLatencyMarginY = EffectiveLBLatencyHidingY + FullDETBufferingTimeY
-                               - ((double) DSTXAfterScaler[k] / HTotal[k] + DSTYAfterScaler[k]) * HTotal[k] / PixelClock[k] - *UrgentWatermark - *DRAMClockChangeWatermark;
+                               - ((double) v->DSTXAfterScaler[k] / v->HTotal[k] + v->DSTYAfterScaler[k]) * v->HTotal[k] / v->PixelClock[k] - v->UrgentWatermark - v->DRAMClockChangeWatermark;
 
-               if (NumberOfActivePlanes > 1) {
+               if (v->NumberOfActivePlanes > 1) {
                        ActiveDRAMClockChangeLatencyMarginY = ActiveDRAMClockChangeLatencyMarginY
-                                       - (1 - 1.0 / NumberOfActivePlanes) * SwathHeightY[k] * HTotal[k] / PixelClock[k] / VRatio[k];
+                                       - (1 - 1.0 / v->NumberOfActivePlanes) * SwathHeightY[k] * v->HTotal[k] / v->PixelClock[k] / v->VRatio[k];
                }
 
                if (BytePerPixelDETC[k] > 0) {
                        ActiveDRAMClockChangeLatencyMarginC = EffectiveLBLatencyHidingC + FullDETBufferingTimeC
-                                       - ((double) DSTXAfterScaler[k] / HTotal[k] + DSTYAfterScaler[k]) * HTotal[k] / PixelClock[k] - *UrgentWatermark - *DRAMClockChangeWatermark;
+                                       - ((double) v->DSTXAfterScaler[k] / v->HTotal[k] + v->DSTYAfterScaler[k]) * v->HTotal[k] / v->PixelClock[k] - v->UrgentWatermark - v->DRAMClockChangeWatermark;
 
-                       if (NumberOfActivePlanes > 1) {
+                       if (v->NumberOfActivePlanes > 1) {
                                ActiveDRAMClockChangeLatencyMarginC = ActiveDRAMClockChangeLatencyMarginC
-                                               - (1 - 1.0 / NumberOfActivePlanes) * SwathHeightC[k] * HTotal[k] / PixelClock[k] / VRatioChroma[k];
+                                               - (1 - 1.0 / v->NumberOfActivePlanes) * SwathHeightC[k] * v->HTotal[k] / v->PixelClock[k] / v->VRatioChroma[k];
                        }
                        v->ActiveDRAMClockChangeLatencyMargin[k] = dml_min(ActiveDRAMClockChangeLatencyMarginY, ActiveDRAMClockChangeLatencyMarginC);
                } else {
                        v->ActiveDRAMClockChangeLatencyMargin[k] = ActiveDRAMClockChangeLatencyMarginY;
                }
 
-               if (WritebackEnable[k] == true) {
-                       WritebackDRAMClockChangeLatencyHiding = WritebackInterfaceBufferSize * 1024
-                                       / (WritebackDestinationWidth[k] * WritebackDestinationHeight[k] / (WritebackSourceHeight[k] * HTotal[k] / PixelClock[k]) * 4);
-                       if (WritebackPixelFormat[k] == dm_444_64) {
+               if (v->WritebackEnable[k] == true) {
+                       WritebackDRAMClockChangeLatencyHiding = v->WritebackInterfaceBufferSize * 1024
+                                       / (v->WritebackDestinationWidth[k] * v->WritebackDestinationHeight[k] / (v->WritebackSourceHeight[k] * v->HTotal[k] / v->PixelClock[k]) * 4);
+                       if (v->WritebackPixelFormat[k] == dm_444_64) {
                                WritebackDRAMClockChangeLatencyHiding = WritebackDRAMClockChangeLatencyHiding / 2;
                        }
                        WritebackDRAMClockChangeLatencyMargin = WritebackDRAMClockChangeLatencyHiding - v->WritebackDRAMClockChangeWatermark;
@@ -5749,14 +5527,14 @@ static void CalculateWatermarksAndDRAMSpeedChangeSupport(
 
        v->MinActiveDRAMClockChangeMargin = 999999;
        PlaneWithMinActiveDRAMClockChangeMargin = 0;
-       for (k = 0; k < NumberOfActivePlanes; ++k) {
+       for (k = 0; k < v->NumberOfActivePlanes; ++k) {
                if (v->ActiveDRAMClockChangeLatencyMargin[k] < v->MinActiveDRAMClockChangeMargin) {
                        v->MinActiveDRAMClockChangeMargin = v->ActiveDRAMClockChangeLatencyMargin[k];
-                       if (BlendingAndTiming[k] == k) {
+                       if (v->BlendingAndTiming[k] == k) {
                                PlaneWithMinActiveDRAMClockChangeMargin = k;
                        } else {
-                               for (j = 0; j < NumberOfActivePlanes; ++j) {
-                                       if (BlendingAndTiming[k] == j) {
+                               for (j = 0; j < v->NumberOfActivePlanes; ++j) {
+                                       if (v->BlendingAndTiming[k] == j) {
                                                PlaneWithMinActiveDRAMClockChangeMargin = j;
                                        }
                                }
@@ -5764,11 +5542,11 @@ static void CalculateWatermarksAndDRAMSpeedChangeSupport(
                }
        }
 
-       *MinActiveDRAMClockChangeLatencySupported = v->MinActiveDRAMClockChangeMargin + DRAMClockChangeLatency;
+       v->MinActiveDRAMClockChangeLatencySupported = v->MinActiveDRAMClockChangeMargin + v->DRAMClockChangeLatency ;
 
        SecondMinActiveDRAMClockChangeMarginOneDisplayInVBLank = 999999;
-       for (k = 0; k < NumberOfActivePlanes; ++k) {
-               if (!((k == PlaneWithMinActiveDRAMClockChangeMargin) && (BlendingAndTiming[k] == k)) && !(BlendingAndTiming[k] == PlaneWithMinActiveDRAMClockChangeMargin)
+       for (k = 0; k < v->NumberOfActivePlanes; ++k) {
+               if (!((k == PlaneWithMinActiveDRAMClockChangeMargin) && (v->BlendingAndTiming[k] == k)) && !(v->BlendingAndTiming[k] == PlaneWithMinActiveDRAMClockChangeMargin)
                                && v->ActiveDRAMClockChangeLatencyMargin[k] < SecondMinActiveDRAMClockChangeMarginOneDisplayInVBLank) {
                        SecondMinActiveDRAMClockChangeMarginOneDisplayInVBLank = v->ActiveDRAMClockChangeLatencyMargin[k];
                }
@@ -5776,25 +5554,25 @@ static void CalculateWatermarksAndDRAMSpeedChangeSupport(
 
        v->TotalNumberOfActiveOTG = 0;
 
-       for (k = 0; k < NumberOfActivePlanes; ++k) {
-               if (BlendingAndTiming[k] == k) {
+       for (k = 0; k < v->NumberOfActivePlanes; ++k) {
+               if (v->BlendingAndTiming[k] == k) {
                        v->TotalNumberOfActiveOTG = v->TotalNumberOfActiveOTG + 1;
                }
        }
 
        if (v->MinActiveDRAMClockChangeMargin > 0 && PrefetchMode == 0) {
                *DRAMClockChangeSupport = dm_dram_clock_change_vactive;
-       } else if ((SynchronizedVBlank == true || v->TotalNumberOfActiveOTG == 1
+       } else if ((v->SynchronizedVBlank == true || v->TotalNumberOfActiveOTG == 1
                        || SecondMinActiveDRAMClockChangeMarginOneDisplayInVBLank > 0) && PrefetchMode == 0) {
                *DRAMClockChangeSupport = dm_dram_clock_change_vblank;
        } else {
                *DRAMClockChangeSupport = dm_dram_clock_change_unsupported;
        }
 
-       *StutterExitWatermark = SRExitTime + ExtraLatency + 10 / DCFCLKDeepSleep;
-       *StutterEnterPlusExitWatermark = (SREnterPlusExitTime + ExtraLatency + 10 / DCFCLKDeepSleep);
-       *Z8StutterExitWatermark = SRExitZ8Time + ExtraLatency + 10 / DCFCLKDeepSleep;
-       *Z8StutterEnterPlusExitWatermark = SREnterPlusExitZ8Time + ExtraLatency + 10 / DCFCLKDeepSleep;
+       *StutterExitWatermark = v->SRExitTime + ExtraLatency + 10 / DCFCLKDeepSleep;
+       *StutterEnterPlusExitWatermark = (v->SREnterPlusExitTime + ExtraLatency + 10 / DCFCLKDeepSleep);
+       *Z8StutterExitWatermark = v->SRExitZ8Time + ExtraLatency + 10 / DCFCLKDeepSleep;
+       *Z8StutterEnterPlusExitWatermark = v->SREnterPlusExitZ8Time + ExtraLatency + 10 / DCFCLKDeepSleep;
 
 #ifdef __DML_VBA_DEBUG__
        dml_print("DML::%s: StutterExitWatermark = %f\n", __func__, *StutterExitWatermark);
index 66b82e4..35d10b4 100644 (file)
@@ -27,7 +27,7 @@
 #include "../display_mode_vba.h"
 #include "../dml_inline_defs.h"
 #include "display_rq_dlg_calc_31.h"
-#include "dml/dcn30/display_mode_vba_30.h"
+#include "../dcn30/display_mode_vba_30.h"
 
 static bool is_dual_plane(enum source_format_class source_format)
 {
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c
new file mode 100644 (file)
index 0000000..4bb3b31
--- /dev/null
@@ -0,0 +1,379 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright 2022 Advanced Micro Devices, 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.
+ *
+ * Authors: AMD
+ *
+ */
+
+#include "clk_mgr.h"
+#include "resource.h"
+#include "dcn31/dcn31_hubbub.h"
+#include "dcn314_fpu.h"
+#include "dml/dcn20/dcn20_fpu.h"
+#include "dml/display_mode_vba.h"
+
+struct _vcs_dpi_ip_params_st dcn3_14_ip = {
+       .VBlankNomDefaultUS = 668,
+       .gpuvm_enable = 1,
+       .gpuvm_max_page_table_levels = 1,
+       .hostvm_enable = 1,
+       .hostvm_max_page_table_levels = 2,
+       .rob_buffer_size_kbytes = 64,
+       .det_buffer_size_kbytes = DCN3_14_DEFAULT_DET_SIZE,
+       .config_return_buffer_size_in_kbytes = 1792,
+       .compressed_buffer_segment_size_in_kbytes = 64,
+       .meta_fifo_size_in_kentries = 32,
+       .zero_size_buffer_entries = 512,
+       .compbuf_reserved_space_64b = 256,
+       .compbuf_reserved_space_zs = 64,
+       .dpp_output_buffer_pixels = 2560,
+       .opp_output_buffer_lines = 1,
+       .pixel_chunk_size_kbytes = 8,
+       .meta_chunk_size_kbytes = 2,
+       .min_meta_chunk_size_bytes = 256,
+       .writeback_chunk_size_kbytes = 8,
+       .ptoi_supported = false,
+       .num_dsc = 4,
+       .maximum_dsc_bits_per_component = 10,
+       .dsc422_native_support = false,
+       .is_line_buffer_bpp_fixed = true,
+       .line_buffer_fixed_bpp = 48,
+       .line_buffer_size_bits = 789504,
+       .max_line_buffer_lines = 12,
+       .writeback_interface_buffer_size_kbytes = 90,
+       .max_num_dpp = 4,
+       .max_num_otg = 4,
+       .max_num_hdmi_frl_outputs = 1,
+       .max_num_wb = 1,
+       .max_dchub_pscl_bw_pix_per_clk = 4,
+       .max_pscl_lb_bw_pix_per_clk = 2,
+       .max_lb_vscl_bw_pix_per_clk = 4,
+       .max_vscl_hscl_bw_pix_per_clk = 4,
+       .max_hscl_ratio = 6,
+       .max_vscl_ratio = 6,
+       .max_hscl_taps = 8,
+       .max_vscl_taps = 8,
+       .dpte_buffer_size_in_pte_reqs_luma = 64,
+       .dpte_buffer_size_in_pte_reqs_chroma = 34,
+       .dispclk_ramp_margin_percent = 1,
+       .max_inter_dcn_tile_repeaters = 8,
+       .cursor_buffer_size = 16,
+       .cursor_chunk_size = 2,
+       .writeback_line_buffer_buffer_size = 0,
+       .writeback_min_hscl_ratio = 1,
+       .writeback_min_vscl_ratio = 1,
+       .writeback_max_hscl_ratio = 1,
+       .writeback_max_vscl_ratio = 1,
+       .writeback_max_hscl_taps = 1,
+       .writeback_max_vscl_taps = 1,
+       .dppclk_delay_subtotal = 46,
+       .dppclk_delay_scl = 50,
+       .dppclk_delay_scl_lb_only = 16,
+       .dppclk_delay_cnvc_formatter = 27,
+       .dppclk_delay_cnvc_cursor = 6,
+       .dispclk_delay_subtotal = 119,
+       .dynamic_metadata_vm_enabled = false,
+       .odm_combine_4to1_supported = false,
+       .dcc_supported = true,
+};
+
+struct _vcs_dpi_soc_bounding_box_st dcn3_14_soc = {
+               /*TODO: correct dispclk/dppclk voltage level determination*/
+       .clock_limits = {
+               {
+                       .state = 0,
+                       .dispclk_mhz = 1200.0,
+                       .dppclk_mhz = 1200.0,
+                       .phyclk_mhz = 600.0,
+                       .phyclk_d18_mhz = 667.0,
+                       .dscclk_mhz = 186.0,
+                       .dtbclk_mhz = 600.0,
+               },
+               {
+                       .state = 1,
+                       .dispclk_mhz = 1200.0,
+                       .dppclk_mhz = 1200.0,
+                       .phyclk_mhz = 810.0,
+                       .phyclk_d18_mhz = 667.0,
+                       .dscclk_mhz = 209.0,
+                       .dtbclk_mhz = 600.0,
+               },
+               {
+                       .state = 2,
+                       .dispclk_mhz = 1200.0,
+                       .dppclk_mhz = 1200.0,
+                       .phyclk_mhz = 810.0,
+                       .phyclk_d18_mhz = 667.0,
+                       .dscclk_mhz = 209.0,
+                       .dtbclk_mhz = 600.0,
+               },
+               {
+                       .state = 3,
+                       .dispclk_mhz = 1200.0,
+                       .dppclk_mhz = 1200.0,
+                       .phyclk_mhz = 810.0,
+                       .phyclk_d18_mhz = 667.0,
+                       .dscclk_mhz = 371.0,
+                       .dtbclk_mhz = 600.0,
+               },
+               {
+                       .state = 4,
+                       .dispclk_mhz = 1200.0,
+                       .dppclk_mhz = 1200.0,
+                       .phyclk_mhz = 810.0,
+                       .phyclk_d18_mhz = 667.0,
+                       .dscclk_mhz = 417.0,
+                       .dtbclk_mhz = 600.0,
+               },
+       },
+       .num_states = 5,
+       .sr_exit_time_us = 9.0,
+       .sr_enter_plus_exit_time_us = 11.0,
+       .sr_exit_z8_time_us = 442.0,
+       .sr_enter_plus_exit_z8_time_us = 560.0,
+       .writeback_latency_us = 12.0,
+       .dram_channel_width_bytes = 4,
+       .round_trip_ping_latency_dcfclk_cycles = 106,
+       .urgent_latency_pixel_data_only_us = 4.0,
+       .urgent_latency_pixel_mixed_with_vm_data_us = 4.0,
+       .urgent_latency_vm_data_only_us = 4.0,
+       .urgent_out_of_order_return_per_channel_pixel_only_bytes = 4096,
+       .urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 4096,
+       .urgent_out_of_order_return_per_channel_vm_only_bytes = 4096,
+       .pct_ideal_sdp_bw_after_urgent = 80.0,
+       .pct_ideal_dram_sdp_bw_after_urgent_pixel_only = 65.0,
+       .pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm = 60.0,
+       .pct_ideal_dram_sdp_bw_after_urgent_vm_only = 30.0,
+       .max_avg_sdp_bw_use_normal_percent = 60.0,
+       .max_avg_dram_bw_use_normal_percent = 60.0,
+       .fabric_datapath_to_dcn_data_return_bytes = 32,
+       .return_bus_width_bytes = 64,
+       .downspread_percent = 0.38,
+       .dcn_downspread_percent = 0.5,
+       .gpuvm_min_page_size_bytes = 4096,
+       .hostvm_min_page_size_bytes = 4096,
+       .do_urgent_latency_adjustment = false,
+       .urgent_latency_adjustment_fabric_clock_component_us = 0,
+       .urgent_latency_adjustment_fabric_clock_reference_mhz = 0,
+};
+
+
+void dcn314_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_params)
+{
+       struct clk_limit_table *clk_table = &bw_params->clk_table;
+       struct _vcs_dpi_voltage_scaling_st *clock_limits =
+               dcn3_14_soc.clock_limits;
+       unsigned int i, closest_clk_lvl;
+       int max_dispclk_mhz = 0, max_dppclk_mhz = 0;
+       int j;
+
+       dc_assert_fp_enabled();
+
+       // Default clock levels are used for diags, which may lead to overclocking.
+       if (!IS_DIAG_DC(dc->ctx->dce_environment) && dc->config.use_default_clock_table == false) {
+
+               dcn3_14_ip.max_num_otg = dc->res_pool->res_cap->num_timing_generator;
+               dcn3_14_ip.max_num_dpp = dc->res_pool->pipe_count;
+
+               if (bw_params->dram_channel_width_bytes > 0)
+                       dcn3_14_soc.dram_channel_width_bytes = bw_params->dram_channel_width_bytes;
+
+               if (bw_params->num_channels > 0)
+                       dcn3_14_soc.num_chans = bw_params->num_channels;
+
+               ASSERT(dcn3_14_soc.num_chans);
+               ASSERT(clk_table->num_entries);
+
+               /* Prepass to find max clocks independent of voltage level. */
+               for (i = 0; i < clk_table->num_entries; ++i) {
+                       if (clk_table->entries[i].dispclk_mhz > max_dispclk_mhz)
+                               max_dispclk_mhz = clk_table->entries[i].dispclk_mhz;
+                       if (clk_table->entries[i].dppclk_mhz > max_dppclk_mhz)
+                               max_dppclk_mhz = clk_table->entries[i].dppclk_mhz;
+               }
+
+               for (i = 0; i < clk_table->num_entries; i++) {
+                       /* loop backwards*/
+                       for (closest_clk_lvl = 0, j = dcn3_14_soc.num_states - 1; j >= 0; j--) {
+                               if ((unsigned int) dcn3_14_soc.clock_limits[j].dcfclk_mhz <= clk_table->entries[i].dcfclk_mhz) {
+                                       closest_clk_lvl = j;
+                                       break;
+                               }
+                       }
+                       if (clk_table->num_entries == 1) {
+                               /*smu gives one DPM level, let's take the highest one*/
+                               closest_clk_lvl = dcn3_14_soc.num_states - 1;
+                       }
+
+                       clock_limits[i].state = i;
+
+                       /* Clocks dependent on voltage level. */
+                       clock_limits[i].dcfclk_mhz = clk_table->entries[i].dcfclk_mhz;
+                       if (clk_table->num_entries == 1 &&
+                               clock_limits[i].dcfclk_mhz < dcn3_14_soc.clock_limits[closest_clk_lvl].dcfclk_mhz) {
+                               /*SMU fix not released yet*/
+                               clock_limits[i].dcfclk_mhz = dcn3_14_soc.clock_limits[closest_clk_lvl].dcfclk_mhz;
+                       }
+                       clock_limits[i].fabricclk_mhz = clk_table->entries[i].fclk_mhz;
+                       clock_limits[i].socclk_mhz = clk_table->entries[i].socclk_mhz;
+
+                       if (clk_table->entries[i].memclk_mhz && clk_table->entries[i].wck_ratio)
+                               clock_limits[i].dram_speed_mts = clk_table->entries[i].memclk_mhz * 2 * clk_table->entries[i].wck_ratio;
+
+                       /* Clocks independent of voltage level. */
+                       clock_limits[i].dispclk_mhz = max_dispclk_mhz ? max_dispclk_mhz :
+                               dcn3_14_soc.clock_limits[closest_clk_lvl].dispclk_mhz;
+
+                       clock_limits[i].dppclk_mhz = max_dppclk_mhz ? max_dppclk_mhz :
+                               dcn3_14_soc.clock_limits[closest_clk_lvl].dppclk_mhz;
+
+                       clock_limits[i].dram_bw_per_chan_gbps = dcn3_14_soc.clock_limits[closest_clk_lvl].dram_bw_per_chan_gbps;
+                       clock_limits[i].dscclk_mhz = dcn3_14_soc.clock_limits[closest_clk_lvl].dscclk_mhz;
+                       clock_limits[i].dtbclk_mhz = dcn3_14_soc.clock_limits[closest_clk_lvl].dtbclk_mhz;
+                       clock_limits[i].phyclk_d18_mhz = dcn3_14_soc.clock_limits[closest_clk_lvl].phyclk_d18_mhz;
+                       clock_limits[i].phyclk_mhz = dcn3_14_soc.clock_limits[closest_clk_lvl].phyclk_mhz;
+               }
+               for (i = 0; i < clk_table->num_entries; i++)
+                       dcn3_14_soc.clock_limits[i] = clock_limits[i];
+               if (clk_table->num_entries) {
+                       dcn3_14_soc.num_states = clk_table->num_entries;
+               }
+       }
+
+       if (max_dispclk_mhz) {
+               dcn3_14_soc.dispclk_dppclk_vco_speed_mhz = max_dispclk_mhz * 2;
+               dc->dml.soc.dispclk_dppclk_vco_speed_mhz = max_dispclk_mhz * 2;
+       }
+
+       if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
+               dml_init_instance(&dc->dml, &dcn3_14_soc, &dcn3_14_ip, DML_PROJECT_DCN314);
+       else
+               dml_init_instance(&dc->dml, &dcn3_14_soc, &dcn3_14_ip, DML_PROJECT_DCN31_FPGA);
+}
+
+static bool is_dual_plane(enum surface_pixel_format format)
+{
+       return format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN || format == SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA;
+}
+
+int dcn314_populate_dml_pipes_from_context_fpu(struct dc *dc, struct dc_state *context,
+                                              display_e2e_pipe_params_st *pipes,
+                                              bool fast_validate)
+{
+       int i, pipe_cnt;
+       struct resource_context *res_ctx = &context->res_ctx;
+       struct pipe_ctx *pipe;
+       bool upscaled = false;
+
+       dc_assert_fp_enabled();
+
+       dcn20_populate_dml_pipes_from_context(dc, context, pipes, fast_validate);
+
+       for (i = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) {
+               struct dc_crtc_timing *timing;
+
+               if (!res_ctx->pipe_ctx[i].stream)
+                       continue;
+               pipe = &res_ctx->pipe_ctx[i];
+               timing = &pipe->stream->timing;
+
+               if (dc_extended_blank_supported(dc) && pipe->stream->adjust.v_total_max == pipe->stream->adjust.v_total_min
+                       && pipe->stream->adjust.v_total_min > timing->v_total)
+                       pipes[pipe_cnt].pipe.dest.vtotal = pipe->stream->adjust.v_total_min;
+
+               if (pipe->plane_state &&
+                               (pipe->plane_state->src_rect.height < pipe->plane_state->dst_rect.height ||
+                               pipe->plane_state->src_rect.width < pipe->plane_state->dst_rect.width))
+                       upscaled = true;
+
+               /*
+                * Immediate flip can be set dynamically after enabling the plane.
+                * We need to require support for immediate flip or underflow can be
+                * intermittently experienced depending on peak b/w requirements.
+                */
+               pipes[pipe_cnt].pipe.src.immediate_flip = true;
+
+               pipes[pipe_cnt].pipe.src.unbounded_req_mode = false;
+               pipes[pipe_cnt].pipe.src.hostvm = dc->res_pool->hubbub->riommu_active;
+               pipes[pipe_cnt].pipe.src.gpuvm = true;
+               pipes[pipe_cnt].pipe.src.dcc_fraction_of_zs_req_luma = 0;
+               pipes[pipe_cnt].pipe.src.dcc_fraction_of_zs_req_chroma = 0;
+               pipes[pipe_cnt].pipe.dest.vfront_porch = timing->v_front_porch;
+               pipes[pipe_cnt].pipe.src.dcc_rate = 3;
+               pipes[pipe_cnt].dout.dsc_input_bpc = 0;
+
+               if (pipes[pipe_cnt].dout.dsc_enable) {
+                       switch (timing->display_color_depth) {
+                       case COLOR_DEPTH_888:
+                               pipes[pipe_cnt].dout.dsc_input_bpc = 8;
+                               break;
+                       case COLOR_DEPTH_101010:
+                               pipes[pipe_cnt].dout.dsc_input_bpc = 10;
+                               break;
+                       case COLOR_DEPTH_121212:
+                               pipes[pipe_cnt].dout.dsc_input_bpc = 12;
+                               break;
+                       default:
+                               ASSERT(0);
+                               break;
+                       }
+               }
+
+               pipe_cnt++;
+       }
+       context->bw_ctx.dml.ip.det_buffer_size_kbytes = DCN3_14_DEFAULT_DET_SIZE;
+
+       dc->config.enable_4to1MPC = false;
+       if (pipe_cnt == 1 && pipe->plane_state && !dc->debug.disable_z9_mpc) {
+               if (is_dual_plane(pipe->plane_state->format)
+                               && pipe->plane_state->src_rect.width <= 1920 && pipe->plane_state->src_rect.height <= 1080) {
+                       dc->config.enable_4to1MPC = true;
+               } else if (!is_dual_plane(pipe->plane_state->format) && pipe->plane_state->src_rect.width <= 5120) {
+                       /* Limit to 5k max to avoid forced pipe split when there is not enough detile for swath */
+                       context->bw_ctx.dml.ip.det_buffer_size_kbytes = 192;
+                       pipes[0].pipe.src.unbounded_req_mode = true;
+               }
+       } else if (context->stream_count >= dc->debug.crb_alloc_policy_min_disp_count
+                       && dc->debug.crb_alloc_policy > DET_SIZE_DEFAULT) {
+               context->bw_ctx.dml.ip.det_buffer_size_kbytes = dc->debug.crb_alloc_policy * 64;
+       } else if (context->stream_count >= 3 && upscaled) {
+               context->bw_ctx.dml.ip.det_buffer_size_kbytes = 192;
+       }
+
+       for (i = 0; i < dc->res_pool->pipe_count; i++) {
+               struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
+
+               if (!pipe->stream)
+                       continue;
+
+               if (pipe->stream->signal == SIGNAL_TYPE_EDP && dc->debug.seamless_boot_odm_combine &&
+                               pipe->stream->apply_seamless_boot_optimization) {
+
+                       if (pipe->stream->apply_boot_odm_mode == dm_odm_combine_policy_2to1) {
+                               context->bw_ctx.dml.vba.ODMCombinePolicy = dm_odm_combine_policy_2to1;
+                               break;
+                       }
+               }
+       }
+
+       return pipe_cnt;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.h b/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.h
new file mode 100644 (file)
index 0000000..d32c5bb
--- /dev/null
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright 2022 Advanced Micro Devices, 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.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DCN314_FPU_H__
+#define __DCN314_FPU_H__
+
+#define DCN3_14_DEFAULT_DET_SIZE 384
+#define DCN3_14_MAX_DET_SIZE 384
+#define DCN3_14_MIN_COMPBUF_SIZE_KB 128
+#define DCN3_14_CRB_SEGMENT_SIZE_KB 64
+
+void dcn314_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_params);
+int dcn314_populate_dml_pipes_from_context_fpu(struct dc *dc, struct dc_state *context,
+                                              display_e2e_pipe_params_st *pipes,
+                                              bool fast_validate);
+
+#endif
index fc4d747..01f3fad 100644 (file)
@@ -61,7 +61,7 @@
 // fudge factor for min dcfclk calclation
 #define __DML_MIN_DCFCLK_FACTOR__   1.15
 
-struct {
+typedef struct {
        double DPPCLK;
        double DISPCLK;
        double PixelClock;
@@ -1599,7 +1599,7 @@ static void CalculateDCCConfiguration(
        int segment_order_vert_contiguous_luma;
        int segment_order_vert_contiguous_chroma;
 
-       enum {
+       typedef enum {
                REQ_256Bytes, REQ_128BytesNonContiguous, REQ_128BytesContiguous, REQ_NA
        } RequestType;
        RequestType RequestLuma;
@@ -4071,9 +4071,7 @@ void dml314_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_
 
        v->SourceFormatPixelAndScanSupport = true;
        for (k = 0; k < v->NumberOfActivePlanes; k++) {
-               if ((v->SurfaceTiling[k] == dm_sw_linear && (!(v->SourceScan[k] != dm_vert) || v->DCCEnable[k] == true))
-                               || ((v->SurfaceTiling[k] == dm_sw_64kb_d || v->SurfaceTiling[k] == dm_sw_64kb_d_t
-                                               || v->SurfaceTiling[k] == dm_sw_64kb_d_x) && !(v->SourcePixelFormat[k] == dm_444_64))) {
+               if (v->SurfaceTiling[k] == dm_sw_linear && (!(v->SourceScan[k] != dm_vert) || v->DCCEnable[k] == true)) {
                        v->SourceFormatPixelAndScanSupport = false;
                }
        }
@@ -7157,12 +7155,13 @@ static double CalculateExtraLatencyBytes(
                        HostVMDynamicLevels = dml_max(0, (int) HostVMMaxNonCachedPageTableLevels - 1);
                else
                        HostVMDynamicLevels = dml_max(0, (int) HostVMMaxNonCachedPageTableLevels - 2);
-       else
+       } else {
                HostVMDynamicLevels = 0;
+       }
 
        ret = ReorderingBytes + (TotalNumberOfActiveDPP * PixelChunkSizeInKByte + TotalNumberOfDCCActiveDPP * MetaChunkSize) * 1024.0;
 
-       if (GPUVMEnable == true)
+       if (GPUVMEnable == true) {
                for (k = 0; k < NumberOfActivePlanes; ++k)
                        ret = ret + NumberOfDPP[k] * dpte_group_bytes[k] * (1 + 8 * HostVMDynamicLevels) * HostVMInefficiencyFactor;
        }
index 6645354..8e4c9d0 100644 (file)
@@ -473,8 +473,11 @@ void dcn32_set_phantom_stream_timing(struct dc *dc,
 
        // DML calculation for MALL region doesn't take into account FW delay
        // and required pstate allow width for multi-display cases
+       /* Add 16 lines margin to the MALL REGION because SUB_VP_START_LINE must be aligned
+        * to 2 swaths (i.e. 16 lines)
+        */
        phantom_vactive = get_subviewport_lines_needed_in_mall(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx) +
-                               pstate_width_fw_delay_lines;
+                               pstate_width_fw_delay_lines + dc->caps.subvp_swath_height_margin_lines;
 
        // For backporch of phantom pipe, use vstartup of the main pipe
        phantom_bp = get_vstartup(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx);
@@ -490,6 +493,7 @@ void dcn32_set_phantom_stream_timing(struct dc *dc,
                                                phantom_stream->timing.v_front_porch +
                                                phantom_stream->timing.v_sync_width +
                                                phantom_bp;
+       phantom_stream->timing.flags.DSC = 0; // Don't need DSC for phantom timing
 }
 
 /**
@@ -983,9 +987,15 @@ static void dcn32_full_validate_bw_helper(struct dc *dc,
         * DML favors voltage over p-state, but we're more interested in
         * supporting p-state over voltage. We can't support p-state in
         * prefetch mode > 0 so try capping the prefetch mode to start.
+        * Override present for testing.
         */
-       context->bw_ctx.dml.soc.allow_for_pstate_or_stutter_in_vblank_final =
+       if (dc->debug.dml_disallow_alternate_prefetch_modes)
+               context->bw_ctx.dml.soc.allow_for_pstate_or_stutter_in_vblank_final =
                        dm_prefetch_support_uclk_fclk_and_stutter;
+       else
+               context->bw_ctx.dml.soc.allow_for_pstate_or_stutter_in_vblank_final =
+                       dm_prefetch_support_uclk_fclk_and_stutter_if_possible;
+
        *vlevel = dml_get_voltage_level(&context->bw_ctx.dml, pipes, *pipe_cnt);
        /* This may adjust vlevel and maxMpcComb */
        if (*vlevel < context->bw_ctx.dml.soc.num_states)
@@ -1004,6 +1014,15 @@ static void dcn32_full_validate_bw_helper(struct dc *dc,
            dc->debug.force_subvp_mclk_switch)) {
 
                dcn32_merge_pipes_for_subvp(dc, context);
+               // to re-initialize viewport after the pipe merge
+               for (int i = 0; i < dc->res_pool->pipe_count; i++) {
+                       struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
+
+                       if (!pipe_ctx->plane_state || !pipe_ctx->stream)
+                               continue;
+
+                       resource_build_scaling_params(pipe_ctx);
+               }
 
                while (!found_supported_config && dcn32_enough_pipes_for_subvp(dc, context) &&
                        dcn32_assign_subvp_pipe(dc, context, &dc_pipe_idx)) {
@@ -1014,7 +1033,9 @@ static void dcn32_full_validate_bw_helper(struct dc *dc,
                         * will not allow for switch in VBLANK. The DRR display must have it's VBLANK stretched
                         * enough to support MCLK switching.
                         */
-                       if (*vlevel == context->bw_ctx.dml.soc.num_states) {
+                       if (*vlevel == context->bw_ctx.dml.soc.num_states &&
+                               context->bw_ctx.dml.soc.allow_for_pstate_or_stutter_in_vblank_final ==
+                                       dm_prefetch_support_uclk_fclk_and_stutter) {
                                context->bw_ctx.dml.soc.allow_for_pstate_or_stutter_in_vblank_final =
                                                                dm_prefetch_support_stutter;
                                /* There are params (such as FabricClock) that need to be recalculated
@@ -1344,7 +1365,8 @@ bool dcn32_internal_validate_bw(struct dc *dc,
        int split[MAX_PIPES] = { 0 };
        bool merge[MAX_PIPES] = { false };
        bool newly_split[MAX_PIPES] = { false };
-       int pipe_cnt, i, pipe_idx, vlevel;
+       int pipe_cnt, i, pipe_idx;
+       int vlevel = context->bw_ctx.dml.soc.num_states;
        struct vba_vars_st *vba = &context->bw_ctx.dml.vba;
 
        dc_assert_fp_enabled();
@@ -1373,17 +1395,22 @@ bool dcn32_internal_validate_bw(struct dc *dc,
                DC_FP_END();
        }
 
-       if (fast_validate || vlevel == context->bw_ctx.dml.soc.num_states ||
-                       vba->DRAMClockChangeSupport[vlevel][vba->maxMpcComb] == dm_dram_clock_change_unsupported) {
+       if (fast_validate ||
+                       (dc->debug.dml_disallow_alternate_prefetch_modes &&
+                       (vlevel == context->bw_ctx.dml.soc.num_states ||
+                               vba->DRAMClockChangeSupport[vlevel][vba->maxMpcComb] == dm_dram_clock_change_unsupported))) {
                /*
-                * If mode is unsupported or there's still no p-state support then
-                * fall back to favoring voltage.
+                * If dml_disallow_alternate_prefetch_modes is false, then we have already
+                * tried alternate prefetch modes during full validation.
+                *
+                * If mode is unsupported or there is no p-state support, then
+                * fall back to favouring voltage.
                 *
-                * If Prefetch mode 0 failed for this config, or passed with Max UCLK, try if
-                * supported with Prefetch mode 1 (dm_prefetch_support_fclk_and_stutter == 2)
+                * If Prefetch mode 0 failed for this config, or passed with Max UCLK, then try
+                * to support with Prefetch mode 1 (dm_prefetch_support_fclk_and_stutter == 2)
                 */
                context->bw_ctx.dml.soc.allow_for_pstate_or_stutter_in_vblank_final =
-                               dm_prefetch_support_fclk_and_stutter;
+                       dm_prefetch_support_fclk_and_stutter;
 
                vlevel = dml_get_voltage_level(&context->bw_ctx.dml, pipes, pipe_cnt);
 
@@ -2098,6 +2125,13 @@ void dcn32_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_pa
                                dc->bb_overrides.dram_clock_change_latency_ns / 1000.0;
                }
 
+               if ((int)(dcn3_2_soc.fclk_change_latency_us * 1000)
+                               != dc->bb_overrides.fclk_clock_change_latency_ns
+                               && dc->bb_overrides.fclk_clock_change_latency_ns) {
+                       dcn3_2_soc.fclk_change_latency_us =
+                               dc->bb_overrides.fclk_clock_change_latency_ns / 1000;
+               }
+
                if ((int)(dcn3_2_soc.dummy_pstate_latency_us * 1000)
                                != dc->bb_overrides.dummy_clock_change_latency_ns
                                && dc->bb_overrides.dummy_clock_change_latency_ns) {
index 890612d..9a60f27 100644 (file)
@@ -221,7 +221,6 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman
                // VBA_DELTA
                // Calculate DET size, swath height
                dml32_CalculateSwathAndDETConfiguration(
-                               &v->dummy_vars.dml32_CalculateSwathAndDETConfiguration,
                                mode_lib->vba.DETSizeOverride,
                                mode_lib->vba.UsesMALLForPStateChange,
                                mode_lib->vba.ConfigReturnBufferSizeInKByte,
@@ -461,7 +460,6 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman
        {
 
                dml32_CalculateVMRowAndSwath(
-                               &v->dummy_vars.dml32_CalculateVMRowAndSwath,
                                mode_lib->vba.NumberOfActiveSurfaces,
                                v->dummy_vars.DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerformanceCalculation.SurfaceParameters,
                                v->SurfaceSizeInMALL,
@@ -758,31 +756,17 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman
                        v->dummy_vars.DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerformanceCalculation.myPipe.BytePerPixelC = v->BytePerPixelC[k];
                        v->dummy_vars.DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerformanceCalculation.myPipe.ProgressiveToInterlaceUnitInOPP = mode_lib->vba.ProgressiveToInterlaceUnitInOPP;
                        v->ErrorResult[k] = dml32_CalculatePrefetchSchedule(
-                                       &v->dummy_vars.dml32_CalculatePrefetchSchedule,
+                                       v,
+                                       k,
                                        v->dummy_vars.DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerformanceCalculation.HostVMInefficiencyFactor,
-                                       &v->dummy_vars.DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerformanceCalculation.myPipe, v->DSCDelay[k],
-                                       mode_lib->vba.DPPCLKDelaySubtotal + mode_lib->vba.DPPCLKDelayCNVCFormater,
-                                       mode_lib->vba.DPPCLKDelaySCL,
-                                       mode_lib->vba.DPPCLKDelaySCLLBOnly,
-                                       mode_lib->vba.DPPCLKDelayCNVCCursor,
-                                       mode_lib->vba.DISPCLKDelaySubtotal,
-                                       (unsigned int) (v->SwathWidthY[k] / mode_lib->vba.HRatio[k]),
-                                       mode_lib->vba.OutputFormat[k],
-                                       mode_lib->vba.MaxInterDCNTileRepeaters,
+                                       &v->dummy_vars.DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerformanceCalculation.myPipe,
+                                       v->DSCDelay[k],
+                                       (unsigned int) (v->SwathWidthY[k] / v->HRatio[k]),
                                        dml_min(v->VStartupLines, v->MaxVStartupLines[k]),
                                        v->MaxVStartupLines[k],
-                                       mode_lib->vba.GPUVMMaxPageTableLevels,
-                                       mode_lib->vba.GPUVMEnable,
-                                       mode_lib->vba.HostVMEnable,
-                                       mode_lib->vba.HostVMMaxNonCachedPageTableLevels,
-                                       mode_lib->vba.HostVMMinPageSize,
-                                       mode_lib->vba.DynamicMetadataEnable[k],
-                                       mode_lib->vba.DynamicMetadataVMEnabled,
-                                       mode_lib->vba.DynamicMetadataLinesBeforeActiveRequired[k],
-                                       mode_lib->vba.DynamicMetadataTransmittedBytes[k],
                                        v->UrgentLatency,
                                        v->UrgentExtraLatency,
-                                       mode_lib->vba.TCalc,
+                                       v->TCalc,
                                        v->PDEAndMetaPTEBytesFrame[k],
                                        v->MetaRowByte[k],
                                        v->PixelPTEBytesPerRow[k],
@@ -796,8 +780,8 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman
                                        v->MaxNumSwathC[k],
                                        v->swath_width_luma_ub[k],
                                        v->swath_width_chroma_ub[k],
-                                       mode_lib->vba.SwathHeightY[k],
-                                       mode_lib->vba.SwathHeightC[k],
+                                       v->SwathHeightY[k],
+                                       v->SwathHeightC[k],
                                        TWait,
                                        /* Output */
                                        &v->DSTXAfterScaler[k],
@@ -1167,59 +1151,28 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman
                v->dummy_vars.DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerformanceCalculation.mmSOCParameters.SMNLatency = mode_lib->vba.SMNLatency;
 
                dml32_CalculateWatermarksMALLUseAndDRAMSpeedChangeSupport(
-                       &v->dummy_vars.dml32_CalculateWatermarksMALLUseAndDRAMSpeedChangeSupport,
-                       mode_lib->vba.USRRetrainingRequiredFinal,
-                       mode_lib->vba.UsesMALLForPStateChange,
-                       mode_lib->vba.PrefetchModePerState[mode_lib->vba.VoltageLevel][mode_lib->vba.maxMpcComb],
-                       mode_lib->vba.NumberOfActiveSurfaces,
-                       mode_lib->vba.MaxLineBufferLines,
-                       mode_lib->vba.LineBufferSizeFinal,
-                       mode_lib->vba.WritebackInterfaceBufferSize,
-                       mode_lib->vba.DCFCLK,
-                       mode_lib->vba.ReturnBW,
-                       mode_lib->vba.SynchronizeTimingsFinal,
-                       mode_lib->vba.SynchronizeDRRDisplaysForUCLKPStateChangeFinal,
-                       mode_lib->vba.DRRDisplay,
-                       v->dpte_group_bytes,
-                       v->meta_row_height,
-                       v->meta_row_height_chroma,
+                       v,
+                       v->PrefetchModePerState[v->VoltageLevel][v->maxMpcComb],
+                       v->DCFCLK,
+                       v->ReturnBW,
                        v->dummy_vars.DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerformanceCalculation.mmSOCParameters,
-                       mode_lib->vba.WritebackChunkSize,
-                       mode_lib->vba.SOCCLK,
+                       v->SOCCLK,
                        v->DCFCLKDeepSleep,
-                       mode_lib->vba.DETBufferSizeY,
-                       mode_lib->vba.DETBufferSizeC,
-                       mode_lib->vba.SwathHeightY,
-                       mode_lib->vba.SwathHeightC,
-                       mode_lib->vba.LBBitPerPixel,
+                       v->DETBufferSizeY,
+                       v->DETBufferSizeC,
+                       v->SwathHeightY,
+                       v->SwathHeightC,
                        v->SwathWidthY,
                        v->SwathWidthC,
-                       mode_lib->vba.HRatio,
-                       mode_lib->vba.HRatioChroma,
-                       mode_lib->vba.vtaps,
-                       mode_lib->vba.VTAPsChroma,
-                       mode_lib->vba.VRatio,
-                       mode_lib->vba.VRatioChroma,
-                       mode_lib->vba.HTotal,
-                       mode_lib->vba.VTotal,
-                       mode_lib->vba.VActive,
-                       mode_lib->vba.PixelClock,
-                       mode_lib->vba.BlendingAndTiming,
-                       mode_lib->vba.DPPPerPlane,
+                       v->DPPPerPlane,
                        v->BytePerPixelDETY,
                        v->BytePerPixelDETC,
                        v->DSTXAfterScaler,
                        v->DSTYAfterScaler,
-                       mode_lib->vba.WritebackEnable,
-                       mode_lib->vba.WritebackPixelFormat,
-                       mode_lib->vba.WritebackDestinationWidth,
-                       mode_lib->vba.WritebackDestinationHeight,
-                       mode_lib->vba.WritebackSourceHeight,
                        v->UnboundedRequestEnabled,
                        v->CompressedBufferSizeInkByte,
 
                        /* Output */
-                       &v->Watermark,
                        &v->dummy_vars.DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerformanceCalculation.dummy_dramchange_support,
                        v->MaxActiveDRAMClockChangeLatencySupported,
                        v->SubViewportLinesNeededInMALL,
@@ -1811,10 +1764,10 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
                                &mode_lib->vba.Read256BlockHeightC[k],
                                &mode_lib->vba.Read256BlockWidthY[k],
                                &mode_lib->vba.Read256BlockWidthC[k],
-                               &mode_lib->vba.MicroTileHeightY[k],
-                               &mode_lib->vba.MicroTileHeightC[k],
-                               &mode_lib->vba.MicroTileWidthY[k],
-                               &mode_lib->vba.MicroTileWidthC[k]);
+                               &mode_lib->vba.MacroTileHeightY[k],
+                               &mode_lib->vba.MacroTileHeightC[k],
+                               &mode_lib->vba.MacroTileWidthY[k],
+                               &mode_lib->vba.MacroTileWidthC[k]);
        }
 
        /*Bandwidth Support Check*/
@@ -1952,7 +1905,6 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
        }
 
        dml32_CalculateSwathAndDETConfiguration(
-                       &v->dummy_vars.dml32_CalculateSwathAndDETConfiguration,
                        mode_lib->vba.DETSizeOverride,
                        mode_lib->vba.UsesMALLForPStateChange,
                        mode_lib->vba.ConfigReturnBufferSizeInKByte,
@@ -2549,7 +2501,6 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
                        }
 
                        dml32_CalculateSwathAndDETConfiguration(
-                                       &v->dummy_vars.dml32_CalculateSwathAndDETConfiguration,
                                        mode_lib->vba.DETSizeOverride,
                                        mode_lib->vba.UsesMALLForPStateChange,
                                        mode_lib->vba.ConfigReturnBufferSizeInKByte,
@@ -2666,10 +2617,10 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
                        mode_lib->vba.Read256BlockWidthC,
                        mode_lib->vba.Read256BlockHeightY,
                        mode_lib->vba.Read256BlockHeightC,
-                       mode_lib->vba.MicroTileWidthY,
-                       mode_lib->vba.MicroTileWidthC,
-                       mode_lib->vba.MicroTileHeightY,
-                       mode_lib->vba.MicroTileHeightC,
+                       mode_lib->vba.MacroTileWidthY,
+                       mode_lib->vba.MacroTileWidthC,
+                       mode_lib->vba.MacroTileHeightY,
+                       mode_lib->vba.MacroTileHeightC,
 
                        /* Output */
                        mode_lib->vba.SurfaceSizeInMALL,
@@ -2716,10 +2667,10 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
                                v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.SurfParameters[k].BlockHeight256BytesY = mode_lib->vba.Read256BlockHeightY[k];
                                v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.SurfParameters[k].BlockWidth256BytesC = mode_lib->vba.Read256BlockWidthC[k];
                                v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.SurfParameters[k].BlockHeight256BytesC = mode_lib->vba.Read256BlockHeightC[k];
-                               v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.SurfParameters[k].BlockWidthY = mode_lib->vba.MicroTileWidthY[k];
-                               v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.SurfParameters[k].BlockHeightY = mode_lib->vba.MicroTileHeightY[k];
-                               v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.SurfParameters[k].BlockWidthC = mode_lib->vba.MicroTileWidthC[k];
-                               v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.SurfParameters[k].BlockHeightC = mode_lib->vba.MicroTileHeightC[k];
+                               v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.SurfParameters[k].BlockWidthY = mode_lib->vba.MacroTileWidthY[k];
+                               v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.SurfParameters[k].BlockHeightY = mode_lib->vba.MacroTileHeightY[k];
+                               v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.SurfParameters[k].BlockWidthC = mode_lib->vba.MacroTileWidthC[k];
+                               v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.SurfParameters[k].BlockHeightC = mode_lib->vba.MacroTileHeightC[k];
                                v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.SurfParameters[k].InterlaceEnable = mode_lib->vba.Interlace[k];
                                v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.SurfParameters[k].HTotal = mode_lib->vba.HTotal[k];
                                v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.SurfParameters[k].DCCEnable = mode_lib->vba.DCCEnable[k];
@@ -2749,7 +2700,6 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
 
                        {
                                dml32_CalculateVMRowAndSwath(
-                                               &v->dummy_vars.dml32_CalculateVMRowAndSwath,
                                                mode_lib->vba.NumberOfActiveSurfaces,
                                                v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.SurfParameters,
                                                mode_lib->vba.SurfaceSizeInMALL,
@@ -3266,64 +3216,47 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
 
                                        mode_lib->vba.NoTimeForPrefetch[i][j][k] =
                                                dml32_CalculatePrefetchSchedule(
-                                                       &v->dummy_vars.dml32_CalculatePrefetchSchedule,
+                                                       v,
+                                                       k,
                                                        v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.HostVMInefficiencyFactor,
                                                        &v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.myPipe,
-                                                       mode_lib->vba.DSCDelayPerState[i][k],
-                                                       mode_lib->vba.DPPCLKDelaySubtotal +
-                                                               mode_lib->vba.DPPCLKDelayCNVCFormater,
-                                                       mode_lib->vba.DPPCLKDelaySCL,
-                                                       mode_lib->vba.DPPCLKDelaySCLLBOnly,
-                                                       mode_lib->vba.DPPCLKDelayCNVCCursor,
-                                                       mode_lib->vba.DISPCLKDelaySubtotal,
-                                                       mode_lib->vba.SwathWidthYThisState[k] /
-                                                               mode_lib->vba.HRatio[k],
-                                                       mode_lib->vba.OutputFormat[k],
-                                                       mode_lib->vba.MaxInterDCNTileRepeaters,
-                                                       dml_min(mode_lib->vba.MaxVStartup,
-                                                                       mode_lib->vba.MaximumVStartup[i][j][k]),
-                                                       mode_lib->vba.MaximumVStartup[i][j][k],
-                                                       mode_lib->vba.GPUVMMaxPageTableLevels,
-                                                       mode_lib->vba.GPUVMEnable, mode_lib->vba.HostVMEnable,
-                                                       mode_lib->vba.HostVMMaxNonCachedPageTableLevels,
-                                                       mode_lib->vba.HostVMMinPageSize,
-                                                       mode_lib->vba.DynamicMetadataEnable[k],
-                                                       mode_lib->vba.DynamicMetadataVMEnabled,
-                                                       mode_lib->vba.DynamicMetadataLinesBeforeActiveRequired[k],
-                                                       mode_lib->vba.DynamicMetadataTransmittedBytes[k],
-                                                       mode_lib->vba.UrgLatency[i],
-                                                       mode_lib->vba.ExtraLatency,
-                                                       mode_lib->vba.TimeCalc,
-                                                       mode_lib->vba.PDEAndMetaPTEBytesPerFrame[i][j][k],
-                                                       mode_lib->vba.MetaRowBytes[i][j][k],
-                                                       mode_lib->vba.DPTEBytesPerRow[i][j][k],
-                                                       mode_lib->vba.PrefetchLinesY[i][j][k],
-                                                       mode_lib->vba.SwathWidthYThisState[k],
-                                                       mode_lib->vba.PrefillY[k],
-                                                       mode_lib->vba.MaxNumSwY[k],
-                                                       mode_lib->vba.PrefetchLinesC[i][j][k],
-                                                       mode_lib->vba.SwathWidthCThisState[k],
-                                                       mode_lib->vba.PrefillC[k],
-                                                       mode_lib->vba.MaxNumSwC[k],
-                                                       mode_lib->vba.swath_width_luma_ub_this_state[k],
-                                                       mode_lib->vba.swath_width_chroma_ub_this_state[k],
-                                                       mode_lib->vba.SwathHeightYThisState[k],
-                                                       mode_lib->vba.SwathHeightCThisState[k], mode_lib->vba.TWait,
+                                                       v->DSCDelayPerState[i][k],
+                                                       v->SwathWidthYThisState[k] / v->HRatio[k],
+                                                       dml_min(v->MaxVStartup, v->MaximumVStartup[i][j][k]),
+                                                       v->MaximumVStartup[i][j][k],
+                                                       v->UrgLatency[i],
+                                                       v->ExtraLatency,
+                                                       v->TimeCalc,
+                                                       v->PDEAndMetaPTEBytesPerFrame[i][j][k],
+                                                       v->MetaRowBytes[i][j][k],
+                                                       v->DPTEBytesPerRow[i][j][k],
+                                                       v->PrefetchLinesY[i][j][k],
+                                                       v->SwathWidthYThisState[k],
+                                                       v->PrefillY[k],
+                                                       v->MaxNumSwY[k],
+                                                       v->PrefetchLinesC[i][j][k],
+                                                       v->SwathWidthCThisState[k],
+                                                       v->PrefillC[k],
+                                                       v->MaxNumSwC[k],
+                                                       v->swath_width_luma_ub_this_state[k],
+                                                       v->swath_width_chroma_ub_this_state[k],
+                                                       v->SwathHeightYThisState[k],
+                                                       v->SwathHeightCThisState[k], v->TWait,
 
                                                        /* Output */
                                                        &v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.DSTXAfterScaler[k],
                                                        &v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.DSTYAfterScaler[k],
-                                                       &mode_lib->vba.LineTimesForPrefetch[k],
-                                                       &mode_lib->vba.PrefetchBW[k],
-                                                       &mode_lib->vba.LinesForMetaPTE[k],
-                                                       &mode_lib->vba.LinesForMetaAndDPTERow[k],
-                                                       &mode_lib->vba.VRatioPreY[i][j][k],
-                                                       &mode_lib->vba.VRatioPreC[i][j][k],
-                                                       &mode_lib->vba.RequiredPrefetchPixelDataBWLuma[0][0][k],
-                                                       &mode_lib->vba.RequiredPrefetchPixelDataBWChroma[0][0][k],
-                                                       &mode_lib->vba.NoTimeForDynamicMetadata[i][j][k],
-                                                       &mode_lib->vba.Tno_bw[k],
-                                                       &mode_lib->vba.prefetch_vmrow_bw[k],
+                                                       &v->LineTimesForPrefetch[k],
+                                                       &v->PrefetchBW[k],
+                                                       &v->LinesForMetaPTE[k],
+                                                       &v->LinesForMetaAndDPTERow[k],
+                                                       &v->VRatioPreY[i][j][k],
+                                                       &v->VRatioPreC[i][j][k],
+                                                       &v->RequiredPrefetchPixelDataBWLuma[0][0][k],
+                                                       &v->RequiredPrefetchPixelDataBWChroma[0][0][k],
+                                                       &v->NoTimeForDynamicMetadata[i][j][k],
+                                                       &v->Tno_bw[k],
+                                                       &v->prefetch_vmrow_bw[k],
                                                        &v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.dummy_single[0],         // double *Tdmdl_vm
                                                        &v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.dummy_single[1],         // double *Tdmdl
                                                        &v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.dummy_single[2],         // double *TSetup
@@ -3566,63 +3499,32 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
 
                        {
                                dml32_CalculateWatermarksMALLUseAndDRAMSpeedChangeSupport(
-                                               &v->dummy_vars.dml32_CalculateWatermarksMALLUseAndDRAMSpeedChangeSupport,
-                                               mode_lib->vba.USRRetrainingRequiredFinal,
-                                               mode_lib->vba.UsesMALLForPStateChange,
-                                               mode_lib->vba.PrefetchModePerState[i][j],
-                                               mode_lib->vba.NumberOfActiveSurfaces,
-                                               mode_lib->vba.MaxLineBufferLines,
-                                               mode_lib->vba.LineBufferSizeFinal,
-                                               mode_lib->vba.WritebackInterfaceBufferSize,
-                                               mode_lib->vba.DCFCLKState[i][j],
-                                               mode_lib->vba.ReturnBWPerState[i][j],
-                                               mode_lib->vba.SynchronizeTimingsFinal,
-                                               mode_lib->vba.SynchronizeDRRDisplaysForUCLKPStateChangeFinal,
-                                               mode_lib->vba.DRRDisplay,
-                                               mode_lib->vba.dpte_group_bytes,
-                                               mode_lib->vba.meta_row_height,
-                                               mode_lib->vba.meta_row_height_chroma,
+                                               v,
+                                               v->PrefetchModePerState[i][j],
+                                               v->DCFCLKState[i][j],
+                                               v->ReturnBWPerState[i][j],
                                                v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.mSOCParameters,
-                                               mode_lib->vba.WritebackChunkSize,
-                                               mode_lib->vba.SOCCLKPerState[i],
-                                               mode_lib->vba.ProjectedDCFCLKDeepSleep[i][j],
-                                               mode_lib->vba.DETBufferSizeYThisState,
-                                               mode_lib->vba.DETBufferSizeCThisState,
-                                               mode_lib->vba.SwathHeightYThisState,
-                                               mode_lib->vba.SwathHeightCThisState,
-                                               mode_lib->vba.LBBitPerPixel,
-                                               mode_lib->vba.SwathWidthYThisState, // 24
-                                               mode_lib->vba.SwathWidthCThisState,
-                                               mode_lib->vba.HRatio,
-                                               mode_lib->vba.HRatioChroma,
-                                               mode_lib->vba.vtaps,
-                                               mode_lib->vba.VTAPsChroma,
-                                               mode_lib->vba.VRatio,
-                                               mode_lib->vba.VRatioChroma,
-                                               mode_lib->vba.HTotal,
-                                               mode_lib->vba.VTotal,
-                                               mode_lib->vba.VActive,
-                                               mode_lib->vba.PixelClock,
-                                               mode_lib->vba.BlendingAndTiming,
-                                               mode_lib->vba.NoOfDPPThisState,
-                                               mode_lib->vba.BytePerPixelInDETY,
-                                               mode_lib->vba.BytePerPixelInDETC,
+                                               v->SOCCLKPerState[i],
+                                               v->ProjectedDCFCLKDeepSleep[i][j],
+                                               v->DETBufferSizeYThisState,
+                                               v->DETBufferSizeCThisState,
+                                               v->SwathHeightYThisState,
+                                               v->SwathHeightCThisState,
+                                               v->SwathWidthYThisState, // 24
+                                               v->SwathWidthCThisState,
+                                               v->NoOfDPPThisState,
+                                               v->BytePerPixelInDETY,
+                                               v->BytePerPixelInDETC,
                                                v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.DSTXAfterScaler,
                                                v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.DSTYAfterScaler,
-                                               mode_lib->vba.WritebackEnable,
-                                               mode_lib->vba.WritebackPixelFormat,
-                                               mode_lib->vba.WritebackDestinationWidth,
-                                               mode_lib->vba.WritebackDestinationHeight,
-                                               mode_lib->vba.WritebackSourceHeight,
-                                               mode_lib->vba.UnboundedRequestEnabledThisState,
-                                               mode_lib->vba.CompressedBufferSizeInkByteThisState,
+                                               v->UnboundedRequestEnabledThisState,
+                                               v->CompressedBufferSizeInkByteThisState,
 
                                                /* Output */
-                                               &mode_lib->vba.Watermark, // Store the values in vba
-                                               &mode_lib->vba.DRAMClockChangeSupport[i][j],
+                                               &v->DRAMClockChangeSupport[i][j],
                                                &v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.dummy_single2[0], // double *MaxActiveDRAMClockChangeLatencySupported
                                                &v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.dummy_integer[0], // Long SubViewportLinesNeededInMALL[]
-                                               &mode_lib->vba.FCLKChangeSupport[i][j],
+                                               &v->FCLKChangeSupport[i][j],
                                                &v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.dummy_single2[1], // double *MinActiveFCLKChangeLatencySupported
                                                &mode_lib->vba.USRRetrainingSupport[i][j],
                                                mode_lib->vba.ActiveDRAMClockChangeLatencyMargin);
index 07f8f3b..59c2547 100644 (file)
@@ -391,7 +391,6 @@ void dml32_CalculateBytePerPixelAndBlockSizes(
 } // CalculateBytePerPixelAndBlockSizes
 
 void dml32_CalculateSwathAndDETConfiguration(
-               struct dml32_CalculateSwathAndDETConfiguration *st_vars,
                unsigned int DETSizeOverride[],
                enum dm_use_mall_for_pstate_change_mode UseMALLForPStateChange[],
                unsigned int ConfigReturnBufferSizeInKByte,
@@ -456,10 +455,18 @@ void dml32_CalculateSwathAndDETConfiguration(
                bool ViewportSizeSupportPerSurface[],
                bool *ViewportSizeSupport)
 {
+       unsigned int MaximumSwathHeightY[DC__NUM_DPP__MAX];
+       unsigned int MaximumSwathHeightC[DC__NUM_DPP__MAX];
+       unsigned int RoundedUpMaxSwathSizeBytesY[DC__NUM_DPP__MAX];
+       unsigned int RoundedUpMaxSwathSizeBytesC[DC__NUM_DPP__MAX];
+       unsigned int RoundedUpSwathSizeBytesY;
+       unsigned int RoundedUpSwathSizeBytesC;
+       double SwathWidthdoubleDPP[DC__NUM_DPP__MAX];
+       double SwathWidthdoubleDPPChroma[DC__NUM_DPP__MAX];
        unsigned int k;
-
-       st_vars->TotalActiveDPP = 0;
-       st_vars->NoChromaSurfaces = true;
+       unsigned int TotalActiveDPP = 0;
+       bool NoChromaSurfaces = true;
+       unsigned int DETBufferSizeInKByteForSwathCalculation;
 
 #ifdef __DML_VBA_DEBUG__
        dml_print("DML::%s: ForceSingleDPP = %d\n", __func__, ForceSingleDPP);
@@ -494,43 +501,43 @@ void dml32_CalculateSwathAndDETConfiguration(
                        DPPPerSurface,
 
                        /* Output */
-                       st_vars->SwathWidthdoubleDPP,
-                       st_vars->SwathWidthdoubleDPPChroma,
+                       SwathWidthdoubleDPP,
+                       SwathWidthdoubleDPPChroma,
                        SwathWidth,
                        SwathWidthChroma,
-                       st_vars->MaximumSwathHeightY,
-                       st_vars->MaximumSwathHeightC,
+                       MaximumSwathHeightY,
+                       MaximumSwathHeightC,
                        swath_width_luma_ub,
                        swath_width_chroma_ub);
 
        for (k = 0; k < NumberOfActiveSurfaces; ++k) {
-               st_vars->RoundedUpMaxSwathSizeBytesY[k] = swath_width_luma_ub[k] * BytePerPixDETY[k] * st_vars->MaximumSwathHeightY[k];
-               st_vars->RoundedUpMaxSwathSizeBytesC[k] = swath_width_chroma_ub[k] * BytePerPixDETC[k] * st_vars->MaximumSwathHeightC[k];
+               RoundedUpMaxSwathSizeBytesY[k] = swath_width_luma_ub[k] * BytePerPixDETY[k] * MaximumSwathHeightY[k];
+               RoundedUpMaxSwathSizeBytesC[k] = swath_width_chroma_ub[k] * BytePerPixDETC[k] * MaximumSwathHeightC[k];
 #ifdef __DML_VBA_DEBUG__
                dml_print("DML::%s: k=%0d DPPPerSurface = %d\n", __func__, k, DPPPerSurface[k]);
                dml_print("DML::%s: k=%0d swath_width_luma_ub = %d\n", __func__, k, swath_width_luma_ub[k]);
                dml_print("DML::%s: k=%0d BytePerPixDETY = %f\n", __func__, k, BytePerPixDETY[k]);
-               dml_print("DML::%s: k=%0d MaximumSwathHeightY = %d\n", __func__, k, st_vars->MaximumSwathHeightY[k]);
+               dml_print("DML::%s: k=%0d MaximumSwathHeightY = %d\n", __func__, k, MaximumSwathHeightY[k]);
                dml_print("DML::%s: k=%0d RoundedUpMaxSwathSizeBytesY = %d\n", __func__, k,
-                               st_vars->RoundedUpMaxSwathSizeBytesY[k]);
+                               RoundedUpMaxSwathSizeBytesY[k]);
                dml_print("DML::%s: k=%0d swath_width_chroma_ub = %d\n", __func__, k, swath_width_chroma_ub[k]);
                dml_print("DML::%s: k=%0d BytePerPixDETC = %f\n", __func__, k, BytePerPixDETC[k]);
-               dml_print("DML::%s: k=%0d MaximumSwathHeightC = %d\n", __func__, k, st_vars->MaximumSwathHeightC[k]);
+               dml_print("DML::%s: k=%0d MaximumSwathHeightC = %d\n", __func__, k, MaximumSwathHeightC[k]);
                dml_print("DML::%s: k=%0d RoundedUpMaxSwathSizeBytesC = %d\n", __func__, k,
-                               st_vars->RoundedUpMaxSwathSizeBytesC[k]);
+                               RoundedUpMaxSwathSizeBytesC[k]);
 #endif
 
                if (SourcePixelFormat[k] == dm_420_10) {
-                       st_vars->RoundedUpMaxSwathSizeBytesY[k] = dml_ceil((unsigned int) st_vars->RoundedUpMaxSwathSizeBytesY[k], 256);
-                       st_vars->RoundedUpMaxSwathSizeBytesC[k] = dml_ceil((unsigned int) st_vars->RoundedUpMaxSwathSizeBytesC[k], 256);
+                       RoundedUpMaxSwathSizeBytesY[k] = dml_ceil((unsigned int) RoundedUpMaxSwathSizeBytesY[k], 256);
+                       RoundedUpMaxSwathSizeBytesC[k] = dml_ceil((unsigned int) RoundedUpMaxSwathSizeBytesC[k], 256);
                }
        }
 
        for (k = 0; k < NumberOfActiveSurfaces; ++k) {
-               st_vars->TotalActiveDPP = st_vars->TotalActiveDPP + (ForceSingleDPP ? 1 : DPPPerSurface[k]);
+               TotalActiveDPP = TotalActiveDPP + (ForceSingleDPP ? 1 : DPPPerSurface[k]);
                if (SourcePixelFormat[k] == dm_420_8 || SourcePixelFormat[k] == dm_420_10 ||
                                SourcePixelFormat[k] == dm_420_12 || SourcePixelFormat[k] == dm_rgbe_alpha) {
-                       st_vars->NoChromaSurfaces = false;
+                       NoChromaSurfaces = false;
                }
        }
 
@@ -540,10 +547,10 @@ void dml32_CalculateSwathAndDETConfiguration(
        // if unbounded req is enabled, program reserved space such that the ROB will not hold more than 8 swaths worth of data
        // - assume worst-case compression rate of 4. [ROB size - 8 * swath_size / max_compression ratio]
        // - assume for "narrow" vp case in which the ROB can fit 8 swaths, the DET should be big enough to do full size req
-       *CompBufReservedSpaceNeedAdjustment = ((int) ROBSizeKBytes - (int) *CompBufReservedSpaceKBytes) > (int) (st_vars->RoundedUpMaxSwathSizeBytesY[0]/512);
+       *CompBufReservedSpaceNeedAdjustment = ((int) ROBSizeKBytes - (int) *CompBufReservedSpaceKBytes) > (int) (RoundedUpMaxSwathSizeBytesY[0]/512);
 
        if (*CompBufReservedSpaceNeedAdjustment == 1) {
-               *CompBufReservedSpaceKBytes = ROBSizeKBytes - st_vars->RoundedUpMaxSwathSizeBytesY[0]/512;
+               *CompBufReservedSpaceKBytes = ROBSizeKBytes - RoundedUpMaxSwathSizeBytesY[0]/512;
        }
 
        #ifdef __DML_VBA_DEBUG__
@@ -551,7 +558,7 @@ void dml32_CalculateSwathAndDETConfiguration(
                dml_print("DML::%s: CompBufReservedSpaceNeedAdjustment  = %d\n",  __func__, *CompBufReservedSpaceNeedAdjustment);
        #endif
 
-       *UnboundedRequestEnabled = dml32_UnboundedRequest(UseUnboundedRequestingFinal, st_vars->TotalActiveDPP, st_vars->NoChromaSurfaces, Output[0], SurfaceTiling[0], *CompBufReservedSpaceNeedAdjustment, DisableUnboundRequestIfCompBufReservedSpaceNeedAdjustment);
+       *UnboundedRequestEnabled = dml32_UnboundedRequest(UseUnboundedRequestingFinal, TotalActiveDPP, NoChromaSurfaces, Output[0], SurfaceTiling[0], *CompBufReservedSpaceNeedAdjustment, DisableUnboundRequestIfCompBufReservedSpaceNeedAdjustment);
 
        dml32_CalculateDETBufferSize(DETSizeOverride,
                        UseMALLForPStateChange,
@@ -566,8 +573,8 @@ void dml32_CalculateSwathAndDETConfiguration(
                        SourcePixelFormat,
                        ReadBandwidthLuma,
                        ReadBandwidthChroma,
-                       st_vars->RoundedUpMaxSwathSizeBytesY,
-                       st_vars->RoundedUpMaxSwathSizeBytesC,
+                       RoundedUpMaxSwathSizeBytesY,
+                       RoundedUpMaxSwathSizeBytesC,
                        DPPPerSurface,
 
                        /* Output */
@@ -575,7 +582,7 @@ void dml32_CalculateSwathAndDETConfiguration(
                        CompressedBufferSizeInkByte);
 
 #ifdef __DML_VBA_DEBUG__
-       dml_print("DML::%s: TotalActiveDPP = %d\n", __func__, st_vars->TotalActiveDPP);
+       dml_print("DML::%s: TotalActiveDPP = %d\n", __func__, TotalActiveDPP);
        dml_print("DML::%s: nomDETInKByte = %d\n", __func__, nomDETInKByte);
        dml_print("DML::%s: ConfigReturnBufferSizeInKByte = %d\n", __func__, ConfigReturnBufferSizeInKByte);
        dml_print("DML::%s: UseUnboundedRequestingFinal = %d\n", __func__, UseUnboundedRequestingFinal);
@@ -586,42 +593,42 @@ void dml32_CalculateSwathAndDETConfiguration(
        *ViewportSizeSupport = true;
        for (k = 0; k < NumberOfActiveSurfaces; ++k) {
 
-               st_vars->DETBufferSizeInKByteForSwathCalculation = (UseMALLForPStateChange[k] ==
+               DETBufferSizeInKByteForSwathCalculation = (UseMALLForPStateChange[k] ==
                                dm_use_mall_pstate_change_phantom_pipe ? 1024 : DETBufferSizeInKByte[k]);
 #ifdef __DML_VBA_DEBUG__
                dml_print("DML::%s: k=%0d DETBufferSizeInKByteForSwathCalculation = %d\n", __func__, k,
-                               st_vars->DETBufferSizeInKByteForSwathCalculation);
+                               DETBufferSizeInKByteForSwathCalculation);
 #endif
 
-               if (st_vars->RoundedUpMaxSwathSizeBytesY[k] + st_vars->RoundedUpMaxSwathSizeBytesC[k] <=
-                               st_vars->DETBufferSizeInKByteForSwathCalculation * 1024 / 2) {
-                       SwathHeightY[k] = st_vars->MaximumSwathHeightY[k];
-                       SwathHeightC[k] = st_vars->MaximumSwathHeightC[k];
-                       st_vars->RoundedUpSwathSizeBytesY = st_vars->RoundedUpMaxSwathSizeBytesY[k];
-                       st_vars->RoundedUpSwathSizeBytesC = st_vars->RoundedUpMaxSwathSizeBytesC[k];
-               } else if (st_vars->RoundedUpMaxSwathSizeBytesY[k] >= 1.5 * st_vars->RoundedUpMaxSwathSizeBytesC[k] &&
-                               st_vars->RoundedUpMaxSwathSizeBytesY[k] / 2 + st_vars->RoundedUpMaxSwathSizeBytesC[k] <=
-                               st_vars->DETBufferSizeInKByteForSwathCalculation * 1024 / 2) {
-                       SwathHeightY[k] = st_vars->MaximumSwathHeightY[k] / 2;
-                       SwathHeightC[k] = st_vars->MaximumSwathHeightC[k];
-                       st_vars->RoundedUpSwathSizeBytesY = st_vars->RoundedUpMaxSwathSizeBytesY[k] / 2;
-                       st_vars->RoundedUpSwathSizeBytesC = st_vars->RoundedUpMaxSwathSizeBytesC[k];
-               } else if (st_vars->RoundedUpMaxSwathSizeBytesY[k] < 1.5 * st_vars->RoundedUpMaxSwathSizeBytesC[k] &&
-                               st_vars->RoundedUpMaxSwathSizeBytesY[k] + st_vars->RoundedUpMaxSwathSizeBytesC[k] / 2 <=
-                               st_vars->DETBufferSizeInKByteForSwathCalculation * 1024 / 2) {
-                       SwathHeightY[k] = st_vars->MaximumSwathHeightY[k];
-                       SwathHeightC[k] = st_vars->MaximumSwathHeightC[k] / 2;
-                       st_vars->RoundedUpSwathSizeBytesY = st_vars->RoundedUpMaxSwathSizeBytesY[k];
-                       st_vars->RoundedUpSwathSizeBytesC = st_vars->RoundedUpMaxSwathSizeBytesC[k] / 2;
+               if (RoundedUpMaxSwathSizeBytesY[k] + RoundedUpMaxSwathSizeBytesC[k] <=
+                               DETBufferSizeInKByteForSwathCalculation * 1024 / 2) {
+                       SwathHeightY[k] = MaximumSwathHeightY[k];
+                       SwathHeightC[k] = MaximumSwathHeightC[k];
+                       RoundedUpSwathSizeBytesY = RoundedUpMaxSwathSizeBytesY[k];
+                       RoundedUpSwathSizeBytesC = RoundedUpMaxSwathSizeBytesC[k];
+               } else if (RoundedUpMaxSwathSizeBytesY[k] >= 1.5 * RoundedUpMaxSwathSizeBytesC[k] &&
+                               RoundedUpMaxSwathSizeBytesY[k] / 2 + RoundedUpMaxSwathSizeBytesC[k] <=
+                               DETBufferSizeInKByteForSwathCalculation * 1024 / 2) {
+                       SwathHeightY[k] = MaximumSwathHeightY[k] / 2;
+                       SwathHeightC[k] = MaximumSwathHeightC[k];
+                       RoundedUpSwathSizeBytesY = RoundedUpMaxSwathSizeBytesY[k] / 2;
+                       RoundedUpSwathSizeBytesC = RoundedUpMaxSwathSizeBytesC[k];
+               } else if (RoundedUpMaxSwathSizeBytesY[k] < 1.5 * RoundedUpMaxSwathSizeBytesC[k] &&
+                               RoundedUpMaxSwathSizeBytesY[k] + RoundedUpMaxSwathSizeBytesC[k] / 2 <=
+                               DETBufferSizeInKByteForSwathCalculation * 1024 / 2) {
+                       SwathHeightY[k] = MaximumSwathHeightY[k];
+                       SwathHeightC[k] = MaximumSwathHeightC[k] / 2;
+                       RoundedUpSwathSizeBytesY = RoundedUpMaxSwathSizeBytesY[k];
+                       RoundedUpSwathSizeBytesC = RoundedUpMaxSwathSizeBytesC[k] / 2;
                } else {
-                       SwathHeightY[k] = st_vars->MaximumSwathHeightY[k] / 2;
-                       SwathHeightC[k] = st_vars->MaximumSwathHeightC[k] / 2;
-                       st_vars->RoundedUpSwathSizeBytesY = st_vars->RoundedUpMaxSwathSizeBytesY[k] / 2;
-                       st_vars->RoundedUpSwathSizeBytesC = st_vars->RoundedUpMaxSwathSizeBytesC[k] / 2;
+                       SwathHeightY[k] = MaximumSwathHeightY[k] / 2;
+                       SwathHeightC[k] = MaximumSwathHeightC[k] / 2;
+                       RoundedUpSwathSizeBytesY = RoundedUpMaxSwathSizeBytesY[k] / 2;
+                       RoundedUpSwathSizeBytesC = RoundedUpMaxSwathSizeBytesC[k] / 2;
                }
 
-               if ((st_vars->RoundedUpMaxSwathSizeBytesY[k] / 2 + st_vars->RoundedUpMaxSwathSizeBytesC[k] / 2 >
-                               st_vars->DETBufferSizeInKByteForSwathCalculation * 1024 / 2)
+               if ((RoundedUpMaxSwathSizeBytesY[k] / 2 + RoundedUpMaxSwathSizeBytesC[k] / 2 >
+                               DETBufferSizeInKByteForSwathCalculation * 1024 / 2)
                                || SwathWidth[k] > MaximumSwathWidthLuma[k] || (SwathHeightC[k] > 0 &&
                                                SwathWidthChroma[k] > MaximumSwathWidthChroma[k])) {
                        *ViewportSizeSupport = false;
@@ -636,7 +643,7 @@ void dml32_CalculateSwathAndDETConfiguration(
 #endif
                        DETBufferSizeY[k] = DETBufferSizeInKByte[k] * 1024;
                        DETBufferSizeC[k] = 0;
-               } else if (st_vars->RoundedUpSwathSizeBytesY <= 1.5 * st_vars->RoundedUpSwathSizeBytesC) {
+               } else if (RoundedUpSwathSizeBytesY <= 1.5 * RoundedUpSwathSizeBytesC) {
 #ifdef __DML_VBA_DEBUG__
                        dml_print("DML::%s: k=%0d Half DET for plane0, half for plane1\n", __func__, k);
 #endif
@@ -654,11 +661,11 @@ void dml32_CalculateSwathAndDETConfiguration(
                dml_print("DML::%s: k=%0d SwathHeightY = %d\n", __func__, k, SwathHeightY[k]);
                dml_print("DML::%s: k=%0d SwathHeightC = %d\n", __func__, k, SwathHeightC[k]);
                dml_print("DML::%s: k=%0d RoundedUpMaxSwathSizeBytesY = %d\n", __func__,
-                               k, st_vars->RoundedUpMaxSwathSizeBytesY[k]);
+                               k, RoundedUpMaxSwathSizeBytesY[k]);
                dml_print("DML::%s: k=%0d RoundedUpMaxSwathSizeBytesC = %d\n", __func__,
-                               k, st_vars->RoundedUpMaxSwathSizeBytesC[k]);
-               dml_print("DML::%s: k=%0d RoundedUpSwathSizeBytesY = %d\n", __func__, k, st_vars->RoundedUpSwathSizeBytesY);
-               dml_print("DML::%s: k=%0d RoundedUpSwathSizeBytesC = %d\n", __func__, k, st_vars->RoundedUpSwathSizeBytesC);
+                               k, RoundedUpMaxSwathSizeBytesC[k]);
+               dml_print("DML::%s: k=%0d RoundedUpSwathSizeBytesY = %d\n", __func__, k, RoundedUpSwathSizeBytesY);
+               dml_print("DML::%s: k=%0d RoundedUpSwathSizeBytesC = %d\n", __func__, k, RoundedUpSwathSizeBytesC);
                dml_print("DML::%s: k=%0d DETBufferSizeInKByte = %d\n", __func__, k, DETBufferSizeInKByte[k]);
                dml_print("DML::%s: k=%0d DETBufferSizeY = %d\n", __func__, k, DETBufferSizeY[k]);
                dml_print("DML::%s: k=%0d DETBufferSizeC = %d\n", __func__, k, DETBufferSizeC[k]);
@@ -1867,7 +1874,6 @@ void dml32_CalculateSurfaceSizeInMall(
 } // CalculateSurfaceSizeInMall
 
 void dml32_CalculateVMRowAndSwath(
-               struct dml32_CalculateVMRowAndSwath *st_vars,
                unsigned int NumberOfActiveSurfaces,
                DmlPipe myPipe[],
                unsigned int SurfaceSizeInMALL[],
@@ -1933,6 +1939,21 @@ void dml32_CalculateVMRowAndSwath(
                unsigned int BIGK_FRAGMENT_SIZE[])
 {
        unsigned int k;
+       unsigned int PTEBufferSizeInRequestsForLuma[DC__NUM_DPP__MAX];
+       unsigned int PTEBufferSizeInRequestsForChroma[DC__NUM_DPP__MAX];
+       unsigned int PDEAndMetaPTEBytesFrameY;
+       unsigned int PDEAndMetaPTEBytesFrameC;
+       unsigned int MetaRowByteY[DC__NUM_DPP__MAX];
+       unsigned int MetaRowByteC[DC__NUM_DPP__MAX];
+       unsigned int PixelPTEBytesPerRowY[DC__NUM_DPP__MAX];
+       unsigned int PixelPTEBytesPerRowC[DC__NUM_DPP__MAX];
+       unsigned int PixelPTEBytesPerRowY_one_row_per_frame[DC__NUM_DPP__MAX];
+       unsigned int PixelPTEBytesPerRowC_one_row_per_frame[DC__NUM_DPP__MAX];
+       unsigned int dpte_row_width_luma_ub_one_row_per_frame[DC__NUM_DPP__MAX];
+       unsigned int dpte_row_height_luma_one_row_per_frame[DC__NUM_DPP__MAX];
+       unsigned int dpte_row_width_chroma_ub_one_row_per_frame[DC__NUM_DPP__MAX];
+       unsigned int dpte_row_height_chroma_one_row_per_frame[DC__NUM_DPP__MAX];
+       bool one_row_per_frame_fits_in_buffer[DC__NUM_DPP__MAX];
 
        for (k = 0; k < NumberOfActiveSurfaces; ++k) {
                if (HostVMEnable == true) {
@@ -1954,15 +1975,15 @@ void dml32_CalculateVMRowAndSwath(
                                myPipe[k].SourcePixelFormat == dm_rgbe_alpha) {
                        if ((myPipe[k].SourcePixelFormat == dm_420_10 || myPipe[k].SourcePixelFormat == dm_420_12) &&
                                        !IsVertical(myPipe[k].SourceRotation)) {
-                               st_vars->PTEBufferSizeInRequestsForLuma[k] =
+                               PTEBufferSizeInRequestsForLuma[k] =
                                                (PTEBufferSizeInRequestsLuma + PTEBufferSizeInRequestsChroma) / 2;
-                               st_vars->PTEBufferSizeInRequestsForChroma[k] = st_vars->PTEBufferSizeInRequestsForLuma[k];
+                               PTEBufferSizeInRequestsForChroma[k] = PTEBufferSizeInRequestsForLuma[k];
                        } else {
-                               st_vars->PTEBufferSizeInRequestsForLuma[k] = PTEBufferSizeInRequestsLuma;
-                               st_vars->PTEBufferSizeInRequestsForChroma[k] = PTEBufferSizeInRequestsChroma;
+                               PTEBufferSizeInRequestsForLuma[k] = PTEBufferSizeInRequestsLuma;
+                               PTEBufferSizeInRequestsForChroma[k] = PTEBufferSizeInRequestsChroma;
                        }
 
-                       st_vars->PDEAndMetaPTEBytesFrameC = dml32_CalculateVMAndRowBytes(
+                       PDEAndMetaPTEBytesFrameC = dml32_CalculateVMAndRowBytes(
                                        myPipe[k].ViewportStationary,
                                        myPipe[k].DCCEnable,
                                        myPipe[k].DPPPerSurface,
@@ -1982,21 +2003,21 @@ void dml32_CalculateVMRowAndSwath(
                                        GPUVMMaxPageTableLevels,
                                        GPUVMMinPageSizeKBytes[k],
                                        HostVMMinPageSize,
-                                       st_vars->PTEBufferSizeInRequestsForChroma[k],
+                                       PTEBufferSizeInRequestsForChroma[k],
                                        myPipe[k].PitchC,
                                        myPipe[k].DCCMetaPitchC,
                                        myPipe[k].BlockWidthC,
                                        myPipe[k].BlockHeightC,
 
                                        /* Output */
-                                       &st_vars->MetaRowByteC[k],
-                                       &st_vars->PixelPTEBytesPerRowC[k],
+                                       &MetaRowByteC[k],
+                                       &PixelPTEBytesPerRowC[k],
                                        &dpte_row_width_chroma_ub[k],
                                        &dpte_row_height_chroma[k],
                                        &dpte_row_height_linear_chroma[k],
-                                       &st_vars->PixelPTEBytesPerRowC_one_row_per_frame[k],
-                                       &st_vars->dpte_row_width_chroma_ub_one_row_per_frame[k],
-                                       &st_vars->dpte_row_height_chroma_one_row_per_frame[k],
+                                       &PixelPTEBytesPerRowC_one_row_per_frame[k],
+                                       &dpte_row_width_chroma_ub_one_row_per_frame[k],
+                                       &dpte_row_height_chroma_one_row_per_frame[k],
                                        &meta_req_width_chroma[k],
                                        &meta_req_height_chroma[k],
                                        &meta_row_width_chroma[k],
@@ -2024,19 +2045,19 @@ void dml32_CalculateVMRowAndSwath(
                                        &VInitPreFillC[k],
                                        &MaxNumSwathC[k]);
                } else {
-                       st_vars->PTEBufferSizeInRequestsForLuma[k] = PTEBufferSizeInRequestsLuma + PTEBufferSizeInRequestsChroma;
-                       st_vars->PTEBufferSizeInRequestsForChroma[k] = 0;
-                       st_vars->PixelPTEBytesPerRowC[k] = 0;
-                       st_vars->PDEAndMetaPTEBytesFrameC = 0;
-                       st_vars->MetaRowByteC[k] = 0;
+                       PTEBufferSizeInRequestsForLuma[k] = PTEBufferSizeInRequestsLuma + PTEBufferSizeInRequestsChroma;
+                       PTEBufferSizeInRequestsForChroma[k] = 0;
+                       PixelPTEBytesPerRowC[k] = 0;
+                       PDEAndMetaPTEBytesFrameC = 0;
+                       MetaRowByteC[k] = 0;
                        MaxNumSwathC[k] = 0;
                        PrefetchSourceLinesC[k] = 0;
-                       st_vars->dpte_row_height_chroma_one_row_per_frame[k] = 0;
-                       st_vars->dpte_row_width_chroma_ub_one_row_per_frame[k] = 0;
-                       st_vars->PixelPTEBytesPerRowC_one_row_per_frame[k] = 0;
+                       dpte_row_height_chroma_one_row_per_frame[k] = 0;
+                       dpte_row_width_chroma_ub_one_row_per_frame[k] = 0;
+                       PixelPTEBytesPerRowC_one_row_per_frame[k] = 0;
                }
 
-               st_vars->PDEAndMetaPTEBytesFrameY = dml32_CalculateVMAndRowBytes(
+               PDEAndMetaPTEBytesFrameY = dml32_CalculateVMAndRowBytes(
                                myPipe[k].ViewportStationary,
                                myPipe[k].DCCEnable,
                                myPipe[k].DPPPerSurface,
@@ -2056,21 +2077,21 @@ void dml32_CalculateVMRowAndSwath(
                                GPUVMMaxPageTableLevels,
                                GPUVMMinPageSizeKBytes[k],
                                HostVMMinPageSize,
-                               st_vars->PTEBufferSizeInRequestsForLuma[k],
+                               PTEBufferSizeInRequestsForLuma[k],
                                myPipe[k].PitchY,
                                myPipe[k].DCCMetaPitchY,
                                myPipe[k].BlockWidthY,
                                myPipe[k].BlockHeightY,
 
                                /* Output */
-                               &st_vars->MetaRowByteY[k],
-                               &st_vars->PixelPTEBytesPerRowY[k],
+                               &MetaRowByteY[k],
+                               &PixelPTEBytesPerRowY[k],
                                &dpte_row_width_luma_ub[k],
                                &dpte_row_height_luma[k],
                                &dpte_row_height_linear_luma[k],
-                               &st_vars->PixelPTEBytesPerRowY_one_row_per_frame[k],
-                               &st_vars->dpte_row_width_luma_ub_one_row_per_frame[k],
-                               &st_vars->dpte_row_height_luma_one_row_per_frame[k],
+                               &PixelPTEBytesPerRowY_one_row_per_frame[k],
+                               &dpte_row_width_luma_ub_one_row_per_frame[k],
+                               &dpte_row_height_luma_one_row_per_frame[k],
                                &meta_req_width[k],
                                &meta_req_height[k],
                                &meta_row_width[k],
@@ -2098,19 +2119,19 @@ void dml32_CalculateVMRowAndSwath(
                                &VInitPreFillY[k],
                                &MaxNumSwathY[k]);
 
-               PDEAndMetaPTEBytesFrame[k] = st_vars->PDEAndMetaPTEBytesFrameY + st_vars->PDEAndMetaPTEBytesFrameC;
-               MetaRowByte[k] = st_vars->MetaRowByteY[k] + st_vars->MetaRowByteC[k];
+               PDEAndMetaPTEBytesFrame[k] = PDEAndMetaPTEBytesFrameY + PDEAndMetaPTEBytesFrameC;
+               MetaRowByte[k] = MetaRowByteY[k] + MetaRowByteC[k];
 
-               if (st_vars->PixelPTEBytesPerRowY[k] <= 64 * st_vars->PTEBufferSizeInRequestsForLuma[k] &&
-                               st_vars->PixelPTEBytesPerRowC[k] <= 64 * st_vars->PTEBufferSizeInRequestsForChroma[k]) {
+               if (PixelPTEBytesPerRowY[k] <= 64 * PTEBufferSizeInRequestsForLuma[k] &&
+                               PixelPTEBytesPerRowC[k] <= 64 * PTEBufferSizeInRequestsForChroma[k]) {
                        PTEBufferSizeNotExceeded[k] = true;
                } else {
                        PTEBufferSizeNotExceeded[k] = false;
                }
 
-               st_vars->one_row_per_frame_fits_in_buffer[k] = (st_vars->PixelPTEBytesPerRowY_one_row_per_frame[k] <= 64 * 2 *
-                       st_vars->PTEBufferSizeInRequestsForLuma[k] &&
-                       st_vars->PixelPTEBytesPerRowC_one_row_per_frame[k] <= 64 * 2 * st_vars->PTEBufferSizeInRequestsForChroma[k]);
+               one_row_per_frame_fits_in_buffer[k] = (PixelPTEBytesPerRowY_one_row_per_frame[k] <= 64 * 2 *
+                       PTEBufferSizeInRequestsForLuma[k] &&
+                       PixelPTEBytesPerRowC_one_row_per_frame[k] <= 64 * 2 * PTEBufferSizeInRequestsForChroma[k]);
        }
 
        dml32_CalculateMALLUseForStaticScreen(
@@ -2118,7 +2139,7 @@ void dml32_CalculateVMRowAndSwath(
                        MALLAllocatedForDCN,
                        UseMALLForStaticScreen,   // mode
                        SurfaceSizeInMALL,
-                       st_vars->one_row_per_frame_fits_in_buffer,
+                       one_row_per_frame_fits_in_buffer,
                        /* Output */
                        UsesMALLForStaticScreen); // boolen
 
@@ -2144,13 +2165,13 @@ void dml32_CalculateVMRowAndSwath(
                                !(UseMALLForPStateChange[k] == dm_use_mall_pstate_change_full_frame);
 
                if (use_one_row_for_frame[k]) {
-                       dpte_row_height_luma[k] = st_vars->dpte_row_height_luma_one_row_per_frame[k];
-                       dpte_row_width_luma_ub[k] = st_vars->dpte_row_width_luma_ub_one_row_per_frame[k];
-                       st_vars->PixelPTEBytesPerRowY[k] = st_vars->PixelPTEBytesPerRowY_one_row_per_frame[k];
-                       dpte_row_height_chroma[k] = st_vars->dpte_row_height_chroma_one_row_per_frame[k];
-                       dpte_row_width_chroma_ub[k] = st_vars->dpte_row_width_chroma_ub_one_row_per_frame[k];
-                       st_vars->PixelPTEBytesPerRowC[k] = st_vars->PixelPTEBytesPerRowC_one_row_per_frame[k];
-                       PTEBufferSizeNotExceeded[k] = st_vars->one_row_per_frame_fits_in_buffer[k];
+                       dpte_row_height_luma[k] = dpte_row_height_luma_one_row_per_frame[k];
+                       dpte_row_width_luma_ub[k] = dpte_row_width_luma_ub_one_row_per_frame[k];
+                       PixelPTEBytesPerRowY[k] = PixelPTEBytesPerRowY_one_row_per_frame[k];
+                       dpte_row_height_chroma[k] = dpte_row_height_chroma_one_row_per_frame[k];
+                       dpte_row_width_chroma_ub[k] = dpte_row_width_chroma_ub_one_row_per_frame[k];
+                       PixelPTEBytesPerRowC[k] = PixelPTEBytesPerRowC_one_row_per_frame[k];
+                       PTEBufferSizeNotExceeded[k] = one_row_per_frame_fits_in_buffer[k];
                }
 
                if (MetaRowByte[k] <= DCCMetaBufferSizeBytes)
@@ -2158,7 +2179,7 @@ void dml32_CalculateVMRowAndSwath(
                else
                        DCCMetaBufferSizeNotExceeded[k] = false;
 
-               PixelPTEBytesPerRow[k] = st_vars->PixelPTEBytesPerRowY[k] + st_vars->PixelPTEBytesPerRowC[k];
+               PixelPTEBytesPerRow[k] = PixelPTEBytesPerRowY[k] + PixelPTEBytesPerRowC[k];
                if (use_one_row_for_frame[k])
                        PixelPTEBytesPerRow[k] = PixelPTEBytesPerRow[k] / 2;
 
@@ -2169,11 +2190,11 @@ void dml32_CalculateVMRowAndSwath(
                                myPipe[k].VRatioChroma,
                                myPipe[k].DCCEnable,
                                myPipe[k].HTotal / myPipe[k].PixelClock,
-                               st_vars->MetaRowByteY[k], st_vars->MetaRowByteC[k],
+                               MetaRowByteY[k], MetaRowByteC[k],
                                meta_row_height[k],
                                meta_row_height_chroma[k],
-                               st_vars->PixelPTEBytesPerRowY[k],
-                               st_vars->PixelPTEBytesPerRowC[k],
+                               PixelPTEBytesPerRowY[k],
+                               PixelPTEBytesPerRowC[k],
                                dpte_row_height_luma[k],
                                dpte_row_height_chroma[k],
 
@@ -2189,12 +2210,12 @@ void dml32_CalculateVMRowAndSwath(
                dml_print("DML::%s: k=%d, dpte_row_height_luma         = %d\n",  __func__, k, dpte_row_height_luma[k]);
                dml_print("DML::%s: k=%d, dpte_row_width_luma_ub       = %d\n",
                                __func__, k, dpte_row_width_luma_ub[k]);
-               dml_print("DML::%s: k=%d, PixelPTEBytesPerRowY         = %d\n",  __func__, k, st_vars->PixelPTEBytesPerRowY[k]);
+               dml_print("DML::%s: k=%d, PixelPTEBytesPerRowY         = %d\n",  __func__, k, PixelPTEBytesPerRowY[k]);
                dml_print("DML::%s: k=%d, dpte_row_height_chroma       = %d\n",
                                __func__, k, dpte_row_height_chroma[k]);
                dml_print("DML::%s: k=%d, dpte_row_width_chroma_ub     = %d\n",
                                __func__, k, dpte_row_width_chroma_ub[k]);
-               dml_print("DML::%s: k=%d, PixelPTEBytesPerRowC         = %d\n",  __func__, k, st_vars->PixelPTEBytesPerRowC[k]);
+               dml_print("DML::%s: k=%d, PixelPTEBytesPerRowC         = %d\n",  __func__, k, PixelPTEBytesPerRowC[k]);
                dml_print("DML::%s: k=%d, PixelPTEBytesPerRow          = %d\n",  __func__, k, PixelPTEBytesPerRow[k]);
                dml_print("DML::%s: k=%d, PTEBufferSizeNotExceeded     = %d\n",
                                __func__, k, PTEBufferSizeNotExceeded[k]);
@@ -3342,29 +3363,14 @@ double dml32_CalculateExtraLatency(
 } // CalculateExtraLatency
 
 bool dml32_CalculatePrefetchSchedule(
-               struct dml32_CalculatePrefetchSchedule *st_vars,
+               struct vba_vars_st *v,
+               unsigned int k,
                double HostVMInefficiencyFactor,
                DmlPipe *myPipe,
                unsigned int DSCDelay,
-               double DPPCLKDelaySubtotalPlusCNVCFormater,
-               double DPPCLKDelaySCL,
-               double DPPCLKDelaySCLLBOnly,
-               double DPPCLKDelayCNVCCursor,
-               double DISPCLKDelaySubtotal,
                unsigned int DPP_RECOUT_WIDTH,
-               enum output_format_class OutputFormat,
-               unsigned int MaxInterDCNTileRepeaters,
                unsigned int VStartup,
                unsigned int MaxVStartup,
-               unsigned int GPUVMPageTableLevels,
-               bool GPUVMEnable,
-               bool HostVMEnable,
-               unsigned int HostVMMaxNonCachedPageTableLevels,
-               double HostVMMinPageSize,
-               bool DynamicMetadataEnable,
-               bool DynamicMetadataVMEnabled,
-               int DynamicMetadataLinesBeforeActiveRequired,
-               unsigned int DynamicMetadataTransmittedBytes,
                double UrgentLatency,
                double UrgentExtraLatency,
                double TCalc,
@@ -3405,72 +3411,100 @@ bool dml32_CalculatePrefetchSchedule(
                double   *VUpdateWidthPix,
                double   *VReadyOffsetPix)
 {
+       double DPPCLKDelaySubtotalPlusCNVCFormater = v->DPPCLKDelaySubtotal + v->DPPCLKDelayCNVCFormater;
        bool MyError = false;
-
-       st_vars->TimeForFetchingMetaPTE = 0;
-       st_vars->TimeForFetchingRowInVBlank = 0;
-       st_vars->LinesToRequestPrefetchPixelData = 0;
-       st_vars->max_vratio_pre = __DML_MAX_VRATIO_PRE__;
-       st_vars->Tsw_est1 = 0;
-       st_vars->Tsw_est3 = 0;
-
-       if (GPUVMEnable == true && HostVMEnable == true)
-               st_vars->HostVMDynamicLevelsTrips = HostVMMaxNonCachedPageTableLevels;
+       unsigned int DPPCycles, DISPCLKCycles;
+       double DSTTotalPixelsAfterScaler;
+       double LineTime;
+       double dst_y_prefetch_equ;
+       double prefetch_bw_oto;
+       double Tvm_oto;
+       double Tr0_oto;
+       double Tvm_oto_lines;
+       double Tr0_oto_lines;
+       double dst_y_prefetch_oto;
+       double TimeForFetchingMetaPTE = 0;
+       double TimeForFetchingRowInVBlank = 0;
+       double LinesToRequestPrefetchPixelData = 0;
+       unsigned int HostVMDynamicLevelsTrips;
+       double  trip_to_mem;
+       double  Tvm_trips;
+       double  Tr0_trips;
+       double  Tvm_trips_rounded;
+       double  Tr0_trips_rounded;
+       double  Lsw_oto;
+       double  Tpre_rounded;
+       double  prefetch_bw_equ;
+       double  Tvm_equ;
+       double  Tr0_equ;
+       double  Tdmbf;
+       double  Tdmec;
+       double  Tdmsks;
+       double  prefetch_sw_bytes;
+       double  bytes_pp;
+       double  dep_bytes;
+       unsigned int max_vratio_pre = __DML_MAX_VRATIO_PRE__;
+       double  min_Lsw;
+       double  Tsw_est1 = 0;
+       double  Tsw_est3 = 0;
+
+       if (v->GPUVMEnable == true && v->HostVMEnable == true)
+               HostVMDynamicLevelsTrips = v->HostVMMaxNonCachedPageTableLevels;
        else
-               st_vars->HostVMDynamicLevelsTrips = 0;
+               HostVMDynamicLevelsTrips = 0;
 #ifdef __DML_VBA_DEBUG__
-       dml_print("DML::%s: GPUVMEnable = %d\n", __func__, GPUVMEnable);
-       dml_print("DML::%s: GPUVMPageTableLevels = %d\n", __func__, GPUVMPageTableLevels);
+       dml_print("DML::%s: v->GPUVMEnable = %d\n", __func__, v->GPUVMEnable);
+       dml_print("DML::%s: v->GPUVMMaxPageTableLevels = %d\n", __func__, v->GPUVMMaxPageTableLevels);
        dml_print("DML::%s: DCCEnable = %d\n", __func__, myPipe->DCCEnable);
-       dml_print("DML::%s: HostVMEnable=%d HostVMInefficiencyFactor=%f\n",
-                       __func__, HostVMEnable, HostVMInefficiencyFactor);
+       dml_print("DML::%s: v->HostVMEnable=%d HostVMInefficiencyFactor=%f\n",
+                       __func__, v->HostVMEnable, HostVMInefficiencyFactor);
 #endif
        dml32_CalculateVUpdateAndDynamicMetadataParameters(
-                       MaxInterDCNTileRepeaters,
+                       v->MaxInterDCNTileRepeaters,
                        myPipe->Dppclk,
                        myPipe->Dispclk,
                        myPipe->DCFClkDeepSleep,
                        myPipe->PixelClock,
                        myPipe->HTotal,
                        myPipe->VBlank,
-                       DynamicMetadataTransmittedBytes,
-                       DynamicMetadataLinesBeforeActiveRequired,
+                       v->DynamicMetadataTransmittedBytes[k],
+                       v->DynamicMetadataLinesBeforeActiveRequired[k],
                        myPipe->InterlaceEnable,
                        myPipe->ProgressiveToInterlaceUnitInOPP,
                        TSetup,
 
                        /* output */
-                       &st_vars->Tdmbf,
-                       &st_vars->Tdmec,
-                       &st_vars->Tdmsks,
+                       &Tdmbf,
+                       &Tdmec,
+                       &Tdmsks,
                        VUpdateOffsetPix,
                        VUpdateWidthPix,
                        VReadyOffsetPix);
 
-       st_vars->LineTime = myPipe->HTotal / myPipe->PixelClock;
-       st_vars->trip_to_mem = UrgentLatency;
-       st_vars->Tvm_trips = UrgentExtraLatency + st_vars->trip_to_mem * (GPUVMPageTableLevels * (st_vars->HostVMDynamicLevelsTrips + 1) - 1);
+       LineTime = myPipe->HTotal / myPipe->PixelClock;
+       trip_to_mem = UrgentLatency;
+       Tvm_trips = UrgentExtraLatency + trip_to_mem * (v->GPUVMMaxPageTableLevels * (HostVMDynamicLevelsTrips + 1) - 1);
 
-       if (DynamicMetadataVMEnabled == true)
-               *Tdmdl = TWait + st_vars->Tvm_trips + st_vars->trip_to_mem;
+       if (v->DynamicMetadataVMEnabled == true)
+               *Tdmdl = TWait + Tvm_trips + trip_to_mem;
        else
                *Tdmdl = TWait + UrgentExtraLatency;
 
 #ifdef __DML_VBA_ALLOW_DELTA__
-       if (DynamicMetadataEnable == false)
+       if (v->DynamicMetadataEnable[k] == false)
                *Tdmdl = 0.0;
 #endif
 
-       if (DynamicMetadataEnable == true) {
-               if (VStartup * st_vars->LineTime < *TSetup + *Tdmdl + st_vars->Tdmbf + st_vars->Tdmec + st_vars->Tdmsks) {
+       if (v->DynamicMetadataEnable[k] == true) {
+               if (VStartup * LineTime < *TSetup + *Tdmdl + Tdmbf + Tdmec + Tdmsks) {
                        *NotEnoughTimeForDynamicMetadata = true;
 #ifdef __DML_VBA_DEBUG__
                        dml_print("DML::%s: Not Enough Time for Dynamic Meta!\n", __func__);
                        dml_print("DML::%s: Tdmbf: %fus - time for dmd transfer from dchub to dio output buffer\n",
-                                       __func__, st_vars->Tdmbf);
-                       dml_print("DML::%s: Tdmec: %fus - time dio takes to transfer dmd\n", __func__, st_vars->Tdmec);
+                                       __func__, Tdmbf);
+                       dml_print("DML::%s: Tdmec: %fus - time dio takes to transfer dmd\n", __func__, Tdmec);
                        dml_print("DML::%s: Tdmsks: %fus - time before active dmd must complete transmission at dio\n",
-                                       __func__, st_vars->Tdmsks);
+                                       __func__, Tdmsks);
                        dml_print("DML::%s: Tdmdl: %fus - time for fabric to become ready and fetch dmd\n",
                                        __func__, *Tdmdl);
 #endif
@@ -3481,22 +3515,22 @@ bool dml32_CalculatePrefetchSchedule(
                *NotEnoughTimeForDynamicMetadata = false;
        }
 
-       *Tdmdl_vm =  (DynamicMetadataEnable == true && DynamicMetadataVMEnabled == true &&
-                       GPUVMEnable == true ? TWait + st_vars->Tvm_trips : 0);
+       *Tdmdl_vm =  (v->DynamicMetadataEnable[k] == true && v->DynamicMetadataVMEnabled == true &&
+                       v->GPUVMEnable == true ? TWait + Tvm_trips : 0);
 
        if (myPipe->ScalerEnabled)
-               st_vars->DPPCycles = DPPCLKDelaySubtotalPlusCNVCFormater + DPPCLKDelaySCL;
+               DPPCycles = DPPCLKDelaySubtotalPlusCNVCFormater + v->DPPCLKDelaySCL;
        else
-               st_vars->DPPCycles = DPPCLKDelaySubtotalPlusCNVCFormater + DPPCLKDelaySCLLBOnly;
+               DPPCycles = DPPCLKDelaySubtotalPlusCNVCFormater + v->DPPCLKDelaySCLLBOnly;
 
-       st_vars->DPPCycles = st_vars->DPPCycles + myPipe->NumberOfCursors * DPPCLKDelayCNVCCursor;
+       DPPCycles = DPPCycles + myPipe->NumberOfCursors * v->DPPCLKDelayCNVCCursor;
 
-       st_vars->DISPCLKCycles = DISPCLKDelaySubtotal;
+       DISPCLKCycles = v->DISPCLKDelaySubtotal;
 
        if (myPipe->Dppclk == 0.0 || myPipe->Dispclk == 0.0)
                return true;
 
-       *DSTXAfterScaler = st_vars->DPPCycles * myPipe->PixelClock / myPipe->Dppclk + st_vars->DISPCLKCycles *
+       *DSTXAfterScaler = DPPCycles * myPipe->PixelClock / myPipe->Dppclk + DISPCLKCycles *
                        myPipe->PixelClock / myPipe->Dispclk + DSCDelay;
 
        *DSTXAfterScaler = *DSTXAfterScaler + (myPipe->ODMMode != dm_odm_combine_mode_disabled ? 18 : 0)
@@ -3506,10 +3540,10 @@ bool dml32_CalculatePrefetchSchedule(
                        + ((myPipe->ODMMode == dm_odm_mode_mso_1to4) ? myPipe->HActive * 3 / 4 : 0);
 
 #ifdef __DML_VBA_DEBUG__
-       dml_print("DML::%s: DPPCycles: %d\n", __func__, st_vars->DPPCycles);
+       dml_print("DML::%s: DPPCycles: %d\n", __func__, DPPCycles);
        dml_print("DML::%s: PixelClock: %f\n", __func__, myPipe->PixelClock);
        dml_print("DML::%s: Dppclk: %f\n", __func__, myPipe->Dppclk);
-       dml_print("DML::%s: DISPCLKCycles: %d\n", __func__, st_vars->DISPCLKCycles);
+       dml_print("DML::%s: DISPCLKCycles: %d\n", __func__, DISPCLKCycles);
        dml_print("DML::%s: DISPCLK: %f\n", __func__,  myPipe->Dispclk);
        dml_print("DML::%s: DSCDelay: %d\n", __func__,  DSCDelay);
        dml_print("DML::%s: ODMMode: %d\n", __func__,  myPipe->ODMMode);
@@ -3517,14 +3551,14 @@ bool dml32_CalculatePrefetchSchedule(
        dml_print("DML::%s: DSTXAfterScaler: %d\n", __func__,  *DSTXAfterScaler);
 #endif
 
-       if (OutputFormat == dm_420 || (myPipe->InterlaceEnable && myPipe->ProgressiveToInterlaceUnitInOPP))
+       if (v->OutputFormat[k] == dm_420 || (myPipe->InterlaceEnable && myPipe->ProgressiveToInterlaceUnitInOPP))
                *DSTYAfterScaler = 1;
        else
                *DSTYAfterScaler = 0;
 
-       st_vars->DSTTotalPixelsAfterScaler = *DSTYAfterScaler * myPipe->HTotal + *DSTXAfterScaler;
-       *DSTYAfterScaler = dml_floor(st_vars->DSTTotalPixelsAfterScaler / myPipe->HTotal, 1);
-       *DSTXAfterScaler = st_vars->DSTTotalPixelsAfterScaler - ((double) (*DSTYAfterScaler * myPipe->HTotal));
+       DSTTotalPixelsAfterScaler = *DSTYAfterScaler * myPipe->HTotal + *DSTXAfterScaler;
+       *DSTYAfterScaler = dml_floor(DSTTotalPixelsAfterScaler / myPipe->HTotal, 1);
+       *DSTXAfterScaler = DSTTotalPixelsAfterScaler - ((double) (*DSTYAfterScaler * myPipe->HTotal));
 #ifdef __DML_VBA_DEBUG__
        dml_print("DML::%s: DSTXAfterScaler: %d (final)\n", __func__,  *DSTXAfterScaler);
        dml_print("DML::%s: DSTYAfterScaler: %d (final)\n", __func__, *DSTYAfterScaler);
@@ -3532,132 +3566,132 @@ bool dml32_CalculatePrefetchSchedule(
 
        MyError = false;
 
-       st_vars->Tr0_trips = st_vars->trip_to_mem * (st_vars->HostVMDynamicLevelsTrips + 1);
-
-       if (GPUVMEnable == true) {
-               st_vars->Tvm_trips_rounded = dml_ceil(4.0 * st_vars->Tvm_trips / st_vars->LineTime, 1.0) / 4.0 * st_vars->LineTime;
-               st_vars->Tr0_trips_rounded = dml_ceil(4.0 * st_vars->Tr0_trips / st_vars->LineTime, 1.0) / 4.0 * st_vars->LineTime;
-               if (GPUVMPageTableLevels >= 3) {
-                       *Tno_bw = UrgentExtraLatency + st_vars->trip_to_mem *
-                                       (double) ((GPUVMPageTableLevels - 2) * (st_vars->HostVMDynamicLevelsTrips + 1) - 1);
-               } else if (GPUVMPageTableLevels == 1 && myPipe->DCCEnable != true) {
-                       st_vars->Tr0_trips_rounded = dml_ceil(4.0 * UrgentExtraLatency / st_vars->LineTime, 1.0) /
-                                       4.0 * st_vars->LineTime; // VBA_ERROR
+       Tr0_trips = trip_to_mem * (HostVMDynamicLevelsTrips + 1);
+
+       if (v->GPUVMEnable == true) {
+               Tvm_trips_rounded = dml_ceil(4.0 * Tvm_trips / LineTime, 1.0) / 4.0 * LineTime;
+               Tr0_trips_rounded = dml_ceil(4.0 * Tr0_trips / LineTime, 1.0) / 4.0 * LineTime;
+               if (v->GPUVMMaxPageTableLevels >= 3) {
+                       *Tno_bw = UrgentExtraLatency + trip_to_mem *
+                                       (double) ((v->GPUVMMaxPageTableLevels - 2) * (HostVMDynamicLevelsTrips + 1) - 1);
+               } else if (v->GPUVMMaxPageTableLevels == 1 && myPipe->DCCEnable != true) {
+                       Tr0_trips_rounded = dml_ceil(4.0 * UrgentExtraLatency / LineTime, 1.0) /
+                                       4.0 * LineTime; // VBA_ERROR
                        *Tno_bw = UrgentExtraLatency;
                } else {
                        *Tno_bw = 0;
                }
        } else if (myPipe->DCCEnable == true) {
-               st_vars->Tvm_trips_rounded = st_vars->LineTime / 4.0;
-               st_vars->Tr0_trips_rounded = dml_ceil(4.0 * st_vars->Tr0_trips / st_vars->LineTime, 1.0) / 4.0 * st_vars->LineTime;
+               Tvm_trips_rounded = LineTime / 4.0;
+               Tr0_trips_rounded = dml_ceil(4.0 * Tr0_trips / LineTime, 1.0) / 4.0 * LineTime;
                *Tno_bw = 0;
        } else {
-               st_vars->Tvm_trips_rounded = st_vars->LineTime / 4.0;
-               st_vars->Tr0_trips_rounded = st_vars->LineTime / 2.0;
+               Tvm_trips_rounded = LineTime / 4.0;
+               Tr0_trips_rounded = LineTime / 2.0;
                *Tno_bw = 0;
        }
-       st_vars->Tvm_trips_rounded = dml_max(st_vars->Tvm_trips_rounded, st_vars->LineTime / 4.0);
-       st_vars->Tr0_trips_rounded = dml_max(st_vars->Tr0_trips_rounded, st_vars->LineTime / 4.0);
+       Tvm_trips_rounded = dml_max(Tvm_trips_rounded, LineTime / 4.0);
+       Tr0_trips_rounded = dml_max(Tr0_trips_rounded, LineTime / 4.0);
 
        if (myPipe->SourcePixelFormat == dm_420_8 || myPipe->SourcePixelFormat == dm_420_10
                        || myPipe->SourcePixelFormat == dm_420_12) {
-               st_vars->bytes_pp = myPipe->BytePerPixelY + myPipe->BytePerPixelC / 4;
+               bytes_pp = myPipe->BytePerPixelY + myPipe->BytePerPixelC / 4;
        } else {
-               st_vars->bytes_pp = myPipe->BytePerPixelY + myPipe->BytePerPixelC;
+               bytes_pp = myPipe->BytePerPixelY + myPipe->BytePerPixelC;
        }
 
-       st_vars->prefetch_sw_bytes = PrefetchSourceLinesY * swath_width_luma_ub * myPipe->BytePerPixelY
+       prefetch_sw_bytes = PrefetchSourceLinesY * swath_width_luma_ub * myPipe->BytePerPixelY
                        + PrefetchSourceLinesC * swath_width_chroma_ub * myPipe->BytePerPixelC;
-       st_vars->prefetch_bw_oto = dml_max(st_vars->bytes_pp * myPipe->PixelClock / myPipe->DPPPerSurface,
-                       st_vars->prefetch_sw_bytes / (dml_max(PrefetchSourceLinesY, PrefetchSourceLinesC) * st_vars->LineTime));
-
-       st_vars->min_Lsw = dml_max(PrefetchSourceLinesY, PrefetchSourceLinesC) / st_vars->max_vratio_pre;
-       st_vars->min_Lsw = dml_max(st_vars->min_Lsw, 1.0);
-       st_vars->Lsw_oto = dml_ceil(4.0 * dml_max(st_vars->prefetch_sw_bytes / st_vars->prefetch_bw_oto / st_vars->LineTime, st_vars->min_Lsw), 1.0) / 4.0;
-
-       if (GPUVMEnable == true) {
-               st_vars->Tvm_oto = dml_max3(
-                               st_vars->Tvm_trips,
-                               *Tno_bw + PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / st_vars->prefetch_bw_oto,
-                               st_vars->LineTime / 4.0);
+       prefetch_bw_oto = dml_max(bytes_pp * myPipe->PixelClock / myPipe->DPPPerSurface,
+                       prefetch_sw_bytes / (dml_max(PrefetchSourceLinesY, PrefetchSourceLinesC) * LineTime));
+
+       min_Lsw = dml_max(PrefetchSourceLinesY, PrefetchSourceLinesC) / max_vratio_pre;
+       min_Lsw = dml_max(min_Lsw, 1.0);
+       Lsw_oto = dml_ceil(4.0 * dml_max(prefetch_sw_bytes / prefetch_bw_oto / LineTime, min_Lsw), 1.0) / 4.0;
+
+       if (v->GPUVMEnable == true) {
+               Tvm_oto = dml_max3(
+                               Tvm_trips,
+                               *Tno_bw + PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / prefetch_bw_oto,
+                               LineTime / 4.0);
        } else
-               st_vars->Tvm_oto = st_vars->LineTime / 4.0;
-
-       if ((GPUVMEnable == true || myPipe->DCCEnable == true)) {
-               st_vars->Tr0_oto = dml_max4(
-                               st_vars->Tr0_trips,
-                               (MetaRowByte + PixelPTEBytesPerRow * HostVMInefficiencyFactor) / st_vars->prefetch_bw_oto,
-                               (st_vars->LineTime - st_vars->Tvm_oto)/2.0,
-                               st_vars->LineTime / 4.0);
+               Tvm_oto = LineTime / 4.0;
+
+       if ((v->GPUVMEnable == true || myPipe->DCCEnable == true)) {
+               Tr0_oto = dml_max4(
+                               Tr0_trips,
+                               (MetaRowByte + PixelPTEBytesPerRow * HostVMInefficiencyFactor) / prefetch_bw_oto,
+                               (LineTime - Tvm_oto)/2.0,
+                               LineTime / 4.0);
 #ifdef __DML_VBA_DEBUG__
                dml_print("DML::%s: Tr0_oto max0 = %f\n", __func__,
-                               (MetaRowByte + PixelPTEBytesPerRow * HostVMInefficiencyFactor) / st_vars->prefetch_bw_oto);
-               dml_print("DML::%s: Tr0_oto max1 = %f\n", __func__, st_vars->Tr0_trips);
-               dml_print("DML::%s: Tr0_oto max2 = %f\n", __func__, st_vars->LineTime - st_vars->Tvm_oto);
-               dml_print("DML::%s: Tr0_oto max3 = %f\n", __func__, st_vars->LineTime / 4);
+                               (MetaRowByte + PixelPTEBytesPerRow * HostVMInefficiencyFactor) / prefetch_bw_oto);
+               dml_print("DML::%s: Tr0_oto max1 = %f\n", __func__, Tr0_trips);
+               dml_print("DML::%s: Tr0_oto max2 = %f\n", __func__, LineTime - Tvm_oto);
+               dml_print("DML::%s: Tr0_oto max3 = %f\n", __func__, LineTime / 4);
 #endif
        } else
-               st_vars->Tr0_oto = (st_vars->LineTime - st_vars->Tvm_oto) / 2.0;
+               Tr0_oto = (LineTime - Tvm_oto) / 2.0;
 
-       st_vars->Tvm_oto_lines = dml_ceil(4.0 * st_vars->Tvm_oto / st_vars->LineTime, 1) / 4.0;
-       st_vars->Tr0_oto_lines = dml_ceil(4.0 * st_vars->Tr0_oto / st_vars->LineTime, 1) / 4.0;
-       st_vars->dst_y_prefetch_oto = st_vars->Tvm_oto_lines + 2 * st_vars->Tr0_oto_lines + st_vars->Lsw_oto;
+       Tvm_oto_lines = dml_ceil(4.0 * Tvm_oto / LineTime, 1) / 4.0;
+       Tr0_oto_lines = dml_ceil(4.0 * Tr0_oto / LineTime, 1) / 4.0;
+       dst_y_prefetch_oto = Tvm_oto_lines + 2 * Tr0_oto_lines + Lsw_oto;
 
-       st_vars->dst_y_prefetch_equ = VStartup - (*TSetup + dml_max(TWait + TCalc, *Tdmdl)) / st_vars->LineTime -
+       dst_y_prefetch_equ = VStartup - (*TSetup + dml_max(TWait + TCalc, *Tdmdl)) / LineTime -
                        (*DSTYAfterScaler + (double) *DSTXAfterScaler / (double) myPipe->HTotal);
 
 #ifdef __DML_VBA_DEBUG__
        dml_print("DML::%s: HTotal = %d\n", __func__, myPipe->HTotal);
-       dml_print("DML::%s: min_Lsw = %f\n", __func__, st_vars->min_Lsw);
+       dml_print("DML::%s: min_Lsw = %f\n", __func__, min_Lsw);
        dml_print("DML::%s: *Tno_bw = %f\n", __func__, *Tno_bw);
        dml_print("DML::%s: UrgentExtraLatency = %f\n", __func__, UrgentExtraLatency);
-       dml_print("DML::%s: trip_to_mem = %f\n", __func__, st_vars->trip_to_mem);
+       dml_print("DML::%s: trip_to_mem = %f\n", __func__, trip_to_mem);
        dml_print("DML::%s: BytePerPixelY = %d\n", __func__, myPipe->BytePerPixelY);
        dml_print("DML::%s: PrefetchSourceLinesY = %f\n", __func__, PrefetchSourceLinesY);
        dml_print("DML::%s: swath_width_luma_ub = %d\n", __func__, swath_width_luma_ub);
        dml_print("DML::%s: BytePerPixelC = %d\n", __func__, myPipe->BytePerPixelC);
        dml_print("DML::%s: PrefetchSourceLinesC = %f\n", __func__, PrefetchSourceLinesC);
        dml_print("DML::%s: swath_width_chroma_ub = %d\n", __func__, swath_width_chroma_ub);
-       dml_print("DML::%s: prefetch_sw_bytes = %f\n", __func__, st_vars->prefetch_sw_bytes);
-       dml_print("DML::%s: bytes_pp = %f\n", __func__, st_vars->bytes_pp);
+       dml_print("DML::%s: prefetch_sw_bytes = %f\n", __func__, prefetch_sw_bytes);
+       dml_print("DML::%s: bytes_pp = %f\n", __func__, bytes_pp);
        dml_print("DML::%s: PDEAndMetaPTEBytesFrame = %d\n", __func__, PDEAndMetaPTEBytesFrame);
        dml_print("DML::%s: MetaRowByte = %d\n", __func__, MetaRowByte);
        dml_print("DML::%s: PixelPTEBytesPerRow = %d\n", __func__, PixelPTEBytesPerRow);
        dml_print("DML::%s: HostVMInefficiencyFactor = %f\n", __func__, HostVMInefficiencyFactor);
-       dml_print("DML::%s: Tvm_trips = %f\n", __func__, st_vars->Tvm_trips);
-       dml_print("DML::%s: Tr0_trips = %f\n", __func__, st_vars->Tr0_trips);
-       dml_print("DML::%s: prefetch_bw_oto = %f\n", __func__, st_vars->prefetch_bw_oto);
-       dml_print("DML::%s: Tr0_oto = %f\n", __func__, st_vars->Tr0_oto);
-       dml_print("DML::%s: Tvm_oto = %f\n", __func__, st_vars->Tvm_oto);
-       dml_print("DML::%s: Tvm_oto_lines = %f\n", __func__, st_vars->Tvm_oto_lines);
-       dml_print("DML::%s: Tr0_oto_lines = %f\n", __func__, st_vars->Tr0_oto_lines);
-       dml_print("DML::%s: Lsw_oto = %f\n", __func__, st_vars->Lsw_oto);
-       dml_print("DML::%s: dst_y_prefetch_oto = %f\n", __func__, st_vars->dst_y_prefetch_oto);
-       dml_print("DML::%s: dst_y_prefetch_equ = %f\n", __func__, st_vars->dst_y_prefetch_equ);
+       dml_print("DML::%s: Tvm_trips = %f\n", __func__, Tvm_trips);
+       dml_print("DML::%s: Tr0_trips = %f\n", __func__, Tr0_trips);
+       dml_print("DML::%s: prefetch_bw_oto = %f\n", __func__, prefetch_bw_oto);
+       dml_print("DML::%s: Tr0_oto = %f\n", __func__, Tr0_oto);
+       dml_print("DML::%s: Tvm_oto = %f\n", __func__, Tvm_oto);
+       dml_print("DML::%s: Tvm_oto_lines = %f\n", __func__, Tvm_oto_lines);
+       dml_print("DML::%s: Tr0_oto_lines = %f\n", __func__, Tr0_oto_lines);
+       dml_print("DML::%s: Lsw_oto = %f\n", __func__, Lsw_oto);
+       dml_print("DML::%s: dst_y_prefetch_oto = %f\n", __func__, dst_y_prefetch_oto);
+       dml_print("DML::%s: dst_y_prefetch_equ = %f\n", __func__, dst_y_prefetch_equ);
 #endif
 
-       st_vars->dst_y_prefetch_equ = dml_floor(4.0 * (st_vars->dst_y_prefetch_equ + 0.125), 1) / 4.0;
-       st_vars->Tpre_rounded = st_vars->dst_y_prefetch_equ * st_vars->LineTime;
+       dst_y_prefetch_equ = dml_floor(4.0 * (dst_y_prefetch_equ + 0.125), 1) / 4.0;
+       Tpre_rounded = dst_y_prefetch_equ * LineTime;
 #ifdef __DML_VBA_DEBUG__
-       dml_print("DML::%s: dst_y_prefetch_equ: %f (after round)\n", __func__, st_vars->dst_y_prefetch_equ);
-       dml_print("DML::%s: LineTime: %f\n", __func__, st_vars->LineTime);
+       dml_print("DML::%s: dst_y_prefetch_equ: %f (after round)\n", __func__, dst_y_prefetch_equ);
+       dml_print("DML::%s: LineTime: %f\n", __func__, LineTime);
        dml_print("DML::%s: VStartup: %d\n", __func__, VStartup);
        dml_print("DML::%s: Tvstartup: %fus - time between vstartup and first pixel of active\n",
-                       __func__, VStartup * st_vars->LineTime);
+                       __func__, VStartup * LineTime);
        dml_print("DML::%s: TSetup: %fus - time from vstartup to vready\n", __func__, *TSetup);
        dml_print("DML::%s: TCalc: %fus - time for calculations in dchub starting at vready\n", __func__, TCalc);
-       dml_print("DML::%s: Tdmbf: %fus - time for dmd transfer from dchub to dio output buffer\n", __func__, st_vars->Tdmbf);
-       dml_print("DML::%s: Tdmec: %fus - time dio takes to transfer dmd\n", __func__, st_vars->Tdmec);
+       dml_print("DML::%s: Tdmbf: %fus - time for dmd transfer from dchub to dio output buffer\n", __func__, Tdmbf);
+       dml_print("DML::%s: Tdmec: %fus - time dio takes to transfer dmd\n", __func__, Tdmec);
        dml_print("DML::%s: Tdmdl_vm: %fus - time for vm stages of dmd\n", __func__, *Tdmdl_vm);
        dml_print("DML::%s: Tdmdl: %fus - time for fabric to become ready and fetch dmd\n", __func__, *Tdmdl);
        dml_print("DML::%s: DSTYAfterScaler: %d lines - number of lines of pipeline and buffer delay after scaler\n",
                        __func__, *DSTYAfterScaler);
 #endif
-       st_vars->dep_bytes = dml_max(PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor,
+       dep_bytes = dml_max(PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor,
                        MetaRowByte + PixelPTEBytesPerRow * HostVMInefficiencyFactor);
 
-       if (st_vars->prefetch_sw_bytes < st_vars->dep_bytes)
-               st_vars->prefetch_sw_bytes = 2 * st_vars->dep_bytes;
+       if (prefetch_sw_bytes < dep_bytes)
+               prefetch_sw_bytes = 2 * dep_bytes;
 
        *PrefetchBandwidth = 0;
        *DestinationLinesToRequestVMInVBlank = 0;
@@ -3665,61 +3699,61 @@ bool dml32_CalculatePrefetchSchedule(
        *VRatioPrefetchY = 0;
        *VRatioPrefetchC = 0;
        *RequiredPrefetchPixDataBWLuma = 0;
-       if (st_vars->dst_y_prefetch_equ > 1) {
+       if (dst_y_prefetch_equ > 1) {
                double PrefetchBandwidth1;
                double PrefetchBandwidth2;
                double PrefetchBandwidth3;
                double PrefetchBandwidth4;
 
-               if (st_vars->Tpre_rounded - *Tno_bw > 0) {
+               if (Tpre_rounded - *Tno_bw > 0) {
                        PrefetchBandwidth1 = (PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor + 2 * MetaRowByte
                                        + 2 * PixelPTEBytesPerRow * HostVMInefficiencyFactor
-                                       + st_vars->prefetch_sw_bytes) / (st_vars->Tpre_rounded - *Tno_bw);
-                       st_vars->Tsw_est1 = st_vars->prefetch_sw_bytes / PrefetchBandwidth1;
+                                       + prefetch_sw_bytes) / (Tpre_rounded - *Tno_bw);
+                       Tsw_est1 = prefetch_sw_bytes / PrefetchBandwidth1;
                } else
                        PrefetchBandwidth1 = 0;
 
-               if (VStartup == MaxVStartup && (st_vars->Tsw_est1 / st_vars->LineTime < st_vars->min_Lsw)
-                               && st_vars->Tpre_rounded - st_vars->min_Lsw * st_vars->LineTime - 0.75 * st_vars->LineTime - *Tno_bw > 0) {
+               if (VStartup == MaxVStartup && (Tsw_est1 / LineTime < min_Lsw)
+                               && Tpre_rounded - min_Lsw * LineTime - 0.75 * LineTime - *Tno_bw > 0) {
                        PrefetchBandwidth1 = (PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor + 2 * MetaRowByte
                                        + 2 * PixelPTEBytesPerRow * HostVMInefficiencyFactor)
-                                       / (st_vars->Tpre_rounded - st_vars->min_Lsw * st_vars->LineTime - 0.75 * st_vars->LineTime - *Tno_bw);
+                                       / (Tpre_rounded - min_Lsw * LineTime - 0.75 * LineTime - *Tno_bw);
                }
 
-               if (st_vars->Tpre_rounded - *Tno_bw - 2 * st_vars->Tr0_trips_rounded > 0)
-                       PrefetchBandwidth2 = (PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor + st_vars->prefetch_sw_bytes) /
-                       (st_vars->Tpre_rounded - *Tno_bw - 2 * st_vars->Tr0_trips_rounded);
+               if (Tpre_rounded - *Tno_bw - 2 * Tr0_trips_rounded > 0)
+                       PrefetchBandwidth2 = (PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor + prefetch_sw_bytes) /
+                       (Tpre_rounded - *Tno_bw - 2 * Tr0_trips_rounded);
                else
                        PrefetchBandwidth2 = 0;
 
-               if (st_vars->Tpre_rounded - st_vars->Tvm_trips_rounded > 0) {
+               if (Tpre_rounded - Tvm_trips_rounded > 0) {
                        PrefetchBandwidth3 = (2 * MetaRowByte + 2 * PixelPTEBytesPerRow * HostVMInefficiencyFactor
-                                       + st_vars->prefetch_sw_bytes) / (st_vars->Tpre_rounded - st_vars->Tvm_trips_rounded);
-                       st_vars->Tsw_est3 = st_vars->prefetch_sw_bytes / PrefetchBandwidth3;
+                                       + prefetch_sw_bytes) / (Tpre_rounded - Tvm_trips_rounded);
+                       Tsw_est3 = prefetch_sw_bytes / PrefetchBandwidth3;
                } else
                        PrefetchBandwidth3 = 0;
 
 
                if (VStartup == MaxVStartup &&
-                               (st_vars->Tsw_est3 / st_vars->LineTime < st_vars->min_Lsw) && st_vars->Tpre_rounded - st_vars->min_Lsw * st_vars->LineTime - 0.75 *
-                               st_vars->LineTime - st_vars->Tvm_trips_rounded > 0) {
+                               (Tsw_est3 / LineTime < min_Lsw) && Tpre_rounded - min_Lsw * LineTime - 0.75 *
+                               LineTime - Tvm_trips_rounded > 0) {
                        PrefetchBandwidth3 = (2 * MetaRowByte + 2 * PixelPTEBytesPerRow * HostVMInefficiencyFactor)
-                                       / (st_vars->Tpre_rounded - st_vars->min_Lsw * st_vars->LineTime - 0.75 * st_vars->LineTime - st_vars->Tvm_trips_rounded);
+                                       / (Tpre_rounded - min_Lsw * LineTime - 0.75 * LineTime - Tvm_trips_rounded);
                }
 
-               if (st_vars->Tpre_rounded - st_vars->Tvm_trips_rounded - 2 * st_vars->Tr0_trips_rounded > 0) {
-                       PrefetchBandwidth4 = st_vars->prefetch_sw_bytes /
-                                       (st_vars->Tpre_rounded - st_vars->Tvm_trips_rounded - 2 * st_vars->Tr0_trips_rounded);
+               if (Tpre_rounded - Tvm_trips_rounded - 2 * Tr0_trips_rounded > 0) {
+                       PrefetchBandwidth4 = prefetch_sw_bytes /
+                                       (Tpre_rounded - Tvm_trips_rounded - 2 * Tr0_trips_rounded);
                } else {
                        PrefetchBandwidth4 = 0;
                }
 
 #ifdef __DML_VBA_DEBUG__
-               dml_print("DML::%s: Tpre_rounded: %f\n", __func__, st_vars->Tpre_rounded);
+               dml_print("DML::%s: Tpre_rounded: %f\n", __func__, Tpre_rounded);
                dml_print("DML::%s: Tno_bw: %f\n", __func__, *Tno_bw);
-               dml_print("DML::%s: Tvm_trips_rounded: %f\n", __func__, st_vars->Tvm_trips_rounded);
-               dml_print("DML::%s: Tsw_est1: %f\n", __func__, st_vars->Tsw_est1);
-               dml_print("DML::%s: Tsw_est3: %f\n", __func__, st_vars->Tsw_est3);
+               dml_print("DML::%s: Tvm_trips_rounded: %f\n", __func__, Tvm_trips_rounded);
+               dml_print("DML::%s: Tsw_est1: %f\n", __func__, Tsw_est1);
+               dml_print("DML::%s: Tsw_est3: %f\n", __func__, Tsw_est3);
                dml_print("DML::%s: PrefetchBandwidth1: %f\n", __func__, PrefetchBandwidth1);
                dml_print("DML::%s: PrefetchBandwidth2: %f\n", __func__, PrefetchBandwidth2);
                dml_print("DML::%s: PrefetchBandwidth3: %f\n", __func__, PrefetchBandwidth3);
@@ -3732,9 +3766,9 @@ bool dml32_CalculatePrefetchSchedule(
 
                        if (PrefetchBandwidth1 > 0) {
                                if (*Tno_bw + PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / PrefetchBandwidth1
-                                               >= st_vars->Tvm_trips_rounded
+                                               >= Tvm_trips_rounded
                                                && (MetaRowByte + PixelPTEBytesPerRow * HostVMInefficiencyFactor)
-                                                               / PrefetchBandwidth1 >= st_vars->Tr0_trips_rounded) {
+                                                               / PrefetchBandwidth1 >= Tr0_trips_rounded) {
                                        Case1OK = true;
                                } else {
                                        Case1OK = false;
@@ -3745,9 +3779,9 @@ bool dml32_CalculatePrefetchSchedule(
 
                        if (PrefetchBandwidth2 > 0) {
                                if (*Tno_bw + PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / PrefetchBandwidth2
-                                               >= st_vars->Tvm_trips_rounded
+                                               >= Tvm_trips_rounded
                                                && (MetaRowByte + PixelPTEBytesPerRow * HostVMInefficiencyFactor)
-                                               / PrefetchBandwidth2 < st_vars->Tr0_trips_rounded) {
+                                               / PrefetchBandwidth2 < Tr0_trips_rounded) {
                                        Case2OK = true;
                                } else {
                                        Case2OK = false;
@@ -3758,9 +3792,9 @@ bool dml32_CalculatePrefetchSchedule(
 
                        if (PrefetchBandwidth3 > 0) {
                                if (*Tno_bw + PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / PrefetchBandwidth3 <
-                                               st_vars->Tvm_trips_rounded && (MetaRowByte + PixelPTEBytesPerRow *
+                                               Tvm_trips_rounded && (MetaRowByte + PixelPTEBytesPerRow *
                                                                HostVMInefficiencyFactor) / PrefetchBandwidth3 >=
-                                                               st_vars->Tr0_trips_rounded) {
+                                                               Tr0_trips_rounded) {
                                        Case3OK = true;
                                } else {
                                        Case3OK = false;
@@ -3770,80 +3804,80 @@ bool dml32_CalculatePrefetchSchedule(
                        }
 
                        if (Case1OK)
-                               st_vars->prefetch_bw_equ = PrefetchBandwidth1;
+                               prefetch_bw_equ = PrefetchBandwidth1;
                        else if (Case2OK)
-                               st_vars->prefetch_bw_equ = PrefetchBandwidth2;
+                               prefetch_bw_equ = PrefetchBandwidth2;
                        else if (Case3OK)
-                               st_vars->prefetch_bw_equ = PrefetchBandwidth3;
+                               prefetch_bw_equ = PrefetchBandwidth3;
                        else
-                               st_vars->prefetch_bw_equ = PrefetchBandwidth4;
+                               prefetch_bw_equ = PrefetchBandwidth4;
 
 #ifdef __DML_VBA_DEBUG__
                        dml_print("DML::%s: Case1OK: %d\n", __func__, Case1OK);
                        dml_print("DML::%s: Case2OK: %d\n", __func__, Case2OK);
                        dml_print("DML::%s: Case3OK: %d\n", __func__, Case3OK);
-                       dml_print("DML::%s: prefetch_bw_equ: %f\n", __func__, st_vars->prefetch_bw_equ);
+                       dml_print("DML::%s: prefetch_bw_equ: %f\n", __func__, prefetch_bw_equ);
 #endif
 
-                       if (st_vars->prefetch_bw_equ > 0) {
-                               if (GPUVMEnable == true) {
-                                       st_vars->Tvm_equ = dml_max3(*Tno_bw + PDEAndMetaPTEBytesFrame *
-                                                       HostVMInefficiencyFactor / st_vars->prefetch_bw_equ,
-                                                       st_vars->Tvm_trips, st_vars->LineTime / 4);
+                       if (prefetch_bw_equ > 0) {
+                               if (v->GPUVMEnable == true) {
+                                       Tvm_equ = dml_max3(*Tno_bw + PDEAndMetaPTEBytesFrame *
+                                                       HostVMInefficiencyFactor / prefetch_bw_equ,
+                                                       Tvm_trips, LineTime / 4);
                                } else {
-                                       st_vars->Tvm_equ = st_vars->LineTime / 4;
+                                       Tvm_equ = LineTime / 4;
                                }
 
-                               if ((GPUVMEnable == true || myPipe->DCCEnable == true)) {
-                                       st_vars->Tr0_equ = dml_max4((MetaRowByte + PixelPTEBytesPerRow *
-                                                       HostVMInefficiencyFactor) / st_vars->prefetch_bw_equ, st_vars->Tr0_trips,
-                                                       (st_vars->LineTime - st_vars->Tvm_equ) / 2, st_vars->LineTime / 4);
+                               if ((v->GPUVMEnable == true || myPipe->DCCEnable == true)) {
+                                       Tr0_equ = dml_max4((MetaRowByte + PixelPTEBytesPerRow *
+                                                       HostVMInefficiencyFactor) / prefetch_bw_equ, Tr0_trips,
+                                                       (LineTime - Tvm_equ) / 2, LineTime / 4);
                                } else {
-                                       st_vars->Tr0_equ = (st_vars->LineTime - st_vars->Tvm_equ) / 2;
+                                       Tr0_equ = (LineTime - Tvm_equ) / 2;
                                }
                        } else {
-                               st_vars->Tvm_equ = 0;
-                               st_vars->Tr0_equ = 0;
+                               Tvm_equ = 0;
+                               Tr0_equ = 0;
 #ifdef __DML_VBA_DEBUG__
                                dml_print("DML: prefetch_bw_equ equals 0! %s:%d\n", __FILE__, __LINE__);
 #endif
                        }
                }
 
-               if (st_vars->dst_y_prefetch_oto < st_vars->dst_y_prefetch_equ) {
-                       *DestinationLinesForPrefetch = st_vars->dst_y_prefetch_oto;
-                       st_vars->TimeForFetchingMetaPTE = st_vars->Tvm_oto;
-                       st_vars->TimeForFetchingRowInVBlank = st_vars->Tr0_oto;
-                       *PrefetchBandwidth = st_vars->prefetch_bw_oto;
+               if (dst_y_prefetch_oto < dst_y_prefetch_equ) {
+                       *DestinationLinesForPrefetch = dst_y_prefetch_oto;
+                       TimeForFetchingMetaPTE = Tvm_oto;
+                       TimeForFetchingRowInVBlank = Tr0_oto;
+                       *PrefetchBandwidth = prefetch_bw_oto;
                } else {
-                       *DestinationLinesForPrefetch = st_vars->dst_y_prefetch_equ;
-                       st_vars->TimeForFetchingMetaPTE = st_vars->Tvm_equ;
-                       st_vars->TimeForFetchingRowInVBlank = st_vars->Tr0_equ;
-                       *PrefetchBandwidth = st_vars->prefetch_bw_equ;
+                       *DestinationLinesForPrefetch = dst_y_prefetch_equ;
+                       TimeForFetchingMetaPTE = Tvm_equ;
+                       TimeForFetchingRowInVBlank = Tr0_equ;
+                       *PrefetchBandwidth = prefetch_bw_equ;
                }
 
-               *DestinationLinesToRequestVMInVBlank = dml_ceil(4.0 * st_vars->TimeForFetchingMetaPTE / st_vars->LineTime, 1.0) / 4.0;
+               *DestinationLinesToRequestVMInVBlank = dml_ceil(4.0 * TimeForFetchingMetaPTE / LineTime, 1.0) / 4.0;
 
                *DestinationLinesToRequestRowInVBlank =
-                               dml_ceil(4.0 * st_vars->TimeForFetchingRowInVBlank / st_vars->LineTime, 1.0) / 4.0;
+                               dml_ceil(4.0 * TimeForFetchingRowInVBlank / LineTime, 1.0) / 4.0;
 
-               st_vars->LinesToRequestPrefetchPixelData = *DestinationLinesForPrefetch -
+               LinesToRequestPrefetchPixelData = *DestinationLinesForPrefetch -
                                *DestinationLinesToRequestVMInVBlank - 2 * *DestinationLinesToRequestRowInVBlank;
 
 #ifdef __DML_VBA_DEBUG__
                dml_print("DML::%s: DestinationLinesForPrefetch = %f\n", __func__, *DestinationLinesForPrefetch);
                dml_print("DML::%s: DestinationLinesToRequestVMInVBlank = %f\n",
                                __func__, *DestinationLinesToRequestVMInVBlank);
-               dml_print("DML::%s: TimeForFetchingRowInVBlank = %f\n", __func__, st_vars->TimeForFetchingRowInVBlank);
-               dml_print("DML::%s: LineTime = %f\n", __func__, st_vars->LineTime);
+               dml_print("DML::%s: TimeForFetchingRowInVBlank = %f\n", __func__, TimeForFetchingRowInVBlank);
+               dml_print("DML::%s: LineTime = %f\n", __func__, LineTime);
                dml_print("DML::%s: DestinationLinesToRequestRowInVBlank = %f\n",
                                __func__, *DestinationLinesToRequestRowInVBlank);
                dml_print("DML::%s: PrefetchSourceLinesY = %f\n", __func__, PrefetchSourceLinesY);
-               dml_print("DML::%s: LinesToRequestPrefetchPixelData = %f\n", __func__, st_vars->LinesToRequestPrefetchPixelData);
+               dml_print("DML::%s: LinesToRequestPrefetchPixelData = %f\n", __func__, LinesToRequestPrefetchPixelData);
 #endif
 
-               if (st_vars->LinesToRequestPrefetchPixelData >= 1 && st_vars->prefetch_bw_equ > 0) {
-                       *VRatioPrefetchY = (double) PrefetchSourceLinesY / st_vars->LinesToRequestPrefetchPixelData;
+               if (LinesToRequestPrefetchPixelData >= 1 && prefetch_bw_equ > 0) {
+                       *VRatioPrefetchY = (double) PrefetchSourceLinesY / LinesToRequestPrefetchPixelData;
                        *VRatioPrefetchY = dml_max(*VRatioPrefetchY, 1.0);
 #ifdef __DML_VBA_DEBUG__
                        dml_print("DML::%s: VRatioPrefetchY = %f\n", __func__, *VRatioPrefetchY);
@@ -3851,12 +3885,12 @@ bool dml32_CalculatePrefetchSchedule(
                        dml_print("DML::%s: VInitPreFillY = %d\n", __func__, VInitPreFillY);
 #endif
                        if ((SwathHeightY > 4) && (VInitPreFillY > 3)) {
-                               if (st_vars->LinesToRequestPrefetchPixelData > (VInitPreFillY - 3.0) / 2.0) {
+                               if (LinesToRequestPrefetchPixelData > (VInitPreFillY - 3.0) / 2.0) {
                                        *VRatioPrefetchY =
                                                        dml_max((double) PrefetchSourceLinesY /
-                                                                       st_vars->LinesToRequestPrefetchPixelData,
+                                                                       LinesToRequestPrefetchPixelData,
                                                                        (double) MaxNumSwathY * SwathHeightY /
-                                                                       (st_vars->LinesToRequestPrefetchPixelData -
+                                                                       (LinesToRequestPrefetchPixelData -
                                                                        (VInitPreFillY - 3.0) / 2.0));
                                        *VRatioPrefetchY = dml_max(*VRatioPrefetchY, 1.0);
                                } else {
@@ -3870,7 +3904,7 @@ bool dml32_CalculatePrefetchSchedule(
 #endif
                        }
 
-                       *VRatioPrefetchC = (double) PrefetchSourceLinesC / st_vars->LinesToRequestPrefetchPixelData;
+                       *VRatioPrefetchC = (double) PrefetchSourceLinesC / LinesToRequestPrefetchPixelData;
                        *VRatioPrefetchC = dml_max(*VRatioPrefetchC, 1.0);
 
 #ifdef __DML_VBA_DEBUG__
@@ -3879,11 +3913,11 @@ bool dml32_CalculatePrefetchSchedule(
                        dml_print("DML::%s: VInitPreFillC = %d\n", __func__, VInitPreFillC);
 #endif
                        if ((SwathHeightC > 4)) {
-                               if (st_vars->LinesToRequestPrefetchPixelData > (VInitPreFillC - 3.0) / 2.0) {
+                               if (LinesToRequestPrefetchPixelData > (VInitPreFillC - 3.0) / 2.0) {
                                        *VRatioPrefetchC =
                                                dml_max(*VRatioPrefetchC,
                                                        (double) MaxNumSwathC * SwathHeightC /
-                                                       (st_vars->LinesToRequestPrefetchPixelData -
+                                                       (LinesToRequestPrefetchPixelData -
                                                        (VInitPreFillC - 3.0) / 2.0));
                                        *VRatioPrefetchC = dml_max(*VRatioPrefetchC, 1.0);
                                } else {
@@ -3898,25 +3932,25 @@ bool dml32_CalculatePrefetchSchedule(
                        }
 
                        *RequiredPrefetchPixDataBWLuma = (double) PrefetchSourceLinesY
-                                       / st_vars->LinesToRequestPrefetchPixelData * myPipe->BytePerPixelY * swath_width_luma_ub
-                                       / st_vars->LineTime;
+                                       / LinesToRequestPrefetchPixelData * myPipe->BytePerPixelY * swath_width_luma_ub
+                                       / LineTime;
 
 #ifdef __DML_VBA_DEBUG__
                        dml_print("DML::%s: BytePerPixelY = %d\n", __func__, myPipe->BytePerPixelY);
                        dml_print("DML::%s: swath_width_luma_ub = %d\n", __func__, swath_width_luma_ub);
-                       dml_print("DML::%s: LineTime = %f\n", __func__, st_vars->LineTime);
+                       dml_print("DML::%s: LineTime = %f\n", __func__, LineTime);
                        dml_print("DML::%s: RequiredPrefetchPixDataBWLuma = %f\n",
                                        __func__, *RequiredPrefetchPixDataBWLuma);
 #endif
                        *RequiredPrefetchPixDataBWChroma = (double) PrefetchSourceLinesC /
-                                       st_vars->LinesToRequestPrefetchPixelData
+                                       LinesToRequestPrefetchPixelData
                                        * myPipe->BytePerPixelC
-                                       * swath_width_chroma_ub / st_vars->LineTime;
+                                       * swath_width_chroma_ub / LineTime;
                } else {
                        MyError = true;
 #ifdef __DML_VBA_DEBUG__
                        dml_print("DML:%s: MyErr set. LinesToRequestPrefetchPixelData: %f, should be > 0\n",
-                                       __func__, st_vars->LinesToRequestPrefetchPixelData);
+                                       __func__, LinesToRequestPrefetchPixelData);
 #endif
                        *VRatioPrefetchY = 0;
                        *VRatioPrefetchC = 0;
@@ -3925,15 +3959,15 @@ bool dml32_CalculatePrefetchSchedule(
                }
 #ifdef __DML_VBA_DEBUG__
                dml_print("DML: Tpre: %fus - sum of time to request meta pte, 2 x data pte + meta data, swaths\n",
-                       (double)st_vars->LinesToRequestPrefetchPixelData * st_vars->LineTime +
-                       2.0*st_vars->TimeForFetchingRowInVBlank + st_vars->TimeForFetchingMetaPTE);
-               dml_print("DML:  Tvm: %fus - time to fetch page tables for meta surface\n", st_vars->TimeForFetchingMetaPTE);
+                       (double)LinesToRequestPrefetchPixelData * LineTime +
+                       2.0*TimeForFetchingRowInVBlank + TimeForFetchingMetaPTE);
+               dml_print("DML:  Tvm: %fus - time to fetch page tables for meta surface\n", TimeForFetchingMetaPTE);
                dml_print("DML: To: %fus - time for propagation from scaler to optc\n",
-                       (*DSTYAfterScaler + ((double) (*DSTXAfterScaler) / (double) myPipe->HTotal)) * st_vars->LineTime);
+                       (*DSTYAfterScaler + ((double) (*DSTXAfterScaler) / (double) myPipe->HTotal)) * LineTime);
                dml_print("DML: Tvstartup - TSetup - Tcalc - Twait - Tpre - To > 0\n");
-               dml_print("DML: Tslack(pre): %fus - time left over in schedule\n", VStartup * st_vars->LineTime -
-                       st_vars->TimeForFetchingMetaPTE - 2*st_vars->TimeForFetchingRowInVBlank - (*DSTYAfterScaler +
-                       ((double) (*DSTXAfterScaler) / (double) myPipe->HTotal)) * st_vars->LineTime - TWait - TCalc - *TSetup);
+               dml_print("DML: Tslack(pre): %fus - time left over in schedule\n", VStartup * LineTime -
+                       TimeForFetchingMetaPTE - 2*TimeForFetchingRowInVBlank - (*DSTYAfterScaler +
+                       ((double) (*DSTXAfterScaler) / (double) myPipe->HTotal)) * LineTime - TWait - TCalc - *TSetup);
                dml_print("DML: row_bytes = dpte_row_bytes (per_pipe) = PixelPTEBytesPerRow = : %d\n",
                                PixelPTEBytesPerRow);
 #endif
@@ -3941,7 +3975,7 @@ bool dml32_CalculatePrefetchSchedule(
                MyError = true;
 #ifdef __DML_VBA_DEBUG__
                dml_print("DML::%s: MyErr set, dst_y_prefetch_equ = %f (should be > 1)\n",
-                               __func__, st_vars->dst_y_prefetch_equ);
+                               __func__, dst_y_prefetch_equ);
 #endif
        }
 
@@ -3957,10 +3991,10 @@ bool dml32_CalculatePrefetchSchedule(
                        dml_print("DML::%s: HostVMInefficiencyFactor = %f\n", __func__, HostVMInefficiencyFactor);
                        dml_print("DML::%s: DestinationLinesToRequestVMInVBlank = %f\n",
                                        __func__, *DestinationLinesToRequestVMInVBlank);
-                       dml_print("DML::%s: LineTime = %f\n", __func__, st_vars->LineTime);
+                       dml_print("DML::%s: LineTime = %f\n", __func__, LineTime);
 #endif
                        prefetch_vm_bw = PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor /
-                                       (*DestinationLinesToRequestVMInVBlank * st_vars->LineTime);
+                                       (*DestinationLinesToRequestVMInVBlank * LineTime);
 #ifdef __DML_VBA_DEBUG__
                        dml_print("DML::%s: prefetch_vm_bw = %f\n", __func__, prefetch_vm_bw);
 #endif
@@ -3977,7 +4011,7 @@ bool dml32_CalculatePrefetchSchedule(
                        prefetch_row_bw = 0;
                } else if (*DestinationLinesToRequestRowInVBlank > 0) {
                        prefetch_row_bw = (MetaRowByte + PixelPTEBytesPerRow * HostVMInefficiencyFactor) /
-                                       (*DestinationLinesToRequestRowInVBlank * st_vars->LineTime);
+                                       (*DestinationLinesToRequestRowInVBlank * LineTime);
 
 #ifdef __DML_VBA_DEBUG__
                        dml_print("DML::%s: MetaRowByte = %d\n", __func__, MetaRowByte);
@@ -4000,12 +4034,12 @@ bool dml32_CalculatePrefetchSchedule(
 
        if (MyError) {
                *PrefetchBandwidth = 0;
-               st_vars->TimeForFetchingMetaPTE = 0;
-               st_vars->TimeForFetchingRowInVBlank = 0;
+               TimeForFetchingMetaPTE = 0;
+               TimeForFetchingRowInVBlank = 0;
                *DestinationLinesToRequestVMInVBlank = 0;
                *DestinationLinesToRequestRowInVBlank = 0;
                *DestinationLinesForPrefetch = 0;
-               st_vars->LinesToRequestPrefetchPixelData = 0;
+               LinesToRequestPrefetchPixelData = 0;
                *VRatioPrefetchY = 0;
                *VRatioPrefetchC = 0;
                *RequiredPrefetchPixDataBWLuma = 0;
@@ -4159,59 +4193,28 @@ void dml32_CalculateFlipSchedule(
 } // CalculateFlipSchedule
 
 void dml32_CalculateWatermarksMALLUseAndDRAMSpeedChangeSupport(
-               struct dml32_CalculateWatermarksMALLUseAndDRAMSpeedChangeSupport *st_vars,
-               bool USRRetrainingRequiredFinal,
-               enum dm_use_mall_for_pstate_change_mode UseMALLForPStateChange[],
+               struct vba_vars_st *v,
                unsigned int PrefetchMode,
-               unsigned int NumberOfActiveSurfaces,
-               unsigned int MaxLineBufferLines,
-               unsigned int LineBufferSize,
-               unsigned int WritebackInterfaceBufferSize,
                double DCFCLK,
                double ReturnBW,
-               bool SynchronizeTimingsFinal,
-               bool SynchronizeDRRDisplaysForUCLKPStateChangeFinal,
-               bool DRRDisplay[],
-               unsigned int dpte_group_bytes[],
-               unsigned int meta_row_height[],
-               unsigned int meta_row_height_chroma[],
                SOCParametersList mmSOCParameters,
-               unsigned int WritebackChunkSize,
                double SOCCLK,
                double DCFClkDeepSleep,
                unsigned int DETBufferSizeY[],
                unsigned int DETBufferSizeC[],
                unsigned int SwathHeightY[],
                unsigned int SwathHeightC[],
-               unsigned int LBBitPerPixel[],
                double SwathWidthY[],
                double SwathWidthC[],
-               double HRatio[],
-               double HRatioChroma[],
-               unsigned int VTaps[],
-               unsigned int VTapsChroma[],
-               double VRatio[],
-               double VRatioChroma[],
-               unsigned int HTotal[],
-               unsigned int VTotal[],
-               unsigned int VActive[],
-               double PixelClock[],
-               unsigned int BlendingAndTiming[],
                unsigned int DPPPerSurface[],
                double BytePerPixelDETY[],
                double BytePerPixelDETC[],
                double DSTXAfterScaler[],
                double DSTYAfterScaler[],
-               bool WritebackEnable[],
-               enum source_format_class WritebackPixelFormat[],
-               double WritebackDestinationWidth[],
-               double WritebackDestinationHeight[],
-               double WritebackSourceHeight[],
                bool UnboundedRequestEnabled,
                unsigned int CompressedBufferSizeInkByte,
 
                /* Output */
-               Watermarks *Watermark,
                enum clock_change_support *DRAMClockChangeSupport,
                double MaxActiveDRAMClockChangeLatencySupported[],
                unsigned int SubViewportLinesNeededInMALL[],
@@ -4221,229 +4224,251 @@ void dml32_CalculateWatermarksMALLUseAndDRAMSpeedChangeSupport(
                double ActiveDRAMClockChangeLatencyMargin[])
 {
        unsigned int i, j, k;
-
-       st_vars->SurfaceWithMinActiveFCLKChangeMargin = 0;
-       st_vars->DRAMClockChangeSupportNumber = 0;
-       st_vars->DRAMClockChangeMethod = 0;
-       st_vars->FoundFirstSurfaceWithMinActiveFCLKChangeMargin = false;
-       st_vars->MinActiveFCLKChangeMargin = 0.;
-       st_vars->SecondMinActiveFCLKChangeMarginOneDisplayInVBLank = 0.;
-       st_vars->TotalPixelBW = 0.0;
-       st_vars->TotalActiveWriteback = 0;
-
-       Watermark->UrgentWatermark = mmSOCParameters.UrgentLatency + mmSOCParameters.ExtraLatency;
-       Watermark->USRRetrainingWatermark = mmSOCParameters.UrgentLatency + mmSOCParameters.ExtraLatency
+       unsigned int SurfaceWithMinActiveFCLKChangeMargin = 0;
+       unsigned int DRAMClockChangeSupportNumber = 0;
+       unsigned int LastSurfaceWithoutMargin;
+       unsigned int DRAMClockChangeMethod = 0;
+       bool FoundFirstSurfaceWithMinActiveFCLKChangeMargin = false;
+       double MinActiveFCLKChangeMargin = 0.;
+       double SecondMinActiveFCLKChangeMarginOneDisplayInVBLank = 0.;
+       double ActiveClockChangeLatencyHidingY;
+       double ActiveClockChangeLatencyHidingC;
+       double ActiveClockChangeLatencyHiding;
+    double EffectiveDETBufferSizeY;
+       double     ActiveFCLKChangeLatencyMargin[DC__NUM_DPP__MAX];
+       double     USRRetrainingLatencyMargin[DC__NUM_DPP__MAX];
+       double TotalPixelBW = 0.0;
+       bool    SynchronizedSurfaces[DC__NUM_DPP__MAX][DC__NUM_DPP__MAX];
+       double     EffectiveLBLatencyHidingY;
+       double     EffectiveLBLatencyHidingC;
+       double     LinesInDETY[DC__NUM_DPP__MAX];
+       double     LinesInDETC[DC__NUM_DPP__MAX];
+       unsigned int    LinesInDETYRoundedDownToSwath[DC__NUM_DPP__MAX];
+       unsigned int    LinesInDETCRoundedDownToSwath[DC__NUM_DPP__MAX];
+       double     FullDETBufferingTimeY;
+       double     FullDETBufferingTimeC;
+       double     WritebackDRAMClockChangeLatencyMargin;
+       double     WritebackFCLKChangeLatencyMargin;
+       double     WritebackLatencyHiding;
+       bool    SameTimingForFCLKChange;
+
+       unsigned int    TotalActiveWriteback = 0;
+       unsigned int LBLatencyHidingSourceLinesY[DC__NUM_DPP__MAX];
+       unsigned int LBLatencyHidingSourceLinesC[DC__NUM_DPP__MAX];
+
+       v->Watermark.UrgentWatermark = mmSOCParameters.UrgentLatency + mmSOCParameters.ExtraLatency;
+       v->Watermark.USRRetrainingWatermark = mmSOCParameters.UrgentLatency + mmSOCParameters.ExtraLatency
                        + mmSOCParameters.USRRetrainingLatency + mmSOCParameters.SMNLatency;
-       Watermark->DRAMClockChangeWatermark = mmSOCParameters.DRAMClockChangeLatency + Watermark->UrgentWatermark;
-       Watermark->FCLKChangeWatermark = mmSOCParameters.FCLKChangeLatency + Watermark->UrgentWatermark;
-       Watermark->StutterExitWatermark = mmSOCParameters.SRExitTime + mmSOCParameters.ExtraLatency
+       v->Watermark.DRAMClockChangeWatermark = mmSOCParameters.DRAMClockChangeLatency + v->Watermark.UrgentWatermark;
+       v->Watermark.FCLKChangeWatermark = mmSOCParameters.FCLKChangeLatency + v->Watermark.UrgentWatermark;
+       v->Watermark.StutterExitWatermark = mmSOCParameters.SRExitTime + mmSOCParameters.ExtraLatency
                        + 10 / DCFClkDeepSleep;
-       Watermark->StutterEnterPlusExitWatermark = mmSOCParameters.SREnterPlusExitTime + mmSOCParameters.ExtraLatency
+       v->Watermark.StutterEnterPlusExitWatermark = mmSOCParameters.SREnterPlusExitTime + mmSOCParameters.ExtraLatency
                        + 10 / DCFClkDeepSleep;
-       Watermark->Z8StutterExitWatermark = mmSOCParameters.SRExitZ8Time + mmSOCParameters.ExtraLatency
+       v->Watermark.Z8StutterExitWatermark = mmSOCParameters.SRExitZ8Time + mmSOCParameters.ExtraLatency
                        + 10 / DCFClkDeepSleep;
-       Watermark->Z8StutterEnterPlusExitWatermark = mmSOCParameters.SREnterPlusExitZ8Time
+       v->Watermark.Z8StutterEnterPlusExitWatermark = mmSOCParameters.SREnterPlusExitZ8Time
                        + mmSOCParameters.ExtraLatency + 10 / DCFClkDeepSleep;
 
 #ifdef __DML_VBA_DEBUG__
        dml_print("DML::%s: UrgentLatency = %f\n", __func__, mmSOCParameters.UrgentLatency);
        dml_print("DML::%s: ExtraLatency = %f\n", __func__, mmSOCParameters.ExtraLatency);
        dml_print("DML::%s: DRAMClockChangeLatency = %f\n", __func__, mmSOCParameters.DRAMClockChangeLatency);
-       dml_print("DML::%s: UrgentWatermark = %f\n", __func__, Watermark->UrgentWatermark);
-       dml_print("DML::%s: USRRetrainingWatermark = %f\n", __func__, Watermark->USRRetrainingWatermark);
-       dml_print("DML::%s: DRAMClockChangeWatermark = %f\n", __func__, Watermark->DRAMClockChangeWatermark);
-       dml_print("DML::%s: FCLKChangeWatermark = %f\n", __func__, Watermark->FCLKChangeWatermark);
-       dml_print("DML::%s: StutterExitWatermark = %f\n", __func__, Watermark->StutterExitWatermark);
-       dml_print("DML::%s: StutterEnterPlusExitWatermark = %f\n", __func__, Watermark->StutterEnterPlusExitWatermark);
-       dml_print("DML::%s: Z8StutterExitWatermark = %f\n", __func__, Watermark->Z8StutterExitWatermark);
+       dml_print("DML::%s: UrgentWatermark = %f\n", __func__, v->Watermark.UrgentWatermark);
+       dml_print("DML::%s: USRRetrainingWatermark = %f\n", __func__, v->Watermark.USRRetrainingWatermark);
+       dml_print("DML::%s: DRAMClockChangeWatermark = %f\n", __func__, v->Watermark.DRAMClockChangeWatermark);
+       dml_print("DML::%s: FCLKChangeWatermark = %f\n", __func__, v->Watermark.FCLKChangeWatermark);
+       dml_print("DML::%s: StutterExitWatermark = %f\n", __func__, v->Watermark.StutterExitWatermark);
+       dml_print("DML::%s: StutterEnterPlusExitWatermark = %f\n", __func__, v->Watermark.StutterEnterPlusExitWatermark);
+       dml_print("DML::%s: Z8StutterExitWatermark = %f\n", __func__, v->Watermark.Z8StutterExitWatermark);
        dml_print("DML::%s: Z8StutterEnterPlusExitWatermark = %f\n",
-                       __func__, Watermark->Z8StutterEnterPlusExitWatermark);
+                       __func__, v->Watermark.Z8StutterEnterPlusExitWatermark);
 #endif
 
 
-       st_vars->TotalActiveWriteback = 0;
-       for (k = 0; k < NumberOfActiveSurfaces; ++k) {
-               if (WritebackEnable[k] == true)
-                       st_vars->TotalActiveWriteback = st_vars->TotalActiveWriteback + 1;
+       TotalActiveWriteback = 0;
+       for (k = 0; k < v->NumberOfActiveSurfaces; ++k) {
+               if (v->WritebackEnable[k] == true)
+                       TotalActiveWriteback = TotalActiveWriteback + 1;
        }
 
-       if (st_vars->TotalActiveWriteback <= 1) {
-               Watermark->WritebackUrgentWatermark = mmSOCParameters.WritebackLatency;
+       if (TotalActiveWriteback <= 1) {
+               v->Watermark.WritebackUrgentWatermark = mmSOCParameters.WritebackLatency;
        } else {
-               Watermark->WritebackUrgentWatermark = mmSOCParameters.WritebackLatency
-                               + WritebackChunkSize * 1024.0 / 32.0 / SOCCLK;
+               v->Watermark.WritebackUrgentWatermark = mmSOCParameters.WritebackLatency
+                               + v->WritebackChunkSize * 1024.0 / 32.0 / SOCCLK;
        }
-       if (USRRetrainingRequiredFinal)
-               Watermark->WritebackUrgentWatermark = Watermark->WritebackUrgentWatermark
+       if (v->USRRetrainingRequiredFinal)
+               v->Watermark.WritebackUrgentWatermark = v->Watermark.WritebackUrgentWatermark
                                + mmSOCParameters.USRRetrainingLatency;
 
-       if (st_vars->TotalActiveWriteback <= 1) {
-               Watermark->WritebackDRAMClockChangeWatermark = mmSOCParameters.DRAMClockChangeLatency
+       if (TotalActiveWriteback <= 1) {
+               v->Watermark.WritebackDRAMClockChangeWatermark = mmSOCParameters.DRAMClockChangeLatency
                                + mmSOCParameters.WritebackLatency;
-               Watermark->WritebackFCLKChangeWatermark = mmSOCParameters.FCLKChangeLatency
+               v->Watermark.WritebackFCLKChangeWatermark = mmSOCParameters.FCLKChangeLatency
                                + mmSOCParameters.WritebackLatency;
        } else {
-               Watermark->WritebackDRAMClockChangeWatermark = mmSOCParameters.DRAMClockChangeLatency
-                               + mmSOCParameters.WritebackLatency + WritebackChunkSize * 1024.0 / 32.0 / SOCCLK;
-               Watermark->WritebackFCLKChangeWatermark = mmSOCParameters.FCLKChangeLatency
-                               + mmSOCParameters.WritebackLatency + WritebackChunkSize * 1024 / 32 / SOCCLK;
+               v->Watermark.WritebackDRAMClockChangeWatermark = mmSOCParameters.DRAMClockChangeLatency
+                               + mmSOCParameters.WritebackLatency + v->WritebackChunkSize * 1024.0 / 32.0 / SOCCLK;
+               v->Watermark.WritebackFCLKChangeWatermark = mmSOCParameters.FCLKChangeLatency
+                               + mmSOCParameters.WritebackLatency + v->WritebackChunkSize * 1024 / 32 / SOCCLK;
        }
 
-       if (USRRetrainingRequiredFinal)
-               Watermark->WritebackDRAMClockChangeWatermark = Watermark->WritebackDRAMClockChangeWatermark
+       if (v->USRRetrainingRequiredFinal)
+               v->Watermark.WritebackDRAMClockChangeWatermark = v->Watermark.WritebackDRAMClockChangeWatermark
                                + mmSOCParameters.USRRetrainingLatency;
 
-       if (USRRetrainingRequiredFinal)
-               Watermark->WritebackFCLKChangeWatermark = Watermark->WritebackFCLKChangeWatermark
+       if (v->USRRetrainingRequiredFinal)
+               v->Watermark.WritebackFCLKChangeWatermark = v->Watermark.WritebackFCLKChangeWatermark
                                + mmSOCParameters.USRRetrainingLatency;
 
 #ifdef __DML_VBA_DEBUG__
        dml_print("DML::%s: WritebackDRAMClockChangeWatermark = %f\n",
-                       __func__, Watermark->WritebackDRAMClockChangeWatermark);
-       dml_print("DML::%s: WritebackFCLKChangeWatermark = %f\n", __func__, Watermark->WritebackFCLKChangeWatermark);
-       dml_print("DML::%s: WritebackUrgentWatermark = %f\n", __func__, Watermark->WritebackUrgentWatermark);
-       dml_print("DML::%s: USRRetrainingRequiredFinal = %d\n", __func__, USRRetrainingRequiredFinal);
+                       __func__, v->Watermark.WritebackDRAMClockChangeWatermark);
+       dml_print("DML::%s: WritebackFCLKChangeWatermark = %f\n", __func__, v->Watermark.WritebackFCLKChangeWatermark);
+       dml_print("DML::%s: WritebackUrgentWatermark = %f\n", __func__, v->Watermark.WritebackUrgentWatermark);
+       dml_print("DML::%s: v->USRRetrainingRequiredFinal = %d\n", __func__, v->USRRetrainingRequiredFinal);
        dml_print("DML::%s: USRRetrainingLatency = %f\n", __func__, mmSOCParameters.USRRetrainingLatency);
 #endif
 
-       for (k = 0; k < NumberOfActiveSurfaces; ++k) {
-               st_vars->TotalPixelBW = st_vars->TotalPixelBW + DPPPerSurface[k] * (SwathWidthY[k] * BytePerPixelDETY[k] * VRatio[k] +
-                               SwathWidthC[k] * BytePerPixelDETC[k] * VRatioChroma[k]) / (HTotal[k] / PixelClock[k]);
+       for (k = 0; k < v->NumberOfActiveSurfaces; ++k) {
+               TotalPixelBW = TotalPixelBW + DPPPerSurface[k] * (SwathWidthY[k] * BytePerPixelDETY[k] * v->VRatio[k] +
+                               SwathWidthC[k] * BytePerPixelDETC[k] * v->VRatioChroma[k]) / (v->HTotal[k] / v->PixelClock[k]);
        }
 
-       for (k = 0; k < NumberOfActiveSurfaces; ++k) {
+       for (k = 0; k < v->NumberOfActiveSurfaces; ++k) {
 
-               st_vars->LBLatencyHidingSourceLinesY[k] = dml_min((double) MaxLineBufferLines, dml_floor(LineBufferSize / LBBitPerPixel[k] / (SwathWidthY[k] / dml_max(HRatio[k], 1.0)), 1)) - (VTaps[k] - 1);
-               st_vars->LBLatencyHidingSourceLinesC[k] = dml_min((double) MaxLineBufferLines, dml_floor(LineBufferSize / LBBitPerPixel[k] / (SwathWidthC[k] / dml_max(HRatioChroma[k], 1.0)), 1)) - (VTapsChroma[k] - 1);
+               LBLatencyHidingSourceLinesY[k] = dml_min((double) v->MaxLineBufferLines, dml_floor(v->LineBufferSizeFinal / v->LBBitPerPixel[k] / (SwathWidthY[k] / dml_max(v->HRatio[k], 1.0)), 1)) - (v->vtaps[k] - 1);
+               LBLatencyHidingSourceLinesC[k] = dml_min((double) v->MaxLineBufferLines, dml_floor(v->LineBufferSizeFinal / v->LBBitPerPixel[k] / (SwathWidthC[k] / dml_max(v->HRatioChroma[k], 1.0)), 1)) - (v->VTAPsChroma[k] - 1);
 
 
 #ifdef __DML_VBA_DEBUG__
-               dml_print("DML::%s: k=%d, MaxLineBufferLines = %d\n", __func__, k, MaxLineBufferLines);
-               dml_print("DML::%s: k=%d, LineBufferSize     = %d\n", __func__, k, LineBufferSize);
-               dml_print("DML::%s: k=%d, LBBitPerPixel      = %d\n", __func__, k, LBBitPerPixel[k]);
-               dml_print("DML::%s: k=%d, HRatio             = %f\n", __func__, k, HRatio[k]);
-               dml_print("DML::%s: k=%d, VTaps              = %d\n", __func__, k, VTaps[k]);
+               dml_print("DML::%s: k=%d, v->MaxLineBufferLines = %d\n", __func__, k, v->MaxLineBufferLines);
+               dml_print("DML::%s: k=%d, v->LineBufferSizeFinal     = %d\n", __func__, k, v->LineBufferSizeFinal);
+               dml_print("DML::%s: k=%d, v->LBBitPerPixel      = %d\n", __func__, k, v->LBBitPerPixel[k]);
+               dml_print("DML::%s: k=%d, v->HRatio             = %f\n", __func__, k, v->HRatio[k]);
+               dml_print("DML::%s: k=%d, v->vtaps              = %d\n", __func__, k, v->vtaps[k]);
 #endif
 
-               st_vars->EffectiveLBLatencyHidingY = st_vars->LBLatencyHidingSourceLinesY[k] / VRatio[k] * (HTotal[k] / PixelClock[k]);
-               st_vars->EffectiveLBLatencyHidingC = st_vars->LBLatencyHidingSourceLinesC[k] / VRatioChroma[k] * (HTotal[k] / PixelClock[k]);
-               st_vars->EffectiveDETBufferSizeY = DETBufferSizeY[k];
+               EffectiveLBLatencyHidingY = LBLatencyHidingSourceLinesY[k] / v->VRatio[k] * (v->HTotal[k] / v->PixelClock[k]);
+               EffectiveLBLatencyHidingC = LBLatencyHidingSourceLinesC[k] / v->VRatioChroma[k] * (v->HTotal[k] / v->PixelClock[k]);
+               EffectiveDETBufferSizeY = DETBufferSizeY[k];
 
                if (UnboundedRequestEnabled) {
-                       st_vars->EffectiveDETBufferSizeY = st_vars->EffectiveDETBufferSizeY
+                       EffectiveDETBufferSizeY = EffectiveDETBufferSizeY
                                        + CompressedBufferSizeInkByte * 1024
-                                                       * (SwathWidthY[k] * BytePerPixelDETY[k] * VRatio[k])
-                                                       / (HTotal[k] / PixelClock[k]) / st_vars->TotalPixelBW;
+                                                       * (SwathWidthY[k] * BytePerPixelDETY[k] * v->VRatio[k])
+                                                       / (v->HTotal[k] / v->PixelClock[k]) / TotalPixelBW;
                }
 
-               st_vars->LinesInDETY[k] = (double) st_vars->EffectiveDETBufferSizeY / BytePerPixelDETY[k] / SwathWidthY[k];
-               st_vars->LinesInDETYRoundedDownToSwath[k] = dml_floor(st_vars->LinesInDETY[k], SwathHeightY[k]);
-               st_vars->FullDETBufferingTimeY = st_vars->LinesInDETYRoundedDownToSwath[k] * (HTotal[k] / PixelClock[k]) / VRatio[k];
+               LinesInDETY[k] = (double) EffectiveDETBufferSizeY / BytePerPixelDETY[k] / SwathWidthY[k];
+               LinesInDETYRoundedDownToSwath[k] = dml_floor(LinesInDETY[k], SwathHeightY[k]);
+               FullDETBufferingTimeY = LinesInDETYRoundedDownToSwath[k] * (v->HTotal[k] / v->PixelClock[k]) / v->VRatio[k];
 
-               st_vars->ActiveClockChangeLatencyHidingY = st_vars->EffectiveLBLatencyHidingY + st_vars->FullDETBufferingTimeY
-                               - (DSTXAfterScaler[k] / HTotal[k] + DSTYAfterScaler[k]) * HTotal[k] / PixelClock[k];
+               ActiveClockChangeLatencyHidingY = EffectiveLBLatencyHidingY + FullDETBufferingTimeY
+                               - (DSTXAfterScaler[k] / v->HTotal[k] + DSTYAfterScaler[k]) * v->HTotal[k] / v->PixelClock[k];
 
-               if (NumberOfActiveSurfaces > 1) {
-                       st_vars->ActiveClockChangeLatencyHidingY = st_vars->ActiveClockChangeLatencyHidingY
-                                       - (1 - 1 / NumberOfActiveSurfaces) * SwathHeightY[k] * HTotal[k]
-                                                       / PixelClock[k] / VRatio[k];
+               if (v->NumberOfActiveSurfaces > 1) {
+                       ActiveClockChangeLatencyHidingY = ActiveClockChangeLatencyHidingY
+                                       - (1 - 1 / v->NumberOfActiveSurfaces) * SwathHeightY[k] * v->HTotal[k]
+                                                       / v->PixelClock[k] / v->VRatio[k];
                }
 
                if (BytePerPixelDETC[k] > 0) {
-                       st_vars->LinesInDETC[k] = DETBufferSizeC[k] / BytePerPixelDETC[k] / SwathWidthC[k];
-                       st_vars->LinesInDETCRoundedDownToSwath[k] = dml_floor(st_vars->LinesInDETC[k], SwathHeightC[k]);
-                       st_vars->FullDETBufferingTimeC = st_vars->LinesInDETCRoundedDownToSwath[k] * (HTotal[k] / PixelClock[k])
-                                       / VRatioChroma[k];
-                       st_vars->ActiveClockChangeLatencyHidingC = st_vars->EffectiveLBLatencyHidingC + st_vars->FullDETBufferingTimeC
-                                       - (DSTXAfterScaler[k] / HTotal[k] + DSTYAfterScaler[k]) * HTotal[k]
-                                                       / PixelClock[k];
-                       if (NumberOfActiveSurfaces > 1) {
-                               st_vars->ActiveClockChangeLatencyHidingC = st_vars->ActiveClockChangeLatencyHidingC
-                                               - (1 - 1 / NumberOfActiveSurfaces) * SwathHeightC[k] * HTotal[k]
-                                                               / PixelClock[k] / VRatioChroma[k];
+                       LinesInDETC[k] = DETBufferSizeC[k] / BytePerPixelDETC[k] / SwathWidthC[k];
+                       LinesInDETCRoundedDownToSwath[k] = dml_floor(LinesInDETC[k], SwathHeightC[k]);
+                       FullDETBufferingTimeC = LinesInDETCRoundedDownToSwath[k] * (v->HTotal[k] / v->PixelClock[k])
+                                       / v->VRatioChroma[k];
+                       ActiveClockChangeLatencyHidingC = EffectiveLBLatencyHidingC + FullDETBufferingTimeC
+                                       - (DSTXAfterScaler[k] / v->HTotal[k] + DSTYAfterScaler[k]) * v->HTotal[k]
+                                                       / v->PixelClock[k];
+                       if (v->NumberOfActiveSurfaces > 1) {
+                               ActiveClockChangeLatencyHidingC = ActiveClockChangeLatencyHidingC
+                                               - (1 - 1 / v->NumberOfActiveSurfaces) * SwathHeightC[k] * v->HTotal[k]
+                                                               / v->PixelClock[k] / v->VRatioChroma[k];
                        }
-                       st_vars->ActiveClockChangeLatencyHiding = dml_min(st_vars->ActiveClockChangeLatencyHidingY,
-                                       st_vars->ActiveClockChangeLatencyHidingC);
+                       ActiveClockChangeLatencyHiding = dml_min(ActiveClockChangeLatencyHidingY,
+                                       ActiveClockChangeLatencyHidingC);
                } else {
-                       st_vars->ActiveClockChangeLatencyHiding = st_vars->ActiveClockChangeLatencyHidingY;
+                       ActiveClockChangeLatencyHiding = ActiveClockChangeLatencyHidingY;
                }
 
-               ActiveDRAMClockChangeLatencyMargin[k] = st_vars->ActiveClockChangeLatencyHiding - Watermark->UrgentWatermark
-                               - Watermark->DRAMClockChangeWatermark;
-               st_vars->ActiveFCLKChangeLatencyMargin[k] = st_vars->ActiveClockChangeLatencyHiding - Watermark->UrgentWatermark
-                               - Watermark->FCLKChangeWatermark;
-               st_vars->USRRetrainingLatencyMargin[k] = st_vars->ActiveClockChangeLatencyHiding - Watermark->USRRetrainingWatermark;
+               ActiveDRAMClockChangeLatencyMargin[k] = ActiveClockChangeLatencyHiding - v->Watermark.UrgentWatermark
+                               - v->Watermark.DRAMClockChangeWatermark;
+               ActiveFCLKChangeLatencyMargin[k] = ActiveClockChangeLatencyHiding - v->Watermark.UrgentWatermark
+                               - v->Watermark.FCLKChangeWatermark;
+               USRRetrainingLatencyMargin[k] = ActiveClockChangeLatencyHiding - v->Watermark.USRRetrainingWatermark;
 
-               if (WritebackEnable[k]) {
-                       st_vars->WritebackLatencyHiding = WritebackInterfaceBufferSize * 1024
-                                       / (WritebackDestinationWidth[k] * WritebackDestinationHeight[k]
-                                                       / (WritebackSourceHeight[k] * HTotal[k] / PixelClock[k]) * 4);
-                       if (WritebackPixelFormat[k] == dm_444_64)
-                               st_vars->WritebackLatencyHiding = st_vars->WritebackLatencyHiding / 2;
+               if (v->WritebackEnable[k]) {
+                       WritebackLatencyHiding = v->WritebackInterfaceBufferSize * 1024
+                                       / (v->WritebackDestinationWidth[k] * v->WritebackDestinationHeight[k]
+                                                       / (v->WritebackSourceHeight[k] * v->HTotal[k] / v->PixelClock[k]) * 4);
+                       if (v->WritebackPixelFormat[k] == dm_444_64)
+                               WritebackLatencyHiding = WritebackLatencyHiding / 2;
 
-                       st_vars->WritebackDRAMClockChangeLatencyMargin = st_vars->WritebackLatencyHiding
-                                       - Watermark->WritebackDRAMClockChangeWatermark;
+                       WritebackDRAMClockChangeLatencyMargin = WritebackLatencyHiding
+                                       - v->Watermark.WritebackDRAMClockChangeWatermark;
 
-                       st_vars->WritebackFCLKChangeLatencyMargin = st_vars->WritebackLatencyHiding
-                                       - Watermark->WritebackFCLKChangeWatermark;
+                       WritebackFCLKChangeLatencyMargin = WritebackLatencyHiding
+                                       - v->Watermark.WritebackFCLKChangeWatermark;
 
                        ActiveDRAMClockChangeLatencyMargin[k] = dml_min(ActiveDRAMClockChangeLatencyMargin[k],
-                                       st_vars->WritebackFCLKChangeLatencyMargin);
-                       st_vars->ActiveFCLKChangeLatencyMargin[k] = dml_min(st_vars->ActiveFCLKChangeLatencyMargin[k],
-                                       st_vars->WritebackDRAMClockChangeLatencyMargin);
+                                       WritebackFCLKChangeLatencyMargin);
+                       ActiveFCLKChangeLatencyMargin[k] = dml_min(ActiveFCLKChangeLatencyMargin[k],
+                                       WritebackDRAMClockChangeLatencyMargin);
                }
                MaxActiveDRAMClockChangeLatencySupported[k] =
-                               (UseMALLForPStateChange[k] == dm_use_mall_pstate_change_phantom_pipe) ?
+                               (v->UsesMALLForPStateChange[k] == dm_use_mall_pstate_change_phantom_pipe) ?
                                                0 :
                                                (ActiveDRAMClockChangeLatencyMargin[k]
                                                                + mmSOCParameters.DRAMClockChangeLatency);
        }
 
-       for (i = 0; i < NumberOfActiveSurfaces; ++i) {
-               for (j = 0; j < NumberOfActiveSurfaces; ++j) {
+       for (i = 0; i < v->NumberOfActiveSurfaces; ++i) {
+               for (j = 0; j < v->NumberOfActiveSurfaces; ++j) {
                        if (i == j ||
-                                       (BlendingAndTiming[i] == i && BlendingAndTiming[j] == i) ||
-                                       (BlendingAndTiming[j] == j && BlendingAndTiming[i] == j) ||
-                                       (BlendingAndTiming[i] == BlendingAndTiming[j] && BlendingAndTiming[i] != i) ||
-                                       (SynchronizeTimingsFinal && PixelClock[i] == PixelClock[j] &&
-                                       HTotal[i] == HTotal[j] && VTotal[i] == VTotal[j] &&
-                                       VActive[i] == VActive[j]) || (SynchronizeDRRDisplaysForUCLKPStateChangeFinal &&
-                                       (DRRDisplay[i] || DRRDisplay[j]))) {
-                               st_vars->SynchronizedSurfaces[i][j] = true;
+                                       (v->BlendingAndTiming[i] == i && v->BlendingAndTiming[j] == i) ||
+                                       (v->BlendingAndTiming[j] == j && v->BlendingAndTiming[i] == j) ||
+                                       (v->BlendingAndTiming[i] == v->BlendingAndTiming[j] && v->BlendingAndTiming[i] != i) ||
+                                       (v->SynchronizeTimingsFinal && v->PixelClock[i] == v->PixelClock[j] &&
+                                       v->HTotal[i] == v->HTotal[j] && v->VTotal[i] == v->VTotal[j] &&
+                                       v->VActive[i] == v->VActive[j]) || (v->SynchronizeDRRDisplaysForUCLKPStateChangeFinal &&
+                                       (v->DRRDisplay[i] || v->DRRDisplay[j]))) {
+                               SynchronizedSurfaces[i][j] = true;
                        } else {
-                               st_vars->SynchronizedSurfaces[i][j] = false;
+                               SynchronizedSurfaces[i][j] = false;
                        }
                }
        }
 
-       for (k = 0; k < NumberOfActiveSurfaces; ++k) {
-               if ((UseMALLForPStateChange[k] != dm_use_mall_pstate_change_phantom_pipe) &&
-                               (!st_vars->FoundFirstSurfaceWithMinActiveFCLKChangeMargin ||
-                               st_vars->ActiveFCLKChangeLatencyMargin[k] < st_vars->MinActiveFCLKChangeMargin)) {
-                       st_vars->FoundFirstSurfaceWithMinActiveFCLKChangeMargin = true;
-                       st_vars->MinActiveFCLKChangeMargin = st_vars->ActiveFCLKChangeLatencyMargin[k];
-                       st_vars->SurfaceWithMinActiveFCLKChangeMargin = k;
+       for (k = 0; k < v->NumberOfActiveSurfaces; ++k) {
+               if ((v->UsesMALLForPStateChange[k] != dm_use_mall_pstate_change_phantom_pipe) &&
+                               (!FoundFirstSurfaceWithMinActiveFCLKChangeMargin ||
+                               ActiveFCLKChangeLatencyMargin[k] < MinActiveFCLKChangeMargin)) {
+                       FoundFirstSurfaceWithMinActiveFCLKChangeMargin = true;
+                       MinActiveFCLKChangeMargin = ActiveFCLKChangeLatencyMargin[k];
+                       SurfaceWithMinActiveFCLKChangeMargin = k;
                }
        }
 
-       *MinActiveFCLKChangeLatencySupported = st_vars->MinActiveFCLKChangeMargin + mmSOCParameters.FCLKChangeLatency;
+       *MinActiveFCLKChangeLatencySupported = MinActiveFCLKChangeMargin + mmSOCParameters.FCLKChangeLatency;
 
-       st_vars->SameTimingForFCLKChange = true;
-       for (k = 0; k < NumberOfActiveSurfaces; ++k) {
-               if (!st_vars->SynchronizedSurfaces[k][st_vars->SurfaceWithMinActiveFCLKChangeMargin]) {
-                       if ((UseMALLForPStateChange[k] != dm_use_mall_pstate_change_phantom_pipe) &&
-                                       (st_vars->SameTimingForFCLKChange ||
-                                       st_vars->ActiveFCLKChangeLatencyMargin[k] <
-                                       st_vars->SecondMinActiveFCLKChangeMarginOneDisplayInVBLank)) {
-                               st_vars->SecondMinActiveFCLKChangeMarginOneDisplayInVBLank = st_vars->ActiveFCLKChangeLatencyMargin[k];
+       SameTimingForFCLKChange = true;
+       for (k = 0; k < v->NumberOfActiveSurfaces; ++k) {
+               if (!SynchronizedSurfaces[k][SurfaceWithMinActiveFCLKChangeMargin]) {
+                       if ((v->UsesMALLForPStateChange[k] != dm_use_mall_pstate_change_phantom_pipe) &&
+                                       (SameTimingForFCLKChange ||
+                                       ActiveFCLKChangeLatencyMargin[k] <
+                                       SecondMinActiveFCLKChangeMarginOneDisplayInVBLank)) {
+                               SecondMinActiveFCLKChangeMarginOneDisplayInVBLank = ActiveFCLKChangeLatencyMargin[k];
                        }
-                       st_vars->SameTimingForFCLKChange = false;
+                       SameTimingForFCLKChange = false;
                }
        }
 
-       if (st_vars->MinActiveFCLKChangeMargin > 0) {
+       if (MinActiveFCLKChangeMargin > 0) {
                *FCLKChangeSupport = dm_fclock_change_vactive;
-       } else if ((st_vars->SameTimingForFCLKChange || st_vars->SecondMinActiveFCLKChangeMarginOneDisplayInVBLank > 0) &&
+       } else if ((SameTimingForFCLKChange || SecondMinActiveFCLKChangeMarginOneDisplayInVBLank > 0) &&
                        (PrefetchMode <= 1)) {
                *FCLKChangeSupport = dm_fclock_change_vblank;
        } else {
@@ -4451,95 +4476,95 @@ void dml32_CalculateWatermarksMALLUseAndDRAMSpeedChangeSupport(
        }
 
        *USRRetrainingSupport = true;
-       for (k = 0; k < NumberOfActiveSurfaces; ++k) {
-               if ((UseMALLForPStateChange[k] != dm_use_mall_pstate_change_phantom_pipe) &&
-                               (st_vars->USRRetrainingLatencyMargin[k] < 0)) {
+       for (k = 0; k < v->NumberOfActiveSurfaces; ++k) {
+               if ((v->UsesMALLForPStateChange[k] != dm_use_mall_pstate_change_phantom_pipe) &&
+                               (USRRetrainingLatencyMargin[k] < 0)) {
                        *USRRetrainingSupport = false;
                }
        }
 
-       for (k = 0; k < NumberOfActiveSurfaces; ++k) {
-               if (UseMALLForPStateChange[k] != dm_use_mall_pstate_change_full_frame &&
-                               UseMALLForPStateChange[k] != dm_use_mall_pstate_change_sub_viewport &&
-                               UseMALLForPStateChange[k] != dm_use_mall_pstate_change_phantom_pipe &&
+       for (k = 0; k < v->NumberOfActiveSurfaces; ++k) {
+               if (v->UsesMALLForPStateChange[k] != dm_use_mall_pstate_change_full_frame &&
+                               v->UsesMALLForPStateChange[k] != dm_use_mall_pstate_change_sub_viewport &&
+                               v->UsesMALLForPStateChange[k] != dm_use_mall_pstate_change_phantom_pipe &&
                                ActiveDRAMClockChangeLatencyMargin[k] < 0) {
                        if (PrefetchMode > 0) {
-                               st_vars->DRAMClockChangeSupportNumber = 2;
-                       } else if (st_vars->DRAMClockChangeSupportNumber == 0) {
-                               st_vars->DRAMClockChangeSupportNumber = 1;
-                               st_vars->LastSurfaceWithoutMargin = k;
-                       } else if (st_vars->DRAMClockChangeSupportNumber == 1 &&
-                                       !st_vars->SynchronizedSurfaces[st_vars->LastSurfaceWithoutMargin][k]) {
-                               st_vars->DRAMClockChangeSupportNumber = 2;
+                               DRAMClockChangeSupportNumber = 2;
+                       } else if (DRAMClockChangeSupportNumber == 0) {
+                               DRAMClockChangeSupportNumber = 1;
+                               LastSurfaceWithoutMargin = k;
+                       } else if (DRAMClockChangeSupportNumber == 1 &&
+                                       !SynchronizedSurfaces[LastSurfaceWithoutMargin][k]) {
+                               DRAMClockChangeSupportNumber = 2;
                        }
                }
        }
 
-       for (k = 0; k < NumberOfActiveSurfaces; ++k) {
-               if (UseMALLForPStateChange[k] == dm_use_mall_pstate_change_full_frame)
-                       st_vars->DRAMClockChangeMethod = 1;
-               else if (UseMALLForPStateChange[k] == dm_use_mall_pstate_change_sub_viewport)
-                       st_vars->DRAMClockChangeMethod = 2;
+       for (k = 0; k < v->NumberOfActiveSurfaces; ++k) {
+               if (v->UsesMALLForPStateChange[k] == dm_use_mall_pstate_change_full_frame)
+                       DRAMClockChangeMethod = 1;
+               else if (v->UsesMALLForPStateChange[k] == dm_use_mall_pstate_change_sub_viewport)
+                       DRAMClockChangeMethod = 2;
        }
 
-       if (st_vars->DRAMClockChangeMethod == 0) {
-               if (st_vars->DRAMClockChangeSupportNumber == 0)
+       if (DRAMClockChangeMethod == 0) {
+               if (DRAMClockChangeSupportNumber == 0)
                        *DRAMClockChangeSupport = dm_dram_clock_change_vactive;
-               else if (st_vars->DRAMClockChangeSupportNumber == 1)
+               else if (DRAMClockChangeSupportNumber == 1)
                        *DRAMClockChangeSupport = dm_dram_clock_change_vblank;
                else
                        *DRAMClockChangeSupport = dm_dram_clock_change_unsupported;
-       } else if (st_vars->DRAMClockChangeMethod == 1) {
-               if (st_vars->DRAMClockChangeSupportNumber == 0)
+       } else if (DRAMClockChangeMethod == 1) {
+               if (DRAMClockChangeSupportNumber == 0)
                        *DRAMClockChangeSupport = dm_dram_clock_change_vactive_w_mall_full_frame;
-               else if (st_vars->DRAMClockChangeSupportNumber == 1)
+               else if (DRAMClockChangeSupportNumber == 1)
                        *DRAMClockChangeSupport = dm_dram_clock_change_vblank_w_mall_full_frame;
                else
                        *DRAMClockChangeSupport = dm_dram_clock_change_unsupported;
        } else {
-               if (st_vars->DRAMClockChangeSupportNumber == 0)
+               if (DRAMClockChangeSupportNumber == 0)
                        *DRAMClockChangeSupport = dm_dram_clock_change_vactive_w_mall_sub_vp;
-               else if (st_vars->DRAMClockChangeSupportNumber == 1)
+               else if (DRAMClockChangeSupportNumber == 1)
                        *DRAMClockChangeSupport = dm_dram_clock_change_vblank_w_mall_sub_vp;
                else
                        *DRAMClockChangeSupport = dm_dram_clock_change_unsupported;
        }
 
-       for (k = 0; k < NumberOfActiveSurfaces; ++k) {
+       for (k = 0; k < v->NumberOfActiveSurfaces; ++k) {
                unsigned int dst_y_pstate;
                unsigned int src_y_pstate_l;
                unsigned int src_y_pstate_c;
                unsigned int src_y_ahead_l, src_y_ahead_c, sub_vp_lines_l, sub_vp_lines_c;
 
-               dst_y_pstate = dml_ceil((mmSOCParameters.DRAMClockChangeLatency + mmSOCParameters.UrgentLatency) / (HTotal[k] / PixelClock[k]), 1);
-               src_y_pstate_l = dml_ceil(dst_y_pstate * VRatio[k], SwathHeightY[k]);
-               src_y_ahead_l = dml_floor(DETBufferSizeY[k] / BytePerPixelDETY[k] / SwathWidthY[k], SwathHeightY[k]) + st_vars->LBLatencyHidingSourceLinesY[k];
-               sub_vp_lines_l = src_y_pstate_l + src_y_ahead_l + meta_row_height[k];
+               dst_y_pstate = dml_ceil((mmSOCParameters.DRAMClockChangeLatency + mmSOCParameters.UrgentLatency) / (v->HTotal[k] / v->PixelClock[k]), 1);
+               src_y_pstate_l = dml_ceil(dst_y_pstate * v->VRatio[k], SwathHeightY[k]);
+               src_y_ahead_l = dml_floor(DETBufferSizeY[k] / BytePerPixelDETY[k] / SwathWidthY[k], SwathHeightY[k]) + LBLatencyHidingSourceLinesY[k];
+               sub_vp_lines_l = src_y_pstate_l + src_y_ahead_l + v->meta_row_height[k];
 
 #ifdef __DML_VBA_DEBUG__
 dml_print("DML::%s: k=%d, DETBufferSizeY               = %d\n", __func__, k, DETBufferSizeY[k]);
 dml_print("DML::%s: k=%d, BytePerPixelDETY             = %f\n", __func__, k, BytePerPixelDETY[k]);
 dml_print("DML::%s: k=%d, SwathWidthY                  = %d\n", __func__, k, SwathWidthY[k]);
 dml_print("DML::%s: k=%d, SwathHeightY                 = %d\n", __func__, k, SwathHeightY[k]);
-dml_print("DML::%s: k=%d, LBLatencyHidingSourceLinesY  = %d\n", __func__, k, st_vars->LBLatencyHidingSourceLinesY[k]);
+dml_print("DML::%s: k=%d, LBLatencyHidingSourceLinesY  = %d\n", __func__, k, LBLatencyHidingSourceLinesY[k]);
 dml_print("DML::%s: k=%d, dst_y_pstate      = %d\n", __func__, k, dst_y_pstate);
 dml_print("DML::%s: k=%d, src_y_pstate_l    = %d\n", __func__, k, src_y_pstate_l);
 dml_print("DML::%s: k=%d, src_y_ahead_l     = %d\n", __func__, k, src_y_ahead_l);
-dml_print("DML::%s: k=%d, meta_row_height   = %d\n", __func__, k, meta_row_height[k]);
+dml_print("DML::%s: k=%d, v->meta_row_height   = %d\n", __func__, k, v->meta_row_height[k]);
 dml_print("DML::%s: k=%d, sub_vp_lines_l    = %d\n", __func__, k, sub_vp_lines_l);
 #endif
                SubViewportLinesNeededInMALL[k] = sub_vp_lines_l;
 
                if (BytePerPixelDETC[k] > 0) {
-                       src_y_pstate_c = dml_ceil(dst_y_pstate * VRatioChroma[k], SwathHeightC[k]);
-                       src_y_ahead_c = dml_floor(DETBufferSizeC[k] / BytePerPixelDETC[k] / SwathWidthC[k], SwathHeightC[k]) + st_vars->LBLatencyHidingSourceLinesC[k];
-                       sub_vp_lines_c = src_y_pstate_c + src_y_ahead_c + meta_row_height_chroma[k];
+                       src_y_pstate_c = dml_ceil(dst_y_pstate * v->VRatioChroma[k], SwathHeightC[k]);
+                       src_y_ahead_c = dml_floor(DETBufferSizeC[k] / BytePerPixelDETC[k] / SwathWidthC[k], SwathHeightC[k]) + LBLatencyHidingSourceLinesC[k];
+                       sub_vp_lines_c = src_y_pstate_c + src_y_ahead_c + v->meta_row_height_chroma[k];
                        SubViewportLinesNeededInMALL[k] = dml_max(sub_vp_lines_l, sub_vp_lines_c);
 
 #ifdef __DML_VBA_DEBUG__
 dml_print("DML::%s: k=%d, src_y_pstate_c            = %d\n", __func__, k, src_y_pstate_c);
 dml_print("DML::%s: k=%d, src_y_ahead_c             = %d\n", __func__, k, src_y_ahead_c);
-dml_print("DML::%s: k=%d, meta_row_height_chroma    = %d\n", __func__, k, meta_row_height_chroma[k]);
+dml_print("DML::%s: k=%d, v->meta_row_height_chroma    = %d\n", __func__, k, v->meta_row_height_chroma[k]);
 dml_print("DML::%s: k=%d, sub_vp_lines_c            = %d\n", __func__, k, sub_vp_lines_c);
 #endif
                }
index 37a314c..924e361 100644 (file)
@@ -82,7 +82,6 @@ void dml32_CalculateSinglePipeDPPCLKAndSCLThroughput(
                double *DPPCLKUsingSingleDPP);
 
 void dml32_CalculateSwathAndDETConfiguration(
-               struct dml32_CalculateSwathAndDETConfiguration *st_vars,
                unsigned int DETSizeOverride[],
                enum dm_use_mall_for_pstate_change_mode UseMALLForPStateChange[],
                unsigned int ConfigReturnBufferSizeInKByte,
@@ -362,7 +361,6 @@ void dml32_CalculateSurfaceSizeInMall(
                bool *ExceededMALLSize);
 
 void dml32_CalculateVMRowAndSwath(
-               struct dml32_CalculateVMRowAndSwath *st_vars,
                unsigned int NumberOfActiveSurfaces,
                DmlPipe myPipe[],
                unsigned int SurfaceSizeInMALL[],
@@ -715,29 +713,14 @@ double dml32_CalculateExtraLatency(
                unsigned int HostVMMaxNonCachedPageTableLevels);
 
 bool dml32_CalculatePrefetchSchedule(
-               struct dml32_CalculatePrefetchSchedule *st_vars,
+               struct vba_vars_st *v,
+               unsigned int k,
                double HostVMInefficiencyFactor,
                DmlPipe *myPipe,
                unsigned int DSCDelay,
-               double DPPCLKDelaySubtotalPlusCNVCFormater,
-               double DPPCLKDelaySCL,
-               double DPPCLKDelaySCLLBOnly,
-               double DPPCLKDelayCNVCCursor,
-               double DISPCLKDelaySubtotal,
                unsigned int DPP_RECOUT_WIDTH,
-               enum output_format_class OutputFormat,
-               unsigned int MaxInterDCNTileRepeaters,
                unsigned int VStartup,
                unsigned int MaxVStartup,
-               unsigned int GPUVMPageTableLevels,
-               bool GPUVMEnable,
-               bool HostVMEnable,
-               unsigned int HostVMMaxNonCachedPageTableLevels,
-               double HostVMMinPageSize,
-               bool DynamicMetadataEnable,
-               bool DynamicMetadataVMEnabled,
-               int DynamicMetadataLinesBeforeActiveRequired,
-               unsigned int DynamicMetadataTransmittedBytes,
                double UrgentLatency,
                double UrgentExtraLatency,
                double TCalc,
@@ -811,59 +794,28 @@ void dml32_CalculateFlipSchedule(
                bool *ImmediateFlipSupportedForPipe);
 
 void dml32_CalculateWatermarksMALLUseAndDRAMSpeedChangeSupport(
-               struct dml32_CalculateWatermarksMALLUseAndDRAMSpeedChangeSupport *st_vars,
-               bool USRRetrainingRequiredFinal,
-               enum dm_use_mall_for_pstate_change_mode UseMALLForPStateChange[],
+               struct vba_vars_st *v,
                unsigned int PrefetchMode,
-               unsigned int NumberOfActiveSurfaces,
-               unsigned int MaxLineBufferLines,
-               unsigned int LineBufferSize,
-               unsigned int WritebackInterfaceBufferSize,
                double DCFCLK,
                double ReturnBW,
-               bool SynchronizeTimingsFinal,
-               bool SynchronizeDRRDisplaysForUCLKPStateChangeFinal,
-               bool DRRDisplay[],
-               unsigned int dpte_group_bytes[],
-               unsigned int meta_row_height[],
-               unsigned int meta_row_height_chroma[],
                SOCParametersList mmSOCParameters,
-               unsigned int WritebackChunkSize,
                double SOCCLK,
                double DCFClkDeepSleep,
                unsigned int DETBufferSizeY[],
                unsigned int DETBufferSizeC[],
                unsigned int SwathHeightY[],
                unsigned int SwathHeightC[],
-               unsigned int LBBitPerPixel[],
                double SwathWidthY[],
                double SwathWidthC[],
-               double HRatio[],
-               double HRatioChroma[],
-               unsigned int VTaps[],
-               unsigned int VTapsChroma[],
-               double VRatio[],
-               double VRatioChroma[],
-               unsigned int HTotal[],
-               unsigned int VTotal[],
-               unsigned int VActive[],
-               double PixelClock[],
-               unsigned int BlendingAndTiming[],
                unsigned int DPPPerSurface[],
                double BytePerPixelDETY[],
                double BytePerPixelDETC[],
                double DSTXAfterScaler[],
                double DSTYAfterScaler[],
-               bool WritebackEnable[],
-               enum source_format_class WritebackPixelFormat[],
-               double WritebackDestinationWidth[],
-               double WritebackDestinationHeight[],
-               double WritebackSourceHeight[],
                bool UnboundedRequestEnabled,
                unsigned int CompressedBufferSizeInkByte,
 
                /* Output */
-               Watermarks *Watermark,
                enum clock_change_support *DRAMClockChangeSupport,
                double MaxActiveDRAMClockChangeLatencySupported[],
                unsigned int SubViewportLinesNeededInMALL[],
index 84b4b00..c870916 100644 (file)
@@ -498,6 +498,13 @@ void dcn321_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_p
                                dc->bb_overrides.dram_clock_change_latency_ns / 1000.0;
                }
 
+               if ((int)(dcn3_21_soc.fclk_change_latency_us * 1000)
+                               != dc->bb_overrides.fclk_clock_change_latency_ns
+                               && dc->bb_overrides.fclk_clock_change_latency_ns) {
+                       dcn3_21_soc.fclk_change_latency_us =
+                               dc->bb_overrides.fclk_clock_change_latency_ns / 1000;
+               }
+
                if ((int)(dcn3_21_soc.dummy_pstate_latency_us * 1000)
                                != dc->bb_overrides.dummy_clock_change_latency_ns
                                && dc->bb_overrides.dummy_clock_change_latency_ns) {
index 5d27ff0..f5400ed 100644 (file)
@@ -35,6 +35,8 @@
 #include "dcn30/display_rq_dlg_calc_30.h"
 #include "dcn31/display_mode_vba_31.h"
 #include "dcn31/display_rq_dlg_calc_31.h"
+#include "dcn314/display_mode_vba_314.h"
+#include "dcn314/display_rq_dlg_calc_314.h"
 #include "dcn32/display_mode_vba_32.h"
 #include "dcn32/display_rq_dlg_calc_32.h"
 #include "dml_logger.h"
@@ -74,6 +76,13 @@ const struct dml_funcs dml31_funcs = {
        .rq_dlg_get_rq_reg = dml31_rq_dlg_get_rq_reg
 };
 
+const struct dml_funcs dml314_funcs = {
+       .validate = dml314_ModeSupportAndSystemConfigurationFull,
+       .recalculate = dml314_recalculate,
+       .rq_dlg_get_dlg_reg = dml314_rq_dlg_get_dlg_reg,
+       .rq_dlg_get_rq_reg = dml314_rq_dlg_get_rq_reg
+};
+
 const struct dml_funcs dml32_funcs = {
        .validate = dml32_ModeSupportAndSystemConfigurationFull,
     .recalculate = dml32_recalculate,
@@ -107,6 +116,9 @@ void dml_init_instance(struct display_mode_lib *lib,
        case DML_PROJECT_DCN31_FPGA:
                lib->funcs = dml31_funcs;
                break;
+       case DML_PROJECT_DCN314:
+               lib->funcs = dml314_funcs;
+               break;
        case DML_PROJECT_DCN32:
                lib->funcs = dml32_funcs;
                break;
index 2bdd6ed..b1878a1 100644 (file)
@@ -41,6 +41,7 @@ enum dml_project {
        DML_PROJECT_DCN30,
        DML_PROJECT_DCN31,
        DML_PROJECT_DCN31_FPGA,
+       DML_PROJECT_DCN314,
        DML_PROJECT_DCN32,
 };
 
index 8460aef..2051dda 100644 (file)
@@ -182,108 +182,6 @@ void Calculate256BBlockSizes(
                unsigned int *BlockWidth256BytesY,
                unsigned int *BlockWidth256BytesC);
 
-struct dml32_CalculateSwathAndDETConfiguration {
-       unsigned int MaximumSwathHeightY[DC__NUM_DPP__MAX];
-       unsigned int MaximumSwathHeightC[DC__NUM_DPP__MAX];
-       unsigned int RoundedUpMaxSwathSizeBytesY[DC__NUM_DPP__MAX];
-       unsigned int RoundedUpMaxSwathSizeBytesC[DC__NUM_DPP__MAX];
-       unsigned int RoundedUpSwathSizeBytesY;
-       unsigned int RoundedUpSwathSizeBytesC;
-       double SwathWidthdoubleDPP[DC__NUM_DPP__MAX];
-       double SwathWidthdoubleDPPChroma[DC__NUM_DPP__MAX];
-       unsigned int TotalActiveDPP;
-       bool NoChromaSurfaces;
-       unsigned int DETBufferSizeInKByteForSwathCalculation;
-};
-
-struct dml32_CalculateVMRowAndSwath {
-       unsigned int PTEBufferSizeInRequestsForLuma[DC__NUM_DPP__MAX];
-       unsigned int PTEBufferSizeInRequestsForChroma[DC__NUM_DPP__MAX];
-       unsigned int PDEAndMetaPTEBytesFrameY;
-       unsigned int PDEAndMetaPTEBytesFrameC;
-       unsigned int MetaRowByteY[DC__NUM_DPP__MAX];
-       unsigned int MetaRowByteC[DC__NUM_DPP__MAX];
-       unsigned int PixelPTEBytesPerRowY[DC__NUM_DPP__MAX];
-       unsigned int PixelPTEBytesPerRowC[DC__NUM_DPP__MAX];
-       unsigned int PixelPTEBytesPerRowY_one_row_per_frame[DC__NUM_DPP__MAX];
-       unsigned int PixelPTEBytesPerRowC_one_row_per_frame[DC__NUM_DPP__MAX];
-       unsigned int dpte_row_width_luma_ub_one_row_per_frame[DC__NUM_DPP__MAX];
-       unsigned int dpte_row_height_luma_one_row_per_frame[DC__NUM_DPP__MAX];
-       unsigned int dpte_row_width_chroma_ub_one_row_per_frame[DC__NUM_DPP__MAX];
-       unsigned int dpte_row_height_chroma_one_row_per_frame[DC__NUM_DPP__MAX];
-       bool one_row_per_frame_fits_in_buffer[DC__NUM_DPP__MAX];
-};
-
-struct dml32_CalculateWatermarksMALLUseAndDRAMSpeedChangeSupport {
-       unsigned int SurfaceWithMinActiveFCLKChangeMargin;
-       unsigned int DRAMClockChangeSupportNumber;
-       unsigned int LastSurfaceWithoutMargin;
-       unsigned int DRAMClockChangeMethod;
-       bool FoundFirstSurfaceWithMinActiveFCLKChangeMargin;
-       double MinActiveFCLKChangeMargin;
-       double SecondMinActiveFCLKChangeMarginOneDisplayInVBLank;
-       double ActiveClockChangeLatencyHidingY;
-       double ActiveClockChangeLatencyHidingC;
-       double ActiveClockChangeLatencyHiding;
-       double EffectiveDETBufferSizeY;
-       double ActiveFCLKChangeLatencyMargin[DC__NUM_DPP__MAX];
-       double USRRetrainingLatencyMargin[DC__NUM_DPP__MAX];
-       double TotalPixelBW;
-       bool SynchronizedSurfaces[DC__NUM_DPP__MAX][DC__NUM_DPP__MAX];
-       double EffectiveLBLatencyHidingY;
-       double EffectiveLBLatencyHidingC;
-       double LinesInDETY[DC__NUM_DPP__MAX];
-       double LinesInDETC[DC__NUM_DPP__MAX];
-       unsigned int LinesInDETYRoundedDownToSwath[DC__NUM_DPP__MAX];
-       unsigned int LinesInDETCRoundedDownToSwath[DC__NUM_DPP__MAX];
-       double FullDETBufferingTimeY;
-       double FullDETBufferingTimeC;
-       double WritebackDRAMClockChangeLatencyMargin;
-       double WritebackFCLKChangeLatencyMargin;
-       double WritebackLatencyHiding;
-       bool SameTimingForFCLKChange;
-       unsigned int TotalActiveWriteback;
-       unsigned int LBLatencyHidingSourceLinesY[DC__NUM_DPP__MAX];
-       unsigned int LBLatencyHidingSourceLinesC[DC__NUM_DPP__MAX];
-};
-
-struct dml32_CalculatePrefetchSchedule {
-       unsigned int DPPCycles, DISPCLKCycles;
-       double DSTTotalPixelsAfterScaler;
-       double LineTime;
-       double dst_y_prefetch_equ;
-       double prefetch_bw_oto;
-       double Tvm_oto;
-       double Tr0_oto;
-       double Tvm_oto_lines;
-       double Tr0_oto_lines;
-       double dst_y_prefetch_oto;
-       double TimeForFetchingMetaPTE;
-       double TimeForFetchingRowInVBlank;
-       double LinesToRequestPrefetchPixelData;
-       unsigned int HostVMDynamicLevelsTrips;
-       double trip_to_mem;
-       double Tvm_trips;
-       double Tr0_trips;
-       double Tvm_trips_rounded;
-       double Tr0_trips_rounded;
-       double Lsw_oto;
-       double Tpre_rounded;
-       double prefetch_bw_equ;
-       double Tvm_equ;
-       double Tr0_equ;
-       double Tdmbf;
-       double Tdmec;
-       double Tdmsks;
-       double prefetch_sw_bytes;
-       double bytes_pp;
-       double dep_bytes;
-       unsigned int max_vratio_pre;
-       double min_Lsw;
-       double Tsw_est1;
-       double Tsw_est3;
-};
-
 struct DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerformanceCalculation {
        unsigned int dummy_integer_array[2][DC__NUM_DPP__MAX];
        double dummy_single_array[2][DC__NUM_DPP__MAX];
@@ -355,10 +253,6 @@ struct dummy_vars {
        struct DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerformanceCalculation
        DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerformanceCalculation;
        struct dml32_ModeSupportAndSystemConfigurationFull dml32_ModeSupportAndSystemConfigurationFull;
-       struct dml32_CalculateSwathAndDETConfiguration dml32_CalculateSwathAndDETConfiguration;
-       struct dml32_CalculateVMRowAndSwath dml32_CalculateVMRowAndSwath;
-       struct dml32_CalculateWatermarksMALLUseAndDRAMSpeedChangeSupport dml32_CalculateWatermarksMALLUseAndDRAMSpeedChangeSupport;
-       struct dml32_CalculatePrefetchSchedule dml32_CalculatePrefetchSchedule;
 };
 
 struct vba_vars_st {
@@ -757,10 +651,10 @@ struct vba_vars_st {
 
        unsigned int OutputTypeAndRatePerState[DC__VOLTAGE_STATES][DC__NUM_DPP__MAX];
        double RequiredDISPCLKPerSurface[DC__VOLTAGE_STATES][2][DC__NUM_DPP__MAX];
-       unsigned int MicroTileHeightY[DC__NUM_DPP__MAX];
-       unsigned int MicroTileHeightC[DC__NUM_DPP__MAX];
-       unsigned int MicroTileWidthY[DC__NUM_DPP__MAX];
-       unsigned int MicroTileWidthC[DC__NUM_DPP__MAX];
+       unsigned int MacroTileHeightY[DC__NUM_DPP__MAX];
+       unsigned int MacroTileHeightC[DC__NUM_DPP__MAX];
+       unsigned int MacroTileWidthY[DC__NUM_DPP__MAX];
+       unsigned int MacroTileWidthC[DC__NUM_DPP__MAX];
        bool ImmediateFlipRequiredFinal;
        bool DCCProgrammingAssumesScanDirectionUnknownFinal;
        bool EnoughWritebackUnits;
@@ -906,8 +800,6 @@ struct vba_vars_st {
        double PSCL_FACTOR[DC__NUM_DPP__MAX];
        double PSCL_FACTOR_CHROMA[DC__NUM_DPP__MAX];
        double MaximumVStartup[DC__VOLTAGE_STATES][2][DC__NUM_DPP__MAX];
-       unsigned int MacroTileWidthY[DC__NUM_DPP__MAX];
-       unsigned int MacroTileWidthC[DC__NUM_DPP__MAX];
        double AlignedDCCMetaPitch[DC__NUM_DPP__MAX];
        double AlignedYPitch[DC__NUM_DPP__MAX];
        double AlignedCPitch[DC__NUM_DPP__MAX];
index 5d2b028..d9f1b0a 100644 (file)
@@ -214,6 +214,7 @@ struct dummy_pstate_entry {
 struct clk_bw_params {
        unsigned int vram_type;
        unsigned int num_channels;
+       unsigned int dram_channel_width_bytes;
        unsigned int dispclk_vco_khz;
        unsigned int dc_mode_softmax_memclk;
        struct clk_limit_table clk_table;
index db7b0b1..226af06 100644 (file)
@@ -116,7 +116,7 @@ static void setup_hpo_dp_stream_encoder(struct pipe_ctx *pipe_ctx)
        dto_params.timing = &pipe_ctx->stream->timing;
        dto_params.ref_dtbclk_khz = dc->clk_mgr->funcs->get_dtb_ref_clk_frequency(dc->clk_mgr);
 
-       dccg->funcs->set_dpstreamclk(dccg, DTBCLK0, tg->inst, link_enc->inst);
+       dccg->funcs->set_dpstreamclk(dccg, DTBCLK0, tg->inst, stream_enc->inst);
        dccg->funcs->enable_symclk32_se(dccg, stream_enc->inst, phyd32clk);
        dccg->funcs->set_dtbclk_dto(dccg, &dto_params);
        stream_enc->funcs->enable_stream(stream_enc);
@@ -137,7 +137,7 @@ static void reset_hpo_dp_stream_encoder(struct pipe_ctx *pipe_ctx)
        stream_enc->funcs->disable(stream_enc);
        dccg->funcs->set_dtbclk_dto(dccg, &dto_params);
        dccg->funcs->disable_symclk32_se(dccg, stream_enc->inst);
-       dccg->funcs->set_dpstreamclk(dccg, REFCLK, tg->inst,  pipe_ctx->link_res.hpo_dp_link_enc->inst);
+       dccg->funcs->set_dpstreamclk(dccg, REFCLK, tg->inst, stream_enc->inst);
 }
 
 static void setup_hpo_dp_stream_attribute(struct pipe_ctx *pipe_ctx)
index ab06c7f..9f3558c 100644 (file)
@@ -244,13 +244,15 @@ enum {
 #define ASICREV_IS_GC_10_3_7(eChipRev) ((eChipRev >= GC_10_3_7_A0) && (eChipRev < GC_10_3_7_UNKNOWN))
 
 #define AMDGPU_FAMILY_GC_11_0_0 145
-#define AMDGPU_FAMILY_GC_11_0_2 148
+#define AMDGPU_FAMILY_GC_11_0_1 148
 #define GC_11_0_0_A0 0x1
 #define GC_11_0_2_A0 0x10
+#define GC_11_0_3_A0 0x20
 #define GC_11_UNKNOWN 0xFF
 
 #define ASICREV_IS_GC_11_0_0(eChipRev) (eChipRev < GC_11_0_2_A0)
-#define ASICREV_IS_GC_11_0_2(eChipRev) (eChipRev >= GC_11_0_2_A0 && eChipRev < GC_11_UNKNOWN)
+#define ASICREV_IS_GC_11_0_2(eChipRev) (eChipRev >= GC_11_0_2_A0 && eChipRev < GC_11_0_3_A0)
+#define ASICREV_IS_GC_11_0_3(eChipRev) (eChipRev >= GC_11_0_3_A0 && eChipRev < GC_11_UNKNOWN)
 
 /*
  * ASIC chip ID
index f093b49..3bf08a6 100644 (file)
@@ -119,13 +119,15 @@ enum dc_log_type {
        LOG_HDMI_RETIMER_REDRIVER,
        LOG_DSC,
        LOG_SMU_MSG,
+       LOG_DC2RESERVED4,
+       LOG_DC2RESERVED5,
        LOG_DWB,
        LOG_GAMMA_DEBUG,
        LOG_MAX_HW_POINTS,
        LOG_ALL_TF_CHANNELS,
        LOG_SAMPLE_1DLUT,
        LOG_DP2,
-       LOG_SECTION_TOTAL_COUNT
+       LOG_DC2RESERVED12,
 };
 
 #define DC_MIN_LOG_MASK ((1 << LOG_ERROR) | \
index 859ffd8..04f7656 100644 (file)
@@ -1600,6 +1600,7 @@ static void interpolate_user_regamma(uint32_t hw_points_num,
        struct fixed31_32 lut2;
        struct fixed31_32 delta_lut;
        struct fixed31_32 delta_index;
+       const struct fixed31_32 one = dc_fixpt_from_int(1);
 
        i = 0;
        /* fixed_pt library has problems handling too small values */
@@ -1628,6 +1629,9 @@ static void interpolate_user_regamma(uint32_t hw_points_num,
                        } else
                                hw_x = coordinates_x[i].x;
 
+                       if (dc_fixpt_le(one, hw_x))
+                               hw_x = one;
+
                        norm_x = dc_fixpt_mul(norm_factor, hw_x);
                        index = dc_fixpt_floor(norm_x);
                        if (index < 0 || index > 255)
index da09ba7..0f39ab9 100644 (file)
@@ -613,10 +613,6 @@ static void build_vrr_infopacket_data_v1(const struct mod_vrr_params *vrr,
         * Note: We should never go above the field rate of the mode timing set.
         */
        infopacket->sb[8] = (unsigned char)((vrr->max_refresh_in_uhz + 500000) / 1000000);
-
-       /* FreeSync HDR */
-       infopacket->sb[9] = 0;
-       infopacket->sb[10] = 0;
 }
 
 static void build_vrr_infopacket_data_v3(const struct mod_vrr_params *vrr,
@@ -684,10 +680,6 @@ static void build_vrr_infopacket_data_v3(const struct mod_vrr_params *vrr,
 
        /* PB16 : Reserved bits 7:1, FixedRate bit 0 */
        infopacket->sb[16] = (vrr->state == VRR_STATE_ACTIVE_FIXED) ? 1 : 0;
-
-       //FreeSync HDR
-       infopacket->sb[9] = 0;
-       infopacket->sb[10] = 0;
 }
 
 static void build_vrr_infopacket_fs2_data(enum color_transfer_func app_tf,
@@ -772,8 +764,7 @@ static void build_vrr_infopacket_header_v2(enum signal_type signal,
                /* HB2  = [Bits 7:5 = 0] [Bits 4:0 = Length = 0x09] */
                infopacket->hb2 = 0x09;
 
-               *payload_size = 0x0A;
-
+               *payload_size = 0x09;
        } else if (dc_is_dp_signal(signal)) {
 
                /* HEADER */
@@ -822,9 +813,9 @@ static void build_vrr_infopacket_header_v3(enum signal_type signal,
                infopacket->hb1 = version;
 
                /* HB2  = [Bits 7:5 = 0] [Bits 4:0 = Length] */
-               *payload_size = 0x10;
-               infopacket->hb2 = *payload_size - 1; //-1 for checksum
+               infopacket->hb2 = 0x10;
 
+               *payload_size = 0x10;
        } else if (dc_is_dp_signal(signal)) {
 
                /* HEADER */
index 2ed9579..cf8d60c 100644 (file)
 #define regBIF0_PCIE_TX_TRACKING_ADDR_HI_BASE_IDX                                                       5
 #define regBIF0_PCIE_TX_TRACKING_CTRL_STATUS                                                            0x420186
 #define regBIF0_PCIE_TX_TRACKING_CTRL_STATUS_BASE_IDX                                                   5
+#define regBIF0_PCIE_TX_POWER_CTRL_1                                                                    0x420187
+#define regBIF0_PCIE_TX_POWER_CTRL_1_BASE_IDX                                                           5
 #define regBIF0_PCIE_TX_CTRL_4                                                                          0x42018b
 #define regBIF0_PCIE_TX_CTRL_4_BASE_IDX                                                                 5
 #define regBIF0_PCIE_TX_STATUS                                                                          0x420194
index eb62a18..3d60c9e 100644 (file)
 #define BIF0_PCIE_TX_TRACKING_CTRL_STATUS__TX_TRACKING_PORT_MASK                                              0x0000000EL
 #define BIF0_PCIE_TX_TRACKING_CTRL_STATUS__TX_TRACKING_UNIT_ID_MASK                                           0x00007F00L
 #define BIF0_PCIE_TX_TRACKING_CTRL_STATUS__TX_TRACKING_STATUS_VALID_MASK                                      0x00008000L
+//BIF0_PCIE_TX_POWER_CTRL_1
+#define BIF0_PCIE_TX_POWER_CTRL_1__MST_MEM_LS_EN__SHIFT                                                       0x0
+#define BIF0_PCIE_TX_POWER_CTRL_1__MST_MEM_DS_EN__SHIFT                                                       0x1
+#define BIF0_PCIE_TX_POWER_CTRL_1__MST_MEM_SD_EN__SHIFT                                                       0x2
+#define BIF0_PCIE_TX_POWER_CTRL_1__REPLAY_MEM_LS_EN__SHIFT                                                    0x3
+#define BIF0_PCIE_TX_POWER_CTRL_1__REPLAY_MEM_DS_EN__SHIFT                                                    0x4
+#define BIF0_PCIE_TX_POWER_CTRL_1__REPLAY_MEM_SD_EN__SHIFT                                                    0x5
+#define BIF0_PCIE_TX_POWER_CTRL_1__MST_MEM_LS_EN_MASK                                                         0x00000001L
+#define BIF0_PCIE_TX_POWER_CTRL_1__MST_MEM_DS_EN_MASK                                                         0x00000002L
+#define BIF0_PCIE_TX_POWER_CTRL_1__MST_MEM_SD_EN_MASK                                                         0x00000004L
+#define BIF0_PCIE_TX_POWER_CTRL_1__REPLAY_MEM_LS_EN_MASK                                                      0x00000008L
+#define BIF0_PCIE_TX_POWER_CTRL_1__REPLAY_MEM_DS_EN_MASK                                                      0x00000010L
+#define BIF0_PCIE_TX_POWER_CTRL_1__REPLAY_MEM_SD_EN_MASK                                                      0x00000020L
 //BIF0_PCIE_TX_CTRL_4
 #define BIF0_PCIE_TX_CTRL_4__TX_PORT_ACCESS_TIMER_SKEW__SHIFT                                                 0x0
 #define BIF0_PCIE_TX_CTRL_4__TX_PORT_ACCESS_TIMER_SKEW_MASK                                                   0x0000000FL
index 80dab11..50bfa51 100644 (file)
@@ -268,7 +268,8 @@ union MESAPI__ADD_QUEUE {
                        uint32_t is_tmz_queue           : 1;
                        uint32_t map_kiq_utility_queue  : 1;
                        uint32_t is_kfd_process         : 1;
-                       uint32_t reserved               : 22;
+                       uint32_t trap_en                : 1;
+                       uint32_t reserved               : 21;
                };
                struct MES_API_STATUS           api_status;
                uint64_t                        tma_addr;
index 78620b0..063f4a7 100644 (file)
 #ifndef SMU13_DRIVER_IF_V13_0_0_H
 #define SMU13_DRIVER_IF_V13_0_0_H
 
-// *** IMPORTANT ***
-// PMFW TEAM: Always increment the interface version on any change to this file
-#define SMU13_DRIVER_IF_VERSION  0x23
-
 //Increment this version if SkuTable_t or BoardTable_t change
-#define PPTABLE_VERSION 0x1D
+#define PPTABLE_VERSION 0x24
 
 #define NUM_GFXCLK_DPM_LEVELS    16
 #define NUM_SOCCLK_DPM_LEVELS    8
@@ -1193,8 +1189,17 @@ typedef struct {
   // SECTION: Advanced Options
   uint32_t          DebugOverrides;
 
+  // Section: Total Board Power idle vs active coefficients
+  uint8_t     TotalBoardPowerSupport;
+  uint8_t     TotalBoardPowerPadding[3];
+
+  int16_t     TotalIdleBoardPowerM;
+  int16_t     TotalIdleBoardPowerB;
+  int16_t     TotalBoardPowerM;
+  int16_t     TotalBoardPowerB;
+
   // SECTION: Sku Reserved
-  uint32_t         Spare[64];
+  uint32_t         Spare[61];
 
   // Padding for MMHUB - do not modify this
   uint32_t     MmHubPadding[8];
@@ -1259,7 +1264,8 @@ typedef struct {
   // SECTION: Clock Spread Spectrum
 
   // UCLK Spread Spectrum
-  uint16_t     UclkSpreadPadding;
+  uint8_t      UclkTrainingModeSpreadPercent;
+  uint8_t      UclkSpreadPadding;
   uint16_t     UclkSpreadFreq;      // kHz
 
   // UCLK Spread Spectrum
@@ -1272,11 +1278,7 @@ typedef struct {
 
   // Section: Memory Config
   uint8_t      DramWidth; // Width of interface to the channel for each DRAM module. See DRAM_BIT_WIDTH_TYPE_e
-  uint8_t      PaddingMem1[3];
-
-  // Section: Total Board Power
-  uint16_t     TotalBoardPower;     //Only needed for TCP Estimated case, where TCP = TGP+Total Board Power
-  uint16_t     BoardPowerPadding;
+  uint8_t      PaddingMem1[7];
 
   // SECTION: UMC feature flags
   uint8_t      HsrEnabled;
@@ -1375,8 +1377,11 @@ typedef struct {
   uint16_t Vcn1ActivityPercentage  ;
 
   uint32_t EnergyAccumulator;
-  uint16_t AverageSocketPower    ;
+  uint16_t AverageSocketPower;
+  uint16_t AverageTotalBoardPower;
+
   uint16_t AvgTemperature[TEMP_COUNT];
+  uint16_t TempPadding;
 
   uint8_t  PcieRate               ;
   uint8_t  PcieWidth              ;
index 76f695a..ae2d337 100644 (file)
@@ -27,7 +27,7 @@
 // *** IMPORTANT ***
 // SMU TEAM: Always increment the interface version if
 // any structure is changed in this file
-#define PMFW_DRIVER_IF_VERSION 4
+#define PMFW_DRIVER_IF_VERSION 5
 
 typedef struct {
   int32_t value;
@@ -197,6 +197,8 @@ typedef struct {
 
   uint16_t SkinTemp;
   uint16_t DeviceState;
+  uint16_t CurTemp;                     //[centi-Celsius]
+  uint16_t spare2;
 } SmuMetrics_t;
 
 typedef struct {
index c02e5e5..f442bf0 100644 (file)
@@ -28,9 +28,9 @@
 #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_4 0x04
+#define SMU13_DRIVER_IF_VERSION_SMU_V13_0_4 0x05
 #define SMU13_DRIVER_IF_VERSION_SMU_V13_0_5 0x04
-#define SMU13_DRIVER_IF_VERSION_SMU_V13_0_0 0x2C
+#define SMU13_DRIVER_IF_VERSION_SMU_V13_0_0 0x30
 #define SMU13_DRIVER_IF_VERSION_SMU_V13_0_7 0x2C
 
 #define SMU13_MODE1_RESET_WAIT_TIME_IN_MS 500  //500ms
@@ -291,5 +291,11 @@ int smu_v13_0_set_default_dpm_tables(struct smu_context *smu);
 void smu_v13_0_set_smu_mailbox_registers(struct smu_context *smu);
 
 int smu_v13_0_mode1_reset(struct smu_context *smu);
+
+int smu_v13_0_get_pptable_from_firmware(struct smu_context *smu,
+                                       void **table,
+                                       uint32_t *size,
+                                       uint32_t pptable_id);
+
 #endif
 #endif
index fa520d7..644ea15 100644 (file)
@@ -368,6 +368,17 @@ static void sienna_cichlid_check_bxco_support(struct smu_context *smu)
                smu_baco->platform_support =
                        (val & RCC_BIF_STRAP0__STRAP_PX_CAPABLE_MASK) ? true :
                                                                        false;
+
+               /*
+                * Disable BACO entry/exit completely on below SKUs to
+                * avoid hardware intermittent failures.
+                */
+               if (((adev->pdev->device == 0x73A1) &&
+                   (adev->pdev->revision == 0x00)) ||
+                   ((adev->pdev->device == 0x73BF) &&
+                   (adev->pdev->revision == 0xCF)))
+                       smu_baco->platform_support = false;
+
        }
 }
 
@@ -4283,6 +4294,7 @@ static const struct pptable_funcs sienna_cichlid_ppt_funcs = {
        .dump_pptable = sienna_cichlid_dump_pptable,
        .init_microcode = smu_v11_0_init_microcode,
        .load_microcode = smu_v11_0_load_microcode,
+       .fini_microcode = smu_v11_0_fini_microcode,
        .init_smc_tables = sienna_cichlid_init_smc_tables,
        .fini_smc_tables = smu_v11_0_fini_smc_tables,
        .init_power = smu_v11_0_init_power,
index e8fe84f..24488f4 100644 (file)
@@ -84,9 +84,6 @@ MODULE_FIRMWARE("amdgpu/smu_13_0_7.bin");
 static const int link_width[] = {0, 1, 2, 4, 8, 12, 16};
 static const int link_speed[] = {25, 50, 80, 160};
 
-static int smu_v13_0_get_pptable_from_firmware(struct smu_context *smu, void **table, uint32_t *size,
-                                              uint32_t pptable_id);
-
 int smu_v13_0_init_microcode(struct smu_context *smu)
 {
        struct amdgpu_device *adev = smu->adev;
@@ -212,6 +209,9 @@ int smu_v13_0_init_pptable_microcode(struct smu_context *smu)
        if (!adev->scpm_enabled)
                return 0;
 
+       if (adev->ip_versions[MP1_HWIP][0] == IP_VERSION(13, 0, 7))
+               return 0;
+
        /* override pptable_id from driver parameter */
        if (amdgpu_smu_pptable_id >= 0) {
                pptable_id = amdgpu_smu_pptable_id;
@@ -219,24 +219,17 @@ int smu_v13_0_init_pptable_microcode(struct smu_context *smu)
        } else {
                pptable_id = smu->smu_table.boot_values.pp_table_id;
 
-               if (adev->ip_versions[MP1_HWIP][0] == IP_VERSION(13, 0, 7) &&
-                       pptable_id == 3667)
-                       pptable_id = 36671;
-
-               if (adev->ip_versions[MP1_HWIP][0] == IP_VERSION(13, 0, 7) &&
-                       pptable_id == 3688)
-                       pptable_id = 36881;
                /*
                 * Temporary solution for SMU V13.0.0 with SCPM enabled:
-                *   - use 36831 signed pptable when pp_table_id is 3683
-                *   - use 36641 signed pptable when pp_table_id is 3664 or 0
-                * TODO: drop these when the pptable carried in vbios is ready.
+                *   - use vbios carried pptable when pptable_id is 3664, 3715 or 3795
+                *   - use 36831 soft pptable when pptable_id is 3683
                 */
                if (adev->ip_versions[MP1_HWIP][0] == IP_VERSION(13, 0, 0)) {
                        switch (pptable_id) {
-                       case 0:
                        case 3664:
-                               pptable_id = 36641;
+                       case 3715:
+                       case 3795:
+                               pptable_id = 0;
                                break;
                        case 3683:
                                pptable_id = 36831;
@@ -425,8 +418,10 @@ static int smu_v13_0_get_pptable_from_vbios(struct smu_context *smu, void **tabl
        return 0;
 }
 
-static int smu_v13_0_get_pptable_from_firmware(struct smu_context *smu, void **table, uint32_t *size,
-                                              uint32_t pptable_id)
+int smu_v13_0_get_pptable_from_firmware(struct smu_context *smu,
+                                       void **table,
+                                       uint32_t *size,
+                                       uint32_t pptable_id)
 {
        const struct smc_firmware_header_v1_0 *hdr;
        struct amdgpu_device *adev = smu->adev;
@@ -478,7 +473,7 @@ int smu_v13_0_setup_pptable(struct smu_context *smu)
 
                /*
                 * Temporary solution for SMU V13.0.0 with SCPM disabled:
-                *   - use 3664 or 3683 on request
+                *   - use 3664, 3683 or 3715 on request
                 *   - use 3664 when pptable_id is 0
                 * TODO: drop these when the pptable carried in vbios is ready.
                 */
@@ -489,6 +484,7 @@ int smu_v13_0_setup_pptable(struct smu_context *smu)
                                break;
                        case 3664:
                        case 3683:
+                       case 3715:
                                break;
                        default:
                                dev_err(adev->dev, "Unsupported pptable id %d\n", pptable_id);
@@ -2344,8 +2340,8 @@ int smu_v13_0_set_gfx_power_up_by_imu(struct smu_context *smu)
 
        index = smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_MSG,
                                               SMU_MSG_EnableGfxImu);
-
-       return smu_cmn_send_msg_without_waiting(smu, index, 0);
+       /* Param 1 to tell PMFW to enable GFXOFF feature */
+       return smu_cmn_send_msg_without_waiting(smu, index, 1);
 }
 
 int smu_v13_0_od_edit_dpm_table(struct smu_context *smu,
index 1bbecee..7db2fd9 100644 (file)
@@ -388,11 +388,29 @@ static int smu_v13_0_0_append_powerplay_table(struct smu_context *smu)
        return 0;
 }
 
-static int smu_v13_0_0_setup_pptable(struct smu_context *smu)
+static int smu_v13_0_0_get_pptable_from_pmfw(struct smu_context *smu,
+                                            void **table,
+                                            uint32_t *size)
 {
        struct smu_table_context *smu_table = &smu->smu_table;
        void *combo_pptable = smu_table->combo_pptable;
+       int ret = 0;
+
+       ret = smu_cmn_get_combo_pptable(smu);
+       if (ret)
+               return ret;
+
+       *table = combo_pptable;
+       *size = sizeof(struct smu_13_0_0_powerplay_table);
+
+       return 0;
+}
+
+static int smu_v13_0_0_setup_pptable(struct smu_context *smu)
+{
+       struct smu_table_context *smu_table = &smu->smu_table;
        struct amdgpu_device *adev = smu->adev;
+       uint32_t pptable_id;
        int ret = 0;
 
        /*
@@ -401,17 +419,51 @@ static int smu_v13_0_0_setup_pptable(struct smu_context *smu)
         * rely on the combo pptable(and its revelant SMU message).
         */
        if (adev->scpm_enabled) {
-               ret = smu_cmn_get_combo_pptable(smu);
-               if (ret)
-                       return ret;
-
-               smu->smu_table.power_play_table = combo_pptable;
-               smu->smu_table.power_play_table_size = sizeof(struct smu_13_0_0_powerplay_table);
+               ret = smu_v13_0_0_get_pptable_from_pmfw(smu,
+                                                       &smu_table->power_play_table,
+                                                       &smu_table->power_play_table_size);
        } else {
-               ret = smu_v13_0_setup_pptable(smu);
-               if (ret)
-                       return ret;
+               /* override pptable_id from driver parameter */
+               if (amdgpu_smu_pptable_id >= 0) {
+                       pptable_id = amdgpu_smu_pptable_id;
+                       dev_info(adev->dev, "override pptable id %d\n", pptable_id);
+               } else {
+                       pptable_id = smu_table->boot_values.pp_table_id;
+               }
+
+               /*
+                * Temporary solution for SMU V13.0.0 with SCPM disabled:
+                *   - use vbios carried pptable when pptable_id is 3664, 3715 or 3795
+                *   - use soft pptable when pptable_id is 3683
+                */
+               if (adev->ip_versions[MP1_HWIP][0] == IP_VERSION(13, 0, 0)) {
+                       switch (pptable_id) {
+                       case 3664:
+                       case 3715:
+                       case 3795:
+                               pptable_id = 0;
+                               break;
+                       case 3683:
+                               break;
+                       default:
+                               dev_err(adev->dev, "Unsupported pptable id %d\n", pptable_id);
+                               return -EINVAL;
+                       }
+               }
+
+               /* force using vbios pptable in sriov mode */
+               if ((amdgpu_sriov_vf(adev) || !pptable_id) && (amdgpu_emu_mode != 1))
+                       ret = smu_v13_0_0_get_pptable_from_pmfw(smu,
+                                                               &smu_table->power_play_table,
+                                                               &smu_table->power_play_table_size);
+               else
+                       ret = smu_v13_0_get_pptable_from_firmware(smu,
+                                                                 &smu_table->power_play_table,
+                                                                 &smu_table->power_play_table_size,
+                                                                 pptable_id);
        }
+       if (ret)
+               return ret;
 
        ret = smu_v13_0_0_store_powerplay_table(smu);
        if (ret)
@@ -1792,7 +1844,9 @@ static const struct pptable_funcs smu_v13_0_0_ppt_funcs = {
        .dump_pptable = smu_v13_0_0_dump_pptable,
        .init_microcode = smu_v13_0_init_microcode,
        .load_microcode = smu_v13_0_load_microcode,
+       .fini_microcode = smu_v13_0_fini_microcode,
        .init_smc_tables = smu_v13_0_0_init_smc_tables,
+       .fini_smc_tables = smu_v13_0_fini_smc_tables,
        .init_power = smu_v13_0_init_power,
        .fini_power = smu_v13_0_fini_power,
        .check_fw_status = smu_v13_0_check_fw_status,
index 82d3718..97e1d55 100644 (file)
@@ -71,7 +71,6 @@ static struct cmn2asic_msg_mapping smu_v13_0_4_message_map[SMU_MSG_MAX_COUNT] =
        MSG_MAP(TestMessage,                    PPSMC_MSG_TestMessage,                  1),
        MSG_MAP(GetSmuVersion,                  PPSMC_MSG_GetPmfwVersion,               1),
        MSG_MAP(GetDriverIfVersion,             PPSMC_MSG_GetDriverIfVersion,           1),
-       MSG_MAP(EnableGfxOff,                   PPSMC_MSG_EnableGfxOff,                 1),
        MSG_MAP(AllowGfxOff,                    PPSMC_MSG_AllowGfxOff,                  1),
        MSG_MAP(DisallowGfxOff,                 PPSMC_MSG_DisallowGfxOff,               1),
        MSG_MAP(PowerDownVcn,                   PPSMC_MSG_PowerDownVcn,                 1),
@@ -199,6 +198,9 @@ static int smu_v13_0_4_fini_smc_tables(struct smu_context *smu)
        kfree(smu_table->watermarks_table);
        smu_table->watermarks_table = NULL;
 
+       kfree(smu_table->gpu_metrics_table);
+       smu_table->gpu_metrics_table = NULL;
+
        return 0;
 }
 
@@ -226,18 +228,6 @@ static int smu_v13_0_4_system_features_control(struct smu_context *smu, bool en)
        return ret;
 }
 
-static int smu_v13_0_4_post_smu_init(struct smu_context *smu)
-{
-       struct amdgpu_device *adev = smu->adev;
-       int ret = 0;
-
-       /* allow message will be sent after enable message */
-       ret = smu_cmn_send_smc_msg(smu, SMU_MSG_EnableGfxOff, NULL);
-       if (ret)
-               dev_err(adev->dev, "Failed to Enable GfxOff!\n");
-       return ret;
-}
-
 static ssize_t smu_v13_0_4_get_gpu_metrics(struct smu_context *smu,
                                           void **table)
 {
@@ -1026,7 +1016,6 @@ static const struct pptable_funcs smu_v13_0_4_ppt_funcs = {
        .get_pp_feature_mask = smu_cmn_get_pp_feature_mask,
        .set_driver_table_location = smu_v13_0_set_driver_table_location,
        .gfx_off_control = smu_v13_0_gfx_off_control,
-       .post_init = smu_v13_0_4_post_smu_init,
        .mode2_reset = smu_v13_0_4_mode2_reset,
        .get_dpm_ultimate_freq = smu_v13_0_4_get_dpm_ultimate_freq,
        .od_edit_dpm_table = smu_v13_0_od_edit_dpm_table,
index 47360ef..6644596 100644 (file)
@@ -176,6 +176,9 @@ static int smu_v13_0_5_fini_smc_tables(struct smu_context *smu)
        kfree(smu_table->watermarks_table);
        smu_table->watermarks_table = NULL;
 
+       kfree(smu_table->gpu_metrics_table);
+       smu_table->gpu_metrics_table = NULL;
+
        return 0;
 }
 
index 9dd56e7..c422bf8 100644 (file)
@@ -120,6 +120,7 @@ static struct cmn2asic_msg_mapping smu_v13_0_7_message_map[SMU_MSG_MAX_COUNT] =
        MSG_MAP(DisallowGfxOff,                 PPSMC_MSG_DisallowGfxOff,              0),
        MSG_MAP(Mode1Reset,             PPSMC_MSG_Mode1Reset,                  0),
        MSG_MAP(PrepareMp1ForUnload,            PPSMC_MSG_PrepareMp1ForUnload,         0),
+       MSG_MAP(SetMGpuFanBoostLimitRpm,        PPSMC_MSG_SetMGpuFanBoostLimitRpm,     0),
 };
 
 static struct cmn2asic_mapping smu_v13_0_7_clk_map[SMU_CLK_COUNT] = {
@@ -400,11 +401,27 @@ static int smu_v13_0_7_append_powerplay_table(struct smu_context *smu)
        return 0;
 }
 
+static int smu_v13_0_7_get_pptable_from_pmfw(struct smu_context *smu,
+                                            void **table,
+                                            uint32_t *size)
+{
+       struct smu_table_context *smu_table = &smu->smu_table;
+       void *combo_pptable = smu_table->combo_pptable;
+       int ret = 0;
+
+       ret = smu_cmn_get_combo_pptable(smu);
+       if (ret)
+               return ret;
+
+       *table = combo_pptable;
+       *size = sizeof(struct smu_13_0_7_powerplay_table);
+
+       return 0;
+}
 
 static int smu_v13_0_7_setup_pptable(struct smu_context *smu)
 {
        struct smu_table_context *smu_table = &smu->smu_table;
-       void *combo_pptable = smu_table->combo_pptable;
        struct amdgpu_device *adev = smu->adev;
        int ret = 0;
 
@@ -413,18 +430,11 @@ static int smu_v13_0_7_setup_pptable(struct smu_context *smu)
         * be used directly by driver. To get the raw pptable, we need to
         * rely on the combo pptable(and its revelant SMU message).
         */
-       if (adev->scpm_enabled) {
-               ret = smu_cmn_get_combo_pptable(smu);
-               if (ret)
-                       return ret;
-
-               smu->smu_table.power_play_table = combo_pptable;
-               smu->smu_table.power_play_table_size = sizeof(struct smu_13_0_7_powerplay_table);
-       } else {
-               ret = smu_v13_0_setup_pptable(smu);
-               if (ret)
-                       return ret;
-       }
+       ret = smu_v13_0_7_get_pptable_from_pmfw(smu,
+                                               &smu_table->power_play_table,
+                                               &smu_table->power_play_table_size);
+       if (ret)
+               return ret;
 
        ret = smu_v13_0_7_store_powerplay_table(smu);
        if (ret)
@@ -1567,6 +1577,16 @@ static int smu_v13_0_7_set_mp1_state(struct smu_context *smu,
        return ret;
 }
 
+static bool smu_v13_0_7_is_mode1_reset_supported(struct smu_context *smu)
+{
+       struct amdgpu_device *adev = smu->adev;
+
+       /* SRIOV does not support SMU mode1 reset */
+       if (amdgpu_sriov_vf(adev))
+               return false;
+
+       return true;
+}
 static const struct pptable_funcs smu_v13_0_7_ppt_funcs = {
        .get_allowed_feature_mask = smu_v13_0_7_get_allowed_feature_mask,
        .set_default_dpm_table = smu_v13_0_7_set_default_dpm_table,
@@ -1574,7 +1594,9 @@ static const struct pptable_funcs smu_v13_0_7_ppt_funcs = {
        .dump_pptable = smu_v13_0_7_dump_pptable,
        .init_microcode = smu_v13_0_init_microcode,
        .load_microcode = smu_v13_0_load_microcode,
+       .fini_microcode = smu_v13_0_fini_microcode,
        .init_smc_tables = smu_v13_0_7_init_smc_tables,
+       .fini_smc_tables = smu_v13_0_fini_smc_tables,
        .init_power = smu_v13_0_init_power,
        .fini_power = smu_v13_0_fini_power,
        .check_fw_status = smu_v13_0_7_check_fw_status,
@@ -1624,6 +1646,8 @@ static const struct pptable_funcs smu_v13_0_7_ppt_funcs = {
        .baco_set_state = smu_v13_0_baco_set_state,
        .baco_enter = smu_v13_0_baco_enter,
        .baco_exit = smu_v13_0_baco_exit,
+       .mode1_reset_is_support = smu_v13_0_7_is_mode1_reset_supported,
+       .mode1_reset = smu_v13_0_mode1_reset,
        .set_mp1_state = smu_v13_0_7_set_mp1_state,
 };
 
index 702ea80..39e7004 100644 (file)
@@ -180,7 +180,7 @@ static int lvds_codec_probe(struct platform_device *pdev)
                of_node_put(bus_node);
                if (ret == -ENODEV) {
                        dev_warn(dev, "missing 'data-mapping' DT property\n");
-               } else if (ret) {
+               } else if (ret < 0) {
                        dev_err(dev, "invalid 'data-mapping' DT property\n");
                        return ret;
                } else {
index 4939220..01ee3fe 100644 (file)
@@ -377,8 +377,8 @@ static int vrr_range_show(struct seq_file *m, void *data)
        if (connector->status != connector_status_connected)
                return -ENODEV;
 
-       seq_printf(m, "Min: %u\n", (u8)connector->display_info.monitor_range.min_vfreq);
-       seq_printf(m, "Max: %u\n", (u8)connector->display_info.monitor_range.max_vfreq);
+       seq_printf(m, "Min: %u\n", connector->display_info.monitor_range.min_vfreq);
+       seq_printf(m, "Max: %u\n", connector->display_info.monitor_range.max_vfreq);
 
        return 0;
 }
index bbc25e3..eaa8193 100644 (file)
@@ -5971,12 +5971,14 @@ static void drm_parse_cea_ext(struct drm_connector *connector,
 }
 
 static
-void get_monitor_range(const struct detailed_timing *timing,
-                      void *info_monitor_range)
+void get_monitor_range(const struct detailed_timing *timing, void *c)
 {
-       struct drm_monitor_range_info *monitor_range = info_monitor_range;
+       struct detailed_mode_closure *closure = c;
+       struct drm_display_info *info = &closure->connector->display_info;
+       struct drm_monitor_range_info *monitor_range = &info->monitor_range;
        const struct detailed_non_pixel *data = &timing->data.other_data;
        const struct detailed_data_monitor_range *range = &data->data.range;
+       const struct edid *edid = closure->drm_edid->edid;
 
        if (!is_display_descriptor(timing, EDID_DETAIL_MONITOR_RANGE))
                return;
@@ -5992,18 +5994,28 @@ void get_monitor_range(const struct detailed_timing *timing,
 
        monitor_range->min_vfreq = range->min_vfreq;
        monitor_range->max_vfreq = range->max_vfreq;
+
+       if (edid->revision >= 4) {
+               if (data->pad2 & DRM_EDID_RANGE_OFFSET_MIN_VFREQ)
+                       monitor_range->min_vfreq += 255;
+               if (data->pad2 & DRM_EDID_RANGE_OFFSET_MAX_VFREQ)
+                       monitor_range->max_vfreq += 255;
+       }
 }
 
 static void drm_get_monitor_range(struct drm_connector *connector,
                                  const struct drm_edid *drm_edid)
 {
-       struct drm_display_info *info = &connector->display_info;
+       const struct drm_display_info *info = &connector->display_info;
+       struct detailed_mode_closure closure = {
+               .connector = connector,
+               .drm_edid = drm_edid,
+       };
 
        if (!version_greater(drm_edid, 1, 1))
                return;
 
-       drm_for_each_detailed_block(drm_edid, get_monitor_range,
-                                   &info->monitor_range);
+       drm_for_each_detailed_block(drm_edid, get_monitor_range, &closure);
 
        DRM_DEBUG_KMS("Supported Monitor Refresh rate range is %d Hz - %d Hz\n",
                      info->monitor_range.min_vfreq,
index 86d670c..ad06886 100644 (file)
@@ -168,21 +168,6 @@ void drm_gem_private_object_init(struct drm_device *dev,
 }
 EXPORT_SYMBOL(drm_gem_private_object_init);
 
-static void
-drm_gem_remove_prime_handles(struct drm_gem_object *obj, struct drm_file *filp)
-{
-       /*
-        * Note: obj->dma_buf can't disappear as long as we still hold a
-        * handle reference in obj->handle_count.
-        */
-       mutex_lock(&filp->prime.lock);
-       if (obj->dma_buf) {
-               drm_prime_remove_buf_handle_locked(&filp->prime,
-                                                  obj->dma_buf);
-       }
-       mutex_unlock(&filp->prime.lock);
-}
-
 /**
  * drm_gem_object_handle_free - release resources bound to userspace handles
  * @obj: GEM object to clean up.
@@ -253,7 +238,7 @@ drm_gem_object_release_handle(int id, void *ptr, void *data)
        if (obj->funcs->close)
                obj->funcs->close(obj, file_priv);
 
-       drm_gem_remove_prime_handles(obj, file_priv);
+       drm_prime_remove_buf_handle(&file_priv->prime, id);
        drm_vma_node_revoke(&obj->vma_node, file_priv);
 
        drm_gem_object_handle_put_unlocked(obj);
index 1fbbc19..7bb98e6 100644 (file)
@@ -74,8 +74,8 @@ int drm_prime_fd_to_handle_ioctl(struct drm_device *dev, void *data,
 
 void drm_prime_init_file_private(struct drm_prime_file_private *prime_fpriv);
 void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv);
-void drm_prime_remove_buf_handle_locked(struct drm_prime_file_private *prime_fpriv,
-                                       struct dma_buf *dma_buf);
+void drm_prime_remove_buf_handle(struct drm_prime_file_private *prime_fpriv,
+                                uint32_t handle);
 
 /* drm_drv.c */
 struct drm_minor *drm_minor_acquire(unsigned int minor_id);
index a3f1806..eb09e86 100644 (file)
@@ -190,29 +190,33 @@ static int drm_prime_lookup_buf_handle(struct drm_prime_file_private *prime_fpri
        return -ENOENT;
 }
 
-void drm_prime_remove_buf_handle_locked(struct drm_prime_file_private *prime_fpriv,
-                                       struct dma_buf *dma_buf)
+void drm_prime_remove_buf_handle(struct drm_prime_file_private *prime_fpriv,
+                                uint32_t handle)
 {
        struct rb_node *rb;
 
-       rb = prime_fpriv->dmabufs.rb_node;
+       mutex_lock(&prime_fpriv->lock);
+
+       rb = prime_fpriv->handles.rb_node;
        while (rb) {
                struct drm_prime_member *member;
 
-               member = rb_entry(rb, struct drm_prime_member, dmabuf_rb);
-               if (member->dma_buf == dma_buf) {
+               member = rb_entry(rb, struct drm_prime_member, handle_rb);
+               if (member->handle == handle) {
                        rb_erase(&member->handle_rb, &prime_fpriv->handles);
                        rb_erase(&member->dmabuf_rb, &prime_fpriv->dmabufs);
 
-                       dma_buf_put(dma_buf);
+                       dma_buf_put(member->dma_buf);
                        kfree(member);
-                       return;
-               } else if (member->dma_buf < dma_buf) {
+                       break;
+               } else if (member->handle < handle) {
                        rb = rb->rb_right;
                } else {
                        rb = rb->rb_left;
                }
        }
+
+       mutex_unlock(&prime_fpriv->lock);
 }
 
 void drm_prime_init_file_private(struct drm_prime_file_private *prime_fpriv)
index dd32b48..ce96234 100644 (file)
@@ -581,11 +581,9 @@ static const struct psb_offset cdv_regmap[2] = {
 static int cdv_chip_setup(struct drm_device *dev)
 {
        struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
-       struct pci_dev *pdev = to_pci_dev(dev->dev);
        INIT_WORK(&dev_priv->hotplug_work, cdv_hotplug_work_func);
 
-       if (pci_enable_msi(pdev))
-               dev_warn(dev->dev, "Enabling MSI failed!\n");
+       dev_priv->use_msi = true;
        dev_priv->regmap = cdv_regmap;
        gma_get_core_freq(dev);
        psb_intel_opregion_init(dev);
index dffe374..4b7627a 100644 (file)
@@ -112,12 +112,12 @@ static void psb_gem_free_object(struct drm_gem_object *obj)
 {
        struct psb_gem_object *pobj = to_psb_gem_object(obj);
 
-       drm_gem_object_release(obj);
-
        /* Undo the mmap pin if we are destroying the object */
        if (pobj->mmapping)
                psb_gem_unpin(pobj);
 
+       drm_gem_object_release(obj);
+
        WARN_ON(pobj->in_gart && !pobj->stolen);
 
        release_resource(&pobj->resource);
index bd40c04..2f52ece 100644 (file)
@@ -532,15 +532,18 @@ int gma_crtc_page_flip(struct drm_crtc *crtc,
                WARN_ON(drm_crtc_vblank_get(crtc) != 0);
 
                gma_crtc->page_flip_event = event;
+               spin_unlock_irqrestore(&dev->event_lock, flags);
 
                /* Call this locked if we want an event at vblank interrupt. */
                ret = crtc_funcs->mode_set_base(crtc, crtc->x, crtc->y, old_fb);
                if (ret) {
-                       gma_crtc->page_flip_event = NULL;
-                       drm_crtc_vblank_put(crtc);
+                       spin_lock_irqsave(&dev->event_lock, flags);
+                       if (gma_crtc->page_flip_event) {
+                               gma_crtc->page_flip_event = NULL;
+                               drm_crtc_vblank_put(crtc);
+                       }
+                       spin_unlock_irqrestore(&dev->event_lock, flags);
                }
-
-               spin_unlock_irqrestore(&dev->event_lock, flags);
        } else {
                ret = crtc_funcs->mode_set_base(crtc, crtc->x, crtc->y, old_fb);
        }
index 5923a9c..f90e628 100644 (file)
@@ -501,12 +501,9 @@ static const struct psb_offset oaktrail_regmap[2] = {
 static int oaktrail_chip_setup(struct drm_device *dev)
 {
        struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
-       struct pci_dev *pdev = to_pci_dev(dev->dev);
        int ret;
 
-       if (pci_enable_msi(pdev))
-               dev_warn(dev->dev, "Enabling MSI failed!\n");
-
+       dev_priv->use_msi = true;
        dev_priv->regmap = oaktrail_regmap;
 
        ret = mid_chip_setup(dev);
index b91de6d..6687308 100644 (file)
@@ -139,8 +139,6 @@ static void gma_suspend_pci(struct pci_dev *pdev)
        dev_priv->regs.saveBSM = bsm;
        pci_read_config_dword(pdev, 0xFC, &vbt);
        dev_priv->regs.saveVBT = vbt;
-       pci_read_config_dword(pdev, PSB_PCIx_MSI_ADDR_LOC, &dev_priv->msi_addr);
-       pci_read_config_dword(pdev, PSB_PCIx_MSI_DATA_LOC, &dev_priv->msi_data);
 
        pci_disable_device(pdev);
        pci_set_power_state(pdev, PCI_D3hot);
@@ -168,9 +166,6 @@ static bool gma_resume_pci(struct pci_dev *pdev)
        pci_restore_state(pdev);
        pci_write_config_dword(pdev, 0x5c, dev_priv->regs.saveBSM);
        pci_write_config_dword(pdev, 0xFC, dev_priv->regs.saveVBT);
-       /* restoring MSI address and data in PCIx space */
-       pci_write_config_dword(pdev, PSB_PCIx_MSI_ADDR_LOC, dev_priv->msi_addr);
-       pci_write_config_dword(pdev, PSB_PCIx_MSI_DATA_LOC, dev_priv->msi_data);
        ret = pci_enable_device(pdev);
 
        if (ret != 0)
@@ -223,8 +218,7 @@ int gma_power_resume(struct device *_dev)
        mutex_lock(&power_mutex);
        gma_resume_pci(pdev);
        gma_resume_display(pdev);
-       gma_irq_preinstall(dev);
-       gma_irq_postinstall(dev);
+       gma_irq_install(dev);
        mutex_unlock(&power_mutex);
        return 0;
 }
index 1d8744f..54e756b 100644 (file)
@@ -383,7 +383,7 @@ static int psb_driver_load(struct drm_device *dev, unsigned long flags)
        PSB_WVDC32(0xFFFFFFFF, PSB_INT_MASK_R);
        spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags);
 
-       gma_irq_install(dev, pdev->irq);
+       gma_irq_install(dev);
 
        dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
 
index 0ea3d23..731cc35 100644 (file)
@@ -490,6 +490,7 @@ struct drm_psb_private {
        int rpm_enabled;
 
        /* MID specific */
+       bool use_msi;
        bool has_gct;
        struct oaktrail_gct_data gct_data;
 
@@ -499,10 +500,6 @@ struct drm_psb_private {
        /* Register state */
        struct psb_save_area regs;
 
-       /* MSI reg save */
-       uint32_t msi_addr;
-       uint32_t msi_data;
-
        /* Hotplug handling */
        struct work_struct hotplug_work;
 
index e6e6d61..038f18e 100644 (file)
@@ -316,17 +316,24 @@ void gma_irq_postinstall(struct drm_device *dev)
        spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags);
 }
 
-int gma_irq_install(struct drm_device *dev, unsigned int irq)
+int gma_irq_install(struct drm_device *dev)
 {
+       struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
+       struct pci_dev *pdev = to_pci_dev(dev->dev);
        int ret;
 
-       if (irq == IRQ_NOTCONNECTED)
+       if (dev_priv->use_msi && pci_enable_msi(pdev)) {
+               dev_warn(dev->dev, "Enabling MSI failed!\n");
+               dev_priv->use_msi = false;
+       }
+
+       if (pdev->irq == IRQ_NOTCONNECTED)
                return -ENOTCONN;
 
        gma_irq_preinstall(dev);
 
        /* PCI devices require shared interrupts. */
-       ret = request_irq(irq, gma_irq_handler, IRQF_SHARED, dev->driver->name, dev);
+       ret = request_irq(pdev->irq, gma_irq_handler, IRQF_SHARED, dev->driver->name, dev);
        if (ret)
                return ret;
 
@@ -369,6 +376,8 @@ void gma_irq_uninstall(struct drm_device *dev)
        spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags);
 
        free_irq(pdev->irq, dev);
+       if (dev_priv->use_msi)
+               pci_disable_msi(pdev);
 }
 
 int gma_crtc_enable_vblank(struct drm_crtc *crtc)
index b51e395..7648f69 100644 (file)
@@ -17,7 +17,7 @@ struct drm_device;
 
 void gma_irq_preinstall(struct drm_device *dev);
 void gma_irq_postinstall(struct drm_device *dev);
-int  gma_irq_install(struct drm_device *dev, unsigned int irq);
+int  gma_irq_install(struct drm_device *dev);
 void gma_irq_uninstall(struct drm_device *dev);
 
 int  gma_crtc_enable_vblank(struct drm_crtc *crtc);
index 6d11e79..f84d397 100644 (file)
@@ -23,9 +23,6 @@
 #define DRIVER_MAJOR 1
 #define DRIVER_MINOR 0
 
-#define PCI_VENDOR_ID_MICROSOFT 0x1414
-#define PCI_DEVICE_ID_HYPERV_VIDEO 0x5353
-
 DEFINE_DRM_GEM_FOPS(hv_fops);
 
 static struct drm_driver hyperv_driver = {
@@ -133,7 +130,6 @@ static int hyperv_vmbus_probe(struct hv_device *hdev,
        }
 
        ret = hyperv_setup_vram(hv, hdev);
-
        if (ret)
                goto err_vmbus_close;
 
@@ -150,18 +146,20 @@ static int hyperv_vmbus_probe(struct hv_device *hdev,
 
        ret = hyperv_mode_config_init(hv);
        if (ret)
-               goto err_vmbus_close;
+               goto err_free_mmio;
 
        ret = drm_dev_register(dev, 0);
        if (ret) {
                drm_err(dev, "Failed to register drm driver.\n");
-               goto err_vmbus_close;
+               goto err_free_mmio;
        }
 
        drm_fbdev_generic_setup(dev, 0);
 
        return 0;
 
+err_free_mmio:
+       vmbus_free_mmio(hv->mem->start, hv->fb_size);
 err_vmbus_close:
        vmbus_close(hdev->channel);
 err_hv_set_drv_data:
index 5dcfa7f..1390729 100644 (file)
@@ -1629,6 +1629,8 @@ static int gen11_dsi_dsc_compute_config(struct intel_encoder *encoder,
        /* FIXME: initialize from VBT */
        vdsc_cfg->rc_model_size = DSC_RC_MODEL_SIZE_CONST;
 
+       vdsc_cfg->pic_height = crtc_state->hw.adjusted_mode.crtc_vdisplay;
+
        ret = intel_dsc_compute_params(crtc_state);
        if (ret)
                return ret;
@@ -2070,7 +2072,14 @@ void icl_dsi_init(struct drm_i915_private *dev_priv)
        else
                intel_dsi->ports = BIT(port);
 
+       if (drm_WARN_ON(&dev_priv->drm, intel_connector->panel.vbt.dsi.bl_ports & ~intel_dsi->ports))
+               intel_connector->panel.vbt.dsi.bl_ports &= intel_dsi->ports;
+
        intel_dsi->dcs_backlight_ports = intel_connector->panel.vbt.dsi.bl_ports;
+
+       if (drm_WARN_ON(&dev_priv->drm, intel_connector->panel.vbt.dsi.cabc_ports & ~intel_dsi->ports))
+               intel_connector->panel.vbt.dsi.cabc_ports &= intel_dsi->ports;
+
        intel_dsi->dcs_cabc_ports = intel_connector->panel.vbt.dsi.cabc_ports;
 
        for_each_dsi_port(port, intel_dsi->ports) {
index 110fc98..f5e1d69 100644 (file)
@@ -16,6 +16,7 @@
 #include "intel_dsi_dcs_backlight.h"
 #include "intel_panel.h"
 #include "intel_pci_config.h"
+#include "intel_pps.h"
 
 /**
  * scale - scale values from one range to another
@@ -971,26 +972,24 @@ int intel_backlight_device_register(struct intel_connector *connector)
        if (!name)
                return -ENOMEM;
 
-       bd = backlight_device_register(name, connector->base.kdev, connector,
-                                      &intel_backlight_device_ops, &props);
-
-       /*
-        * Using the same name independent of the drm device or connector
-        * prevents registration of multiple backlight devices in the
-        * driver. However, we need to use the default name for backward
-        * compatibility. Use unique names for subsequent backlight devices as a
-        * fallback when the default name already exists.
-        */
-       if (IS_ERR(bd) && PTR_ERR(bd) == -EEXIST) {
+       bd = backlight_device_get_by_name(name);
+       if (bd) {
+               put_device(&bd->dev);
+               /*
+                * Using the same name independent of the drm device or connector
+                * prevents registration of multiple backlight devices in the
+                * driver. However, we need to use the default name for backward
+                * compatibility. Use unique names for subsequent backlight devices as a
+                * fallback when the default name already exists.
+                */
                kfree(name);
                name = kasprintf(GFP_KERNEL, "card%d-%s-backlight",
                                 i915->drm.primary->index, connector->base.name);
                if (!name)
                        return -ENOMEM;
-
-               bd = backlight_device_register(name, connector->base.kdev, connector,
-                                              &intel_backlight_device_ops, &props);
        }
+       bd = backlight_device_register(name, connector->base.kdev, connector,
+                                      &intel_backlight_device_ops, &props);
 
        if (IS_ERR(bd)) {
                drm_err(&i915->drm,
@@ -1773,9 +1772,13 @@ void intel_backlight_init_funcs(struct intel_panel *panel)
                panel->backlight.pwm_funcs = &i9xx_pwm_funcs;
        }
 
-       if (connector->base.connector_type == DRM_MODE_CONNECTOR_eDP &&
-           intel_dp_aux_init_backlight_funcs(connector) == 0)
-               return;
+       if (connector->base.connector_type == DRM_MODE_CONNECTOR_eDP) {
+               if (intel_dp_aux_init_backlight_funcs(connector) == 0)
+                       return;
+
+               if (!(dev_priv->quirks & QUIRK_NO_PPS_BACKLIGHT_POWER_HOOK))
+                       connector->panel.backlight.power = intel_pps_backlight_power;
+       }
 
        /* We're using a standard PWM backlight interface */
        panel->backlight.funcs = &pwm_bl_funcs;
index 51dde5b..7d6eb9a 100644 (file)
@@ -479,6 +479,13 @@ init_bdb_block(struct drm_i915_private *i915,
 
        block_size = get_blocksize(block);
 
+       /*
+        * Version number and new block size are considered
+        * part of the header for MIPI sequenece block v3+.
+        */
+       if (section_id == BDB_MIPI_SEQUENCE && *(const u8 *)block >= 3)
+               block_size += 5;
+
        entry = kzalloc(struct_size(entry, data, max(min_size, block_size) + 3),
                        GFP_KERNEL);
        if (!entry) {
@@ -1596,6 +1603,8 @@ static void parse_dsi_backlight_ports(struct drm_i915_private *i915,
                                      struct intel_panel *panel,
                                      enum port port)
 {
+       enum port port_bc = DISPLAY_VER(i915) >= 11 ? PORT_B : PORT_C;
+
        if (!panel->vbt.dsi.config->dual_link || i915->vbt.version < 197) {
                panel->vbt.dsi.bl_ports = BIT(port);
                if (panel->vbt.dsi.config->cabc_supported)
@@ -1609,11 +1618,11 @@ static void parse_dsi_backlight_ports(struct drm_i915_private *i915,
                panel->vbt.dsi.bl_ports = BIT(PORT_A);
                break;
        case DL_DCS_PORT_C:
-               panel->vbt.dsi.bl_ports = BIT(PORT_C);
+               panel->vbt.dsi.bl_ports = BIT(port_bc);
                break;
        default:
        case DL_DCS_PORT_A_AND_C:
-               panel->vbt.dsi.bl_ports = BIT(PORT_A) | BIT(PORT_C);
+               panel->vbt.dsi.bl_ports = BIT(PORT_A) | BIT(port_bc);
                break;
        }
 
@@ -1625,12 +1634,12 @@ static void parse_dsi_backlight_ports(struct drm_i915_private *i915,
                panel->vbt.dsi.cabc_ports = BIT(PORT_A);
                break;
        case DL_DCS_PORT_C:
-               panel->vbt.dsi.cabc_ports = BIT(PORT_C);
+               panel->vbt.dsi.cabc_ports = BIT(port_bc);
                break;
        default:
        case DL_DCS_PORT_A_AND_C:
                panel->vbt.dsi.cabc_ports =
-                                       BIT(PORT_A) | BIT(PORT_C);
+                                       BIT(PORT_A) | BIT(port_bc);
                break;
        }
 }
index 79269d2..3699869 100644 (file)
@@ -404,15 +404,17 @@ static int tgl_get_bw_info(struct drm_i915_private *dev_priv, const struct intel
                int clpchgroup;
                int j;
 
-               if (i < num_groups - 1)
-                       bi_next = &dev_priv->max_bw[i + 1];
-
                clpchgroup = (sa->deburst * qi.deinterleave / num_channels) << i;
 
-               if (i < num_groups - 1 && clpchgroup < clperchgroup)
-                       bi_next->num_planes = (ipqdepth - clpchgroup) / clpchgroup + 1;
-               else
-                       bi_next->num_planes = 0;
+               if (i < num_groups - 1) {
+                       bi_next = &dev_priv->max_bw[i + 1];
+
+                       if (clpchgroup < clperchgroup)
+                               bi_next->num_planes = (ipqdepth - clpchgroup) /
+                                                      clpchgroup + 1;
+                       else
+                               bi_next->num_planes = 0;
+               }
 
                bi->num_qgv_points = qi.num_points;
                bi->num_psf_gv_points = qi.num_psf_points;
index 32292c0..3ed7eea 100644 (file)
@@ -389,23 +389,13 @@ static int dg2_max_source_rate(struct intel_dp *intel_dp)
        return intel_dp_is_edp(intel_dp) ? 810000 : 1350000;
 }
 
-static bool is_low_voltage_sku(struct drm_i915_private *i915, enum phy phy)
-{
-       u32 voltage;
-
-       voltage = intel_de_read(i915, ICL_PORT_COMP_DW3(phy)) & VOLTAGE_INFO_MASK;
-
-       return voltage == VOLTAGE_INFO_0_85V;
-}
-
 static int icl_max_source_rate(struct intel_dp *intel_dp)
 {
        struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
        struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
        enum phy phy = intel_port_to_phy(dev_priv, dig_port->base.port);
 
-       if (intel_phy_is_combo(dev_priv, phy) &&
-           (is_low_voltage_sku(dev_priv, phy) || !intel_dp_is_edp(intel_dp)))
+       if (intel_phy_is_combo(dev_priv, phy) && !intel_dp_is_edp(intel_dp))
                return 540000;
 
        return 810000;
@@ -413,23 +403,7 @@ static int icl_max_source_rate(struct intel_dp *intel_dp)
 
 static int ehl_max_source_rate(struct intel_dp *intel_dp)
 {
-       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
-       struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
-       enum phy phy = intel_port_to_phy(dev_priv, dig_port->base.port);
-
-       if (intel_dp_is_edp(intel_dp) || is_low_voltage_sku(dev_priv, phy))
-               return 540000;
-
-       return 810000;
-}
-
-static int dg1_max_source_rate(struct intel_dp *intel_dp)
-{
-       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
-       struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
-       enum phy phy = intel_port_to_phy(i915, dig_port->base.port);
-
-       if (intel_phy_is_combo(i915, phy) && is_low_voltage_sku(i915, phy))
+       if (intel_dp_is_edp(intel_dp))
                return 540000;
 
        return 810000;
@@ -491,7 +465,7 @@ intel_dp_set_source_rates(struct intel_dp *intel_dp)
                        max_rate = dg2_max_source_rate(intel_dp);
                else if (IS_ALDERLAKE_P(dev_priv) || IS_ALDERLAKE_S(dev_priv) ||
                         IS_DG1(dev_priv) || IS_ROCKETLAKE(dev_priv))
-                       max_rate = dg1_max_source_rate(intel_dp);
+                       max_rate = 810000;
                else if (IS_JSL_EHL(dev_priv))
                        max_rate = ehl_max_source_rate(intel_dp);
                else
@@ -1395,6 +1369,7 @@ static int intel_dp_dsc_compute_params(struct intel_encoder *encoder,
         * DP_DSC_RC_BUF_SIZE for this.
         */
        vdsc_cfg->rc_model_size = DSC_RC_MODEL_SIZE_CONST;
+       vdsc_cfg->pic_height = crtc_state->hw.adjusted_mode.crtc_vdisplay;
 
        /*
         * Slice Height of 8 works for all currently available panels. So start
@@ -5293,8 +5268,6 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
 
        intel_panel_init(intel_connector);
 
-       if (!(dev_priv->quirks & QUIRK_NO_PPS_BACKLIGHT_POWER_HOOK))
-               intel_connector->panel.backlight.power = intel_pps_backlight_power;
        intel_backlight_setup(intel_connector, pipe);
 
        intel_edp_add_properties(intel_dp);
index 9feaf1a..d213d8a 100644 (file)
@@ -671,6 +671,28 @@ intel_dp_prepare_link_train(struct intel_dp *intel_dp,
        intel_dp_compute_rate(intel_dp, crtc_state->port_clock,
                              &link_bw, &rate_select);
 
+       /*
+        * WaEdpLinkRateDataReload
+        *
+        * Parade PS8461E MUX (used on varius TGL+ laptops) needs
+        * to snoop the link rates reported by the sink when we
+        * use LINK_RATE_SET in order to operate in jitter cleaning
+        * mode (as opposed to redriver mode). Unfortunately it
+        * loses track of the snooped link rates when powered down,
+        * so we need to make it re-snoop often. Without this high
+        * link rates are not stable.
+        */
+       if (!link_bw) {
+               struct intel_connector *connector = intel_dp->attached_connector;
+               __le16 sink_rates[DP_MAX_SUPPORTED_RATES];
+
+               drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] Reloading eDP link rates\n",
+                           connector->base.base.id, connector->base.name);
+
+               drm_dp_dpcd_read(&intel_dp->aux, DP_SUPPORTED_LINK_RATES,
+                                sink_rates, sizeof(sink_rates));
+       }
+
        if (link_bw)
                drm_dbg_kms(&i915->drm,
                            "[ENCODER:%d:%s] Using LINK_BW_SET value %02x\n",
index c8488f5..e415cd7 100644 (file)
@@ -191,6 +191,9 @@ static struct intel_quirk intel_quirks[] = {
        /* ASRock ITX*/
        { 0x3185, 0x1849, 0x2212, quirk_increase_ddi_disabled_time },
        { 0x3184, 0x1849, 0x2212, quirk_increase_ddi_disabled_time },
+       /* ECS Liva Q2 */
+       { 0x3185, 0x1019, 0xa94d, quirk_increase_ddi_disabled_time },
+       { 0x3184, 0x1019, 0xa94d, quirk_increase_ddi_disabled_time },
 };
 
 void intel_init_quirks(struct drm_i915_private *i915)
index 43e1bbc..ca530f0 100644 (file)
@@ -460,7 +460,6 @@ int intel_dsc_compute_params(struct intel_crtc_state *pipe_config)
        u8 i = 0;
 
        vdsc_cfg->pic_width = pipe_config->hw.adjusted_mode.crtc_hdisplay;
-       vdsc_cfg->pic_height = pipe_config->hw.adjusted_mode.crtc_vdisplay;
        vdsc_cfg->slice_width = DIV_ROUND_UP(vdsc_cfg->pic_width,
                                             pipe_config->dsc.slice_count);
 
index b9b1fed..35136d2 100644 (file)
@@ -1933,7 +1933,14 @@ void vlv_dsi_init(struct drm_i915_private *dev_priv)
        else
                intel_dsi->ports = BIT(port);
 
+       if (drm_WARN_ON(&dev_priv->drm, intel_connector->panel.vbt.dsi.bl_ports & ~intel_dsi->ports))
+               intel_connector->panel.vbt.dsi.bl_ports &= intel_dsi->ports;
+
        intel_dsi->dcs_backlight_ports = intel_connector->panel.vbt.dsi.bl_ports;
+
+       if (drm_WARN_ON(&dev_priv->drm, intel_connector->panel.vbt.dsi.cabc_ports & ~intel_dsi->ports))
+               intel_connector->panel.vbt.dsi.cabc_ports &= intel_dsi->ports;
+
        intel_dsi->dcs_cabc_ports = intel_connector->panel.vbt.dsi.cabc_ports;
 
        /* Create a DSI host (and a device) for each port. */
index ccec405..85482a0 100644 (file)
@@ -268,7 +268,7 @@ static void __i915_gem_object_free_mmaps(struct drm_i915_gem_object *obj)
  */
 void __i915_gem_object_pages_fini(struct drm_i915_gem_object *obj)
 {
-       assert_object_held(obj);
+       assert_object_held_shared(obj);
 
        if (!list_empty(&obj->vma.list)) {
                struct i915_vma *vma;
@@ -331,15 +331,7 @@ static void __i915_gem_free_objects(struct drm_i915_private *i915,
                        continue;
                }
 
-               if (!i915_gem_object_trylock(obj, NULL)) {
-                       /* busy, toss it back to the pile */
-                       if (llist_add(&obj->freed, &i915->mm.free_list))
-                               queue_delayed_work(i915->wq, &i915->mm.free_work, msecs_to_jiffies(10));
-                       continue;
-               }
-
                __i915_gem_object_pages_fini(obj);
-               i915_gem_object_unlock(obj);
                __i915_gem_free_object(obj);
 
                /* But keep the pointer alive for RCU-protected lookups */
@@ -359,7 +351,7 @@ void i915_gem_flush_free_objects(struct drm_i915_private *i915)
 static void __i915_gem_free_work(struct work_struct *work)
 {
        struct drm_i915_private *i915 =
-               container_of(work, struct drm_i915_private, mm.free_work.work);
+               container_of(work, struct drm_i915_private, mm.free_work);
 
        i915_gem_flush_free_objects(i915);
 }
@@ -391,7 +383,7 @@ static void i915_gem_free_object(struct drm_gem_object *gem_obj)
         */
 
        if (llist_add(&obj->freed, &i915->mm.free_list))
-               queue_delayed_work(i915->wq, &i915->mm.free_work, 0);
+               queue_work(i915->wq, &i915->mm.free_work);
 }
 
 void __i915_gem_object_flush_frontbuffer(struct drm_i915_gem_object *obj,
@@ -731,6 +723,9 @@ bool i915_gem_object_needs_ccs_pages(struct drm_i915_gem_object *obj)
        bool lmem_placement = false;
        int i;
 
+       if (!HAS_FLAT_CCS(to_i915(obj->base.dev)))
+               return false;
+
        for (i = 0; i < obj->mm.n_placements; i++) {
                /* Compression is not allowed for the objects with smem placement */
                if (obj->mm.placements[i]->type == INTEL_MEMORY_SYSTEM)
@@ -745,7 +740,7 @@ bool i915_gem_object_needs_ccs_pages(struct drm_i915_gem_object *obj)
 
 void i915_gem_init__objects(struct drm_i915_private *i915)
 {
-       INIT_DELAYED_WORK(&i915->mm.free_work, __i915_gem_free_work);
+       INIT_WORK(&i915->mm.free_work, __i915_gem_free_work);
 }
 
 void i915_objects_module_exit(void)
index 5cf36a1..9f6b14e 100644 (file)
@@ -335,7 +335,6 @@ struct drm_i915_gem_object {
 #define I915_BO_READONLY          BIT(7)
 #define I915_TILING_QUIRK_BIT     8 /* unknown swizzling; do not release! */
 #define I915_BO_PROTECTED         BIT(9)
-#define I915_BO_WAS_BOUND_BIT     10
        /**
         * @mem_flags - Mutable placement-related flags
         *
@@ -616,6 +615,8 @@ struct drm_i915_gem_object {
                 * pages were last acquired.
                 */
                bool dirty:1;
+
+               u32 tlb;
        } mm;
 
        struct {
index 97c820e..8357dbd 100644 (file)
@@ -6,14 +6,15 @@
 
 #include <drm/drm_cache.h>
 
+#include "gt/intel_gt.h"
+#include "gt/intel_gt_pm.h"
+
 #include "i915_drv.h"
 #include "i915_gem_object.h"
 #include "i915_scatterlist.h"
 #include "i915_gem_lmem.h"
 #include "i915_gem_mman.h"
 
-#include "gt/intel_gt.h"
-
 void __i915_gem_object_set_pages(struct drm_i915_gem_object *obj,
                                 struct sg_table *pages,
                                 unsigned int sg_page_sizes)
@@ -190,6 +191,18 @@ static void unmap_object(struct drm_i915_gem_object *obj, void *ptr)
                vunmap(ptr);
 }
 
+static void flush_tlb_invalidate(struct drm_i915_gem_object *obj)
+{
+       struct drm_i915_private *i915 = to_i915(obj->base.dev);
+       struct intel_gt *gt = to_gt(i915);
+
+       if (!obj->mm.tlb)
+               return;
+
+       intel_gt_invalidate_tlb(gt, obj->mm.tlb);
+       obj->mm.tlb = 0;
+}
+
 struct sg_table *
 __i915_gem_object_unset_pages(struct drm_i915_gem_object *obj)
 {
@@ -215,13 +228,7 @@ __i915_gem_object_unset_pages(struct drm_i915_gem_object *obj)
        __i915_gem_object_reset_page_iter(obj);
        obj->mm.page_sizes.phys = obj->mm.page_sizes.sg = 0;
 
-       if (test_and_clear_bit(I915_BO_WAS_BOUND_BIT, &obj->flags)) {
-               struct drm_i915_private *i915 = to_i915(obj->base.dev);
-               intel_wakeref_t wakeref;
-
-               with_intel_runtime_pm_if_active(&i915->runtime_pm, wakeref)
-                       intel_gt_invalidate_tlbs(to_gt(i915));
-       }
+       flush_tlb_invalidate(obj);
 
        return pages;
 }
index f131dc0..6f3ab7a 100644 (file)
@@ -297,7 +297,7 @@ static struct ttm_tt *i915_ttm_tt_create(struct ttm_buffer_object *bo,
                i915_tt->is_shmem = true;
        }
 
-       if (HAS_FLAT_CCS(i915) && i915_gem_object_needs_ccs_pages(obj))
+       if (i915_gem_object_needs_ccs_pages(obj))
                ccs_pages = DIV_ROUND_UP(DIV_ROUND_UP(bo->base.size,
                                                      NUM_BYTES_PER_CCS_BYTE),
                                         PAGE_SIZE);
index 68c2b0d..f435e06 100644 (file)
@@ -11,7 +11,9 @@
 #include "pxp/intel_pxp.h"
 
 #include "i915_drv.h"
+#include "i915_perf_oa_regs.h"
 #include "intel_context.h"
+#include "intel_engine_pm.h"
 #include "intel_engine_regs.h"
 #include "intel_ggtt_gmch.h"
 #include "intel_gt.h"
@@ -36,8 +38,6 @@ static void __intel_gt_init_early(struct intel_gt *gt)
 {
        spin_lock_init(&gt->irq_lock);
 
-       mutex_init(&gt->tlb_invalidate_lock);
-
        INIT_LIST_HEAD(&gt->closed_vma);
        spin_lock_init(&gt->closed_lock);
 
@@ -48,6 +48,8 @@ static void __intel_gt_init_early(struct intel_gt *gt)
        intel_gt_init_reset(gt);
        intel_gt_init_requests(gt);
        intel_gt_init_timelines(gt);
+       mutex_init(&gt->tlb.invalidate_lock);
+       seqcount_mutex_init(&gt->tlb.seqno, &gt->tlb.invalidate_lock);
        intel_gt_pm_init_early(gt);
 
        intel_uc_init_early(&gt->uc);
@@ -768,6 +770,7 @@ void intel_gt_driver_late_release_all(struct drm_i915_private *i915)
                intel_gt_fini_requests(gt);
                intel_gt_fini_reset(gt);
                intel_gt_fini_timelines(gt);
+               mutex_destroy(&gt->tlb.invalidate_lock);
                intel_engines_free(gt);
        }
 }
@@ -906,7 +909,7 @@ get_reg_and_bit(const struct intel_engine_cs *engine, const bool gen8,
        return rb;
 }
 
-void intel_gt_invalidate_tlbs(struct intel_gt *gt)
+static void mmio_invalidate_full(struct intel_gt *gt)
 {
        static const i915_reg_t gen8_regs[] = {
                [RENDER_CLASS]                  = GEN8_RTCR,
@@ -924,13 +927,11 @@ void intel_gt_invalidate_tlbs(struct intel_gt *gt)
        struct drm_i915_private *i915 = gt->i915;
        struct intel_uncore *uncore = gt->uncore;
        struct intel_engine_cs *engine;
+       intel_engine_mask_t awake, tmp;
        enum intel_engine_id id;
        const i915_reg_t *regs;
        unsigned int num = 0;
 
-       if (I915_SELFTEST_ONLY(gt->awake == -ENODEV))
-               return;
-
        if (GRAPHICS_VER(i915) == 12) {
                regs = gen12_regs;
                num = ARRAY_SIZE(gen12_regs);
@@ -945,28 +946,41 @@ void intel_gt_invalidate_tlbs(struct intel_gt *gt)
                          "Platform does not implement TLB invalidation!"))
                return;
 
-       GEM_TRACE("\n");
-
-       assert_rpm_wakelock_held(&i915->runtime_pm);
-
-       mutex_lock(&gt->tlb_invalidate_lock);
        intel_uncore_forcewake_get(uncore, FORCEWAKE_ALL);
 
        spin_lock_irq(&uncore->lock); /* serialise invalidate with GT reset */
 
+       awake = 0;
        for_each_engine(engine, gt, id) {
                struct reg_and_bit rb;
 
+               if (!intel_engine_pm_is_awake(engine))
+                       continue;
+
                rb = get_reg_and_bit(engine, regs == gen8_regs, regs, num);
                if (!i915_mmio_reg_offset(rb.reg))
                        continue;
 
                intel_uncore_write_fw(uncore, rb.reg, rb.bit);
+               awake |= engine->mask;
        }
 
+       GT_TRACE(gt, "invalidated engines %08x\n", awake);
+
+       /* Wa_2207587034:tgl,dg1,rkl,adl-s,adl-p */
+       if (awake &&
+           (IS_TIGERLAKE(i915) ||
+            IS_DG1(i915) ||
+            IS_ROCKETLAKE(i915) ||
+            IS_ALDERLAKE_S(i915) ||
+            IS_ALDERLAKE_P(i915)))
+               intel_uncore_write_fw(uncore, GEN12_OA_TLB_INV_CR, 1);
+
        spin_unlock_irq(&uncore->lock);
 
-       for_each_engine(engine, gt, id) {
+       for_each_engine_masked(engine, gt, awake, tmp) {
+               struct reg_and_bit rb;
+
                /*
                 * HW architecture suggest typical invalidation time at 40us,
                 * with pessimistic cases up to 100us and a recommendation to
@@ -974,12 +988,8 @@ void intel_gt_invalidate_tlbs(struct intel_gt *gt)
                 */
                const unsigned int timeout_us = 100;
                const unsigned int timeout_ms = 4;
-               struct reg_and_bit rb;
 
                rb = get_reg_and_bit(engine, regs == gen8_regs, regs, num);
-               if (!i915_mmio_reg_offset(rb.reg))
-                       continue;
-
                if (__intel_wait_for_register_fw(uncore,
                                                 rb.reg, rb.bit, 0,
                                                 timeout_us, timeout_ms,
@@ -996,5 +1006,38 @@ void intel_gt_invalidate_tlbs(struct intel_gt *gt)
         * transitions.
         */
        intel_uncore_forcewake_put_delayed(uncore, FORCEWAKE_ALL);
-       mutex_unlock(&gt->tlb_invalidate_lock);
+}
+
+static bool tlb_seqno_passed(const struct intel_gt *gt, u32 seqno)
+{
+       u32 cur = intel_gt_tlb_seqno(gt);
+
+       /* Only skip if a *full* TLB invalidate barrier has passed */
+       return (s32)(cur - ALIGN(seqno, 2)) > 0;
+}
+
+void intel_gt_invalidate_tlb(struct intel_gt *gt, u32 seqno)
+{
+       intel_wakeref_t wakeref;
+
+       if (I915_SELFTEST_ONLY(gt->awake == -ENODEV))
+               return;
+
+       if (intel_gt_is_wedged(gt))
+               return;
+
+       if (tlb_seqno_passed(gt, seqno))
+               return;
+
+       with_intel_gt_pm_if_awake(gt, wakeref) {
+               mutex_lock(&gt->tlb.invalidate_lock);
+               if (tlb_seqno_passed(gt, seqno))
+                       goto unlock;
+
+               mmio_invalidate_full(gt);
+
+               write_seqcount_invalidate(&gt->tlb.seqno);
+unlock:
+               mutex_unlock(&gt->tlb.invalidate_lock);
+       }
 }
index 82d6f24..40b06ad 100644 (file)
@@ -101,6 +101,16 @@ void intel_gt_info_print(const struct intel_gt_info *info,
 
 void intel_gt_watchdog_work(struct work_struct *work);
 
-void intel_gt_invalidate_tlbs(struct intel_gt *gt);
+static inline u32 intel_gt_tlb_seqno(const struct intel_gt *gt)
+{
+       return seqprop_sequence(&gt->tlb.seqno);
+}
+
+static inline u32 intel_gt_next_invalidate_tlb_full(const struct intel_gt *gt)
+{
+       return intel_gt_tlb_seqno(gt) | 1;
+}
+
+void intel_gt_invalidate_tlb(struct intel_gt *gt, u32 seqno);
 
 #endif /* __INTEL_GT_H__ */
index bc898df..a334787 100644 (file)
@@ -55,6 +55,9 @@ static inline void intel_gt_pm_might_put(struct intel_gt *gt)
        for (tmp = 1, intel_gt_pm_get(gt); tmp; \
             intel_gt_pm_put(gt), tmp = 0)
 
+#define with_intel_gt_pm_if_awake(gt, wf) \
+       for (wf = intel_gt_pm_get_if_awake(gt); wf; intel_gt_pm_put_async(gt), wf = 0)
+
 static inline int intel_gt_pm_wait_for_idle(struct intel_gt *gt)
 {
        return intel_wakeref_wait_for_idle(&gt->wakeref);
index df70880..3804a58 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/llist.h>
 #include <linux/mutex.h>
 #include <linux/notifier.h>
+#include <linux/seqlock.h>
 #include <linux/spinlock.h>
 #include <linux/types.h>
 #include <linux/workqueue.h>
@@ -83,7 +84,22 @@ struct intel_gt {
        struct intel_uc uc;
        struct intel_gsc gsc;
 
-       struct mutex tlb_invalidate_lock;
+       struct {
+               /* Serialize global tlb invalidations */
+               struct mutex invalidate_lock;
+
+               /*
+                * Batch TLB invalidations
+                *
+                * After unbinding the PTE, we need to ensure the TLB
+                * are invalidated prior to releasing the physical pages.
+                * But we only need one such invalidation for all unbinds,
+                * so we track how many TLB invalidations have been
+                * performed since unbind the PTE and only emit an extra
+                * invalidate if no full barrier has been passed.
+                */
+               seqcount_mutex_t seqno;
+       } tlb;
 
        struct i915_wa_list wa_list;
 
index 14fe658..1d19c07 100644 (file)
@@ -12,6 +12,7 @@
 #include "intel_llc.h"
 #include "intel_mchbar_regs.h"
 #include "intel_pcode.h"
+#include "intel_rps.h"
 
 struct ia_constants {
        unsigned int min_gpu_freq;
@@ -55,9 +56,6 @@ static bool get_ia_constants(struct intel_llc *llc,
        if (!HAS_LLC(i915) || IS_DGFX(i915))
                return false;
 
-       if (rps->max_freq <= rps->min_freq)
-               return false;
-
        consts->max_ia_freq = cpu_max_MHz();
 
        consts->min_ring_freq =
@@ -65,13 +63,8 @@ static bool get_ia_constants(struct intel_llc *llc,
        /* convert DDR frequency from units of 266.6MHz to bandwidth */
        consts->min_ring_freq = mult_frac(consts->min_ring_freq, 8, 3);
 
-       consts->min_gpu_freq = rps->min_freq;
-       consts->max_gpu_freq = rps->max_freq;
-       if (GRAPHICS_VER(i915) >= 9) {
-               /* Convert GT frequency to 50 HZ units */
-               consts->min_gpu_freq /= GEN9_FREQ_SCALER;
-               consts->max_gpu_freq /= GEN9_FREQ_SCALER;
-       }
+       consts->min_gpu_freq = intel_rps_get_min_raw_freq(rps);
+       consts->max_gpu_freq = intel_rps_get_max_raw_freq(rps);
 
        return true;
 }
@@ -131,6 +124,12 @@ static void gen6_update_ring_freq(struct intel_llc *llc)
                return;
 
        /*
+        * Although this is unlikely on any platform during initialization,
+        * let's ensure we don't get accidentally into infinite loop
+        */
+       if (consts.max_gpu_freq <= consts.min_gpu_freq)
+               return;
+       /*
         * For each potential GPU frequency, load a ring frequency we'd like
         * to use for memory access.  We do this by specifying the IA frequency
         * the PCU should use as a reference to determine the ring frequency.
index 2c35324..933648c 100644 (file)
@@ -638,9 +638,9 @@ static int emit_copy(struct i915_request *rq,
        return 0;
 }
 
-static int scatter_list_length(struct scatterlist *sg)
+static u64 scatter_list_length(struct scatterlist *sg)
 {
-       int len = 0;
+       u64 len = 0;
 
        while (sg && sg_dma_len(sg)) {
                len += sg_dma_len(sg);
@@ -650,28 +650,26 @@ static int scatter_list_length(struct scatterlist *sg)
        return len;
 }
 
-static void
+static int
 calculate_chunk_sz(struct drm_i915_private *i915, bool src_is_lmem,
-                  int *src_sz, u32 bytes_to_cpy, u32 ccs_bytes_to_cpy)
+                  u64 bytes_to_cpy, u64 ccs_bytes_to_cpy)
 {
-       if (ccs_bytes_to_cpy) {
-               if (!src_is_lmem)
-                       /*
-                        * When CHUNK_SZ is passed all the pages upto CHUNK_SZ
-                        * will be taken for the blt. in Flat-ccs supported
-                        * platform Smem obj will have more pages than required
-                        * for main meory hence limit it to the required size
-                        * for main memory
-                        */
-                       *src_sz = min_t(int, bytes_to_cpy, CHUNK_SZ);
-       } else { /* ccs handling is not required */
-               *src_sz = CHUNK_SZ;
-       }
+       if (ccs_bytes_to_cpy && !src_is_lmem)
+               /*
+                * When CHUNK_SZ is passed all the pages upto CHUNK_SZ
+                * will be taken for the blt. in Flat-ccs supported
+                * platform Smem obj will have more pages than required
+                * for main meory hence limit it to the required size
+                * for main memory
+                */
+               return min_t(u64, bytes_to_cpy, CHUNK_SZ);
+       else
+               return CHUNK_SZ;
 }
 
-static void get_ccs_sg_sgt(struct sgt_dma *it, u32 bytes_to_cpy)
+static void get_ccs_sg_sgt(struct sgt_dma *it, u64 bytes_to_cpy)
 {
-       u32 len;
+       u64 len;
 
        do {
                GEM_BUG_ON(!it->sg || !sg_dma_len(it->sg));
@@ -702,13 +700,13 @@ intel_context_migrate_copy(struct intel_context *ce,
 {
        struct sgt_dma it_src = sg_sgt(src), it_dst = sg_sgt(dst), it_ccs;
        struct drm_i915_private *i915 = ce->engine->i915;
-       u32 ccs_bytes_to_cpy = 0, bytes_to_cpy;
+       u64 ccs_bytes_to_cpy = 0, bytes_to_cpy;
        enum i915_cache_level ccs_cache_level;
        u32 src_offset, dst_offset;
        u8 src_access, dst_access;
        struct i915_request *rq;
-       int src_sz, dst_sz;
-       bool ccs_is_src;
+       u64 src_sz, dst_sz;
+       bool ccs_is_src, overwrite_ccs;
        int err;
 
        GEM_BUG_ON(ce->vm != ce->engine->gt->migrate.context->vm);
@@ -749,6 +747,8 @@ intel_context_migrate_copy(struct intel_context *ce,
                        get_ccs_sg_sgt(&it_ccs, bytes_to_cpy);
        }
 
+       overwrite_ccs = HAS_FLAT_CCS(i915) && !ccs_bytes_to_cpy && dst_is_lmem;
+
        src_offset = 0;
        dst_offset = CHUNK_SZ;
        if (HAS_64K_PAGES(ce->engine->i915)) {
@@ -788,8 +788,8 @@ intel_context_migrate_copy(struct intel_context *ce,
                if (err)
                        goto out_rq;
 
-               calculate_chunk_sz(i915, src_is_lmem, &src_sz,
-                                  bytes_to_cpy, ccs_bytes_to_cpy);
+               src_sz = calculate_chunk_sz(i915, src_is_lmem,
+                                           bytes_to_cpy, ccs_bytes_to_cpy);
 
                len = emit_pte(rq, &it_src, src_cache_level, src_is_lmem,
                               src_offset, src_sz);
@@ -852,6 +852,25 @@ intel_context_migrate_copy(struct intel_context *ce,
                        if (err)
                                goto out_rq;
                        ccs_bytes_to_cpy -= ccs_sz;
+               } else if (overwrite_ccs) {
+                       err = rq->engine->emit_flush(rq, EMIT_INVALIDATE);
+                       if (err)
+                               goto out_rq;
+
+                       /*
+                        * While we can't always restore/manage the CCS state,
+                        * we still need to ensure we don't leak the CCS state
+                        * from the previous user, so make sure we overwrite it
+                        * with something.
+                        */
+                       err = emit_copy_ccs(rq, dst_offset, INDIRECT_ACCESS,
+                                           dst_offset, DIRECT_ACCESS, len);
+                       if (err)
+                               goto out_rq;
+
+                       err = rq->engine->emit_flush(rq, EMIT_INVALIDATE);
+                       if (err)
+                               goto out_rq;
                }
 
                /* Arbitration is re-enabled between requests. */
index d8b94d6..6ee8d11 100644 (file)
@@ -206,8 +206,12 @@ void ppgtt_bind_vma(struct i915_address_space *vm,
 void ppgtt_unbind_vma(struct i915_address_space *vm,
                      struct i915_vma_resource *vma_res)
 {
-       if (vma_res->allocated)
-               vm->clear_range(vm, vma_res->start, vma_res->vma_size);
+       if (!vma_res->allocated)
+               return;
+
+       vm->clear_range(vm, vma_res->start, vma_res->vma_size);
+       if (vma_res->tlb)
+               vma_invalidate_tlb(vm, vma_res->tlb);
 }
 
 static unsigned long pd_count(u64 size, int shift)
index 6e90032..aa6aed8 100644 (file)
@@ -15,6 +15,7 @@
 #include "gt/intel_gt_mcr.h"
 #include "gt/intel_gt_regs.h"
 
+#ifdef CONFIG_64BIT
 static void _release_bars(struct pci_dev *pdev)
 {
        int resno;
@@ -111,6 +112,9 @@ static void i915_resize_lmem_bar(struct drm_i915_private *i915, resource_size_t
        pci_assign_unassigned_bus_resources(pdev->bus);
        pci_write_config_dword(pdev, PCI_COMMAND, pci_cmd);
 }
+#else
+static void i915_resize_lmem_bar(struct drm_i915_private *i915, resource_size_t lmem_size) {}
+#endif
 
 static int
 region_lmem_release(struct intel_memory_region *mem)
index fb3f57e..7bb9670 100644 (file)
@@ -2126,6 +2126,31 @@ u32 intel_rps_get_max_frequency(struct intel_rps *rps)
                return intel_gpu_freq(rps, rps->max_freq_softlimit);
 }
 
+/**
+ * intel_rps_get_max_raw_freq - returns the max frequency in some raw format.
+ * @rps: the intel_rps structure
+ *
+ * Returns the max frequency in a raw format. In newer platforms raw is in
+ * units of 50 MHz.
+ */
+u32 intel_rps_get_max_raw_freq(struct intel_rps *rps)
+{
+       struct intel_guc_slpc *slpc = rps_to_slpc(rps);
+       u32 freq;
+
+       if (rps_uses_slpc(rps)) {
+               return DIV_ROUND_CLOSEST(slpc->rp0_freq,
+                                        GT_FREQUENCY_MULTIPLIER);
+       } else {
+               freq = rps->max_freq;
+               if (GRAPHICS_VER(rps_to_i915(rps)) >= 9) {
+                       /* Convert GT frequency to 50 MHz units */
+                       freq /= GEN9_FREQ_SCALER;
+               }
+               return freq;
+       }
+}
+
 u32 intel_rps_get_rp0_frequency(struct intel_rps *rps)
 {
        struct intel_guc_slpc *slpc = rps_to_slpc(rps);
@@ -2214,6 +2239,31 @@ u32 intel_rps_get_min_frequency(struct intel_rps *rps)
                return intel_gpu_freq(rps, rps->min_freq_softlimit);
 }
 
+/**
+ * intel_rps_get_min_raw_freq - returns the min frequency in some raw format.
+ * @rps: the intel_rps structure
+ *
+ * Returns the min frequency in a raw format. In newer platforms raw is in
+ * units of 50 MHz.
+ */
+u32 intel_rps_get_min_raw_freq(struct intel_rps *rps)
+{
+       struct intel_guc_slpc *slpc = rps_to_slpc(rps);
+       u32 freq;
+
+       if (rps_uses_slpc(rps)) {
+               return DIV_ROUND_CLOSEST(slpc->min_freq,
+                                        GT_FREQUENCY_MULTIPLIER);
+       } else {
+               freq = rps->min_freq;
+               if (GRAPHICS_VER(rps_to_i915(rps)) >= 9) {
+                       /* Convert GT frequency to 50 MHz units */
+                       freq /= GEN9_FREQ_SCALER;
+               }
+               return freq;
+       }
+}
+
 static int set_min_freq(struct intel_rps *rps, u32 val)
 {
        int ret = 0;
index 1e8d564..4509dfd 100644 (file)
@@ -37,8 +37,10 @@ u32 intel_rps_get_cagf(struct intel_rps *rps, u32 rpstat1);
 u32 intel_rps_read_actual_frequency(struct intel_rps *rps);
 u32 intel_rps_get_requested_frequency(struct intel_rps *rps);
 u32 intel_rps_get_min_frequency(struct intel_rps *rps);
+u32 intel_rps_get_min_raw_freq(struct intel_rps *rps);
 int intel_rps_set_min_frequency(struct intel_rps *rps, u32 val);
 u32 intel_rps_get_max_frequency(struct intel_rps *rps);
+u32 intel_rps_get_max_raw_freq(struct intel_rps *rps);
 int intel_rps_set_max_frequency(struct intel_rps *rps, u32 val);
 u32 intel_rps_get_rp0_frequency(struct intel_rps *rps);
 u32 intel_rps_get_rp1_frequency(struct intel_rps *rps);
index 76916ae..3e91f44 100644 (file)
@@ -1438,7 +1438,12 @@ void intel_guc_busyness_park(struct intel_gt *gt)
        if (!guc_submission_initialized(guc))
                return;
 
-       cancel_delayed_work(&guc->timestamp.work);
+       /*
+        * There is a race with suspend flow where the worker runs after suspend
+        * and causes an unclaimed register access warning. Cancel the worker
+        * synchronously here.
+        */
+       cancel_delayed_work_sync(&guc->timestamp.work);
 
        /*
         * Before parking, we should sample engine busyness stats if we need to.
@@ -4027,6 +4032,13 @@ static inline void guc_init_lrc_mapping(struct intel_guc *guc)
        xa_destroy(&guc->context_lookup);
 
        /*
+        * A reset might have occurred while we had a pending stalled request,
+        * so make sure we clean that up.
+        */
+       guc->stalled_request = NULL;
+       guc->submission_stall_reason = STALL_NONE;
+
+       /*
         * Some contexts might have been pinned before we enabled GuC
         * submission, so we need to add them to the GuC bookeeping.
         * Also, after a reset the of the GuC we want to make sure that the
index 557f331..3b81a6d 100644 (file)
@@ -298,7 +298,7 @@ no_enough_resource:
 }
 
 /**
- * inte_gvt_free_vgpu_resource - free HW resource owned by a vGPU
+ * intel_vgpu_free_resource() - free HW resource owned by a vGPU
  * @vgpu: a vGPU
  *
  * This function is used to free the HW resource owned by a vGPU.
@@ -328,7 +328,7 @@ void intel_vgpu_reset_resource(struct intel_vgpu *vgpu)
 }
 
 /**
- * intel_alloc_vgpu_resource - allocate HW resource for a vGPU
+ * intel_vgpu_alloc_resource() - allocate HW resource for a vGPU
  * @vgpu: vGPU
  * @param: vGPU creation params
  *
index b4f6936..ce0eb03 100644 (file)
@@ -2341,7 +2341,7 @@ static int emulate_ggtt_mmio_write(struct intel_vgpu *vgpu, unsigned int off,
                        gvt_vgpu_err("fail to populate guest ggtt entry\n");
                        /* guest driver may read/write the entry when partial
                         * update the entry in this situation p2m will fail
-                        * settting the shadow entry to point to a scratch page
+                        * setting the shadow entry to point to a scratch page
                         */
                        ops->set_pfn(&m, gvt->gtt.scratch_mfn);
                } else
index beea589..61423da 100644 (file)
@@ -905,7 +905,7 @@ static int update_fdi_rx_iir_status(struct intel_vgpu *vgpu,
        else if (FDI_RX_IMR_TO_PIPE(offset) != INVALID_INDEX)
                index = FDI_RX_IMR_TO_PIPE(offset);
        else {
-               gvt_vgpu_err("Unsupport registers %x\n", offset);
+               gvt_vgpu_err("Unsupported registers %x\n", offset);
                return -EINVAL;
        }
 
@@ -3052,7 +3052,7 @@ int intel_vgpu_default_mmio_read(struct intel_vgpu *vgpu, unsigned int offset,
 }
 
 /**
- * intel_t_default_mmio_write - default MMIO write handler
+ * intel_vgpu_default_mmio_write() - default MMIO write handler
  * @vgpu: a vGPU
  * @offset: access offset
  * @p_data: write data buffer
index c85bafe..1c6e941 100644 (file)
@@ -546,7 +546,7 @@ static void switch_mmio(struct intel_vgpu *pre,
 }
 
 /**
- * intel_gvt_switch_render_mmio - switch mmio context of specific engine
+ * intel_gvt_switch_mmio - switch mmio context of specific engine
  * @pre: the last vGPU that own the engine
  * @next: the vGPU to switch to
  * @engine: the engine
index d25647b..086bbe8 100644 (file)
@@ -247,7 +247,7 @@ struct i915_gem_mm {
         * List of objects which are pending destruction.
         */
        struct llist_head free_list;
-       struct delayed_work free_work;
+       struct work_struct free_work;
        /**
         * Count of objects pending destructions. Used to skip needlessly
         * waiting on an RCU barrier if no objects are waiting to be freed.
@@ -1378,7 +1378,7 @@ static inline void i915_gem_drain_freed_objects(struct drm_i915_private *i915)
         * armed the work again.
         */
        while (atomic_read(&i915->mm.free_count)) {
-               flush_delayed_work(&i915->mm.free_work);
+               flush_work(&i915->mm.free_work);
                flush_delayed_work(&i915->bdev.wq);
                rcu_barrier();
        }
index 3168d70..135d04c 100644 (file)
 
 #define GT0_PERF_LIMIT_REASONS         _MMIO(0x1381a8)
 #define   GT0_PERF_LIMIT_REASONS_MASK  0xde3
-#define   PROCHOT_MASK                 REG_BIT(1)
-#define   THERMAL_LIMIT_MASK           REG_BIT(2)
-#define   RATL_MASK                    REG_BIT(6)
-#define   VR_THERMALERT_MASK           REG_BIT(7)
-#define   VR_TDC_MASK                  REG_BIT(8)
-#define   POWER_LIMIT_4_MASK           REG_BIT(9)
-#define   POWER_LIMIT_1_MASK           REG_BIT(11)
-#define   POWER_LIMIT_2_MASK           REG_BIT(12)
+#define   PROCHOT_MASK                 REG_BIT(0)
+#define   THERMAL_LIMIT_MASK           REG_BIT(1)
+#define   RATL_MASK                    REG_BIT(5)
+#define   VR_THERMALERT_MASK           REG_BIT(6)
+#define   VR_TDC_MASK                  REG_BIT(7)
+#define   POWER_LIMIT_4_MASK           REG_BIT(8)
+#define   POWER_LIMIT_1_MASK           REG_BIT(10)
+#define   POWER_LIMIT_2_MASK           REG_BIT(11)
 
 #define CHV_CLK_CTL1                   _MMIO(0x101100)
 #define VLV_CLK_CTL2                   _MMIO(0x101104)
index ef3b04c..373582c 100644 (file)
@@ -538,8 +538,6 @@ int i915_vma_bind(struct i915_vma *vma,
                                   bind_flags);
        }
 
-       set_bit(I915_BO_WAS_BOUND_BIT, &vma->obj->flags);
-
        atomic_or(bind_flags, &vma->flags);
        return 0;
 }
@@ -1310,6 +1308,19 @@ err_unpin:
        return err;
 }
 
+void vma_invalidate_tlb(struct i915_address_space *vm, u32 *tlb)
+{
+       /*
+        * Before we release the pages that were bound by this vma, we
+        * must invalidate all the TLBs that may still have a reference
+        * back to our physical address. It only needs to be done once,
+        * so after updating the PTE to point away from the pages, record
+        * the most recent TLB invalidation seqno, and if we have not yet
+        * flushed the TLBs upon release, perform a full invalidation.
+        */
+       WRITE_ONCE(*tlb, intel_gt_next_invalidate_tlb_full(vm->gt));
+}
+
 static void __vma_put_pages(struct i915_vma *vma, unsigned int count)
 {
        /* We allocate under vma_get_pages, so beware the shrinker */
@@ -1871,12 +1882,13 @@ int _i915_vma_move_to_active(struct i915_vma *vma,
                enum dma_resv_usage usage;
                int idx;
 
-               obj->read_domains = 0;
                if (flags & EXEC_OBJECT_WRITE) {
                        usage = DMA_RESV_USAGE_WRITE;
                        obj->write_domain = I915_GEM_DOMAIN_RENDER;
+                       obj->read_domains = 0;
                } else {
                        usage = DMA_RESV_USAGE_READ;
+                       obj->write_domain = 0;
                }
 
                dma_fence_array_for_each(curr, idx, fence)
@@ -1941,7 +1953,12 @@ struct dma_fence *__i915_vma_evict(struct i915_vma *vma, bool async)
                vma->vm->skip_pte_rewrite;
        trace_i915_vma_unbind(vma);
 
-       unbind_fence = i915_vma_resource_unbind(vma_res);
+       if (async)
+               unbind_fence = i915_vma_resource_unbind(vma_res,
+                                                       &vma->obj->mm.tlb);
+       else
+               unbind_fence = i915_vma_resource_unbind(vma_res, NULL);
+
        vma->resource = NULL;
 
        atomic_and(~(I915_VMA_BIND_MASK | I915_VMA_ERROR | I915_VMA_GGTT_WRITE),
@@ -1949,10 +1966,13 @@ struct dma_fence *__i915_vma_evict(struct i915_vma *vma, bool async)
 
        i915_vma_detach(vma);
 
-       if (!async && unbind_fence) {
-               dma_fence_wait(unbind_fence, false);
-               dma_fence_put(unbind_fence);
-               unbind_fence = NULL;
+       if (!async) {
+               if (unbind_fence) {
+                       dma_fence_wait(unbind_fence, false);
+                       dma_fence_put(unbind_fence);
+                       unbind_fence = NULL;
+               }
+               vma_invalidate_tlb(vma->vm, &vma->obj->mm.tlb);
        }
 
        /*
index 88ca0bd..33a58f6 100644 (file)
@@ -213,6 +213,7 @@ bool i915_vma_misplaced(const struct i915_vma *vma,
                        u64 size, u64 alignment, u64 flags);
 void __i915_vma_set_map_and_fenceable(struct i915_vma *vma);
 void i915_vma_revoke_mmap(struct i915_vma *vma);
+void vma_invalidate_tlb(struct i915_address_space *vm, u32 *tlb);
 struct dma_fence *__i915_vma_evict(struct i915_vma *vma, bool async);
 int __i915_vma_unbind(struct i915_vma *vma);
 int __must_check i915_vma_unbind(struct i915_vma *vma);
index 27c5502..5a67995 100644 (file)
@@ -223,10 +223,13 @@ i915_vma_resource_fence_notify(struct i915_sw_fence *fence,
  * Return: A refcounted pointer to a dma-fence that signals when unbinding is
  * complete.
  */
-struct dma_fence *i915_vma_resource_unbind(struct i915_vma_resource *vma_res)
+struct dma_fence *i915_vma_resource_unbind(struct i915_vma_resource *vma_res,
+                                          u32 *tlb)
 {
        struct i915_address_space *vm = vma_res->vm;
 
+       vma_res->tlb = tlb;
+
        /* Reference for the sw fence */
        i915_vma_resource_get(vma_res);
 
index 5d8427c..06923d1 100644 (file)
@@ -67,6 +67,7 @@ struct i915_page_sizes {
  * taken when the unbind is scheduled.
  * @skip_pte_rewrite: During ggtt suspend and vm takedown pte rewriting
  * needs to be skipped for unbind.
+ * @tlb: pointer for obj->mm.tlb, if async unbind. Otherwise, NULL
  *
  * The lifetime of a struct i915_vma_resource is from a binding request to
  * the actual possible asynchronous unbind has completed.
@@ -119,6 +120,8 @@ struct i915_vma_resource {
        bool immediate_unbind:1;
        bool needs_wakeref:1;
        bool skip_pte_rewrite:1;
+
+       u32 *tlb;
 };
 
 bool i915_vma_resource_hold(struct i915_vma_resource *vma_res,
@@ -131,7 +134,8 @@ struct i915_vma_resource *i915_vma_resource_alloc(void);
 
 void i915_vma_resource_free(struct i915_vma_resource *vma_res);
 
-struct dma_fence *i915_vma_resource_unbind(struct i915_vma_resource *vma_res);
+struct dma_fence *i915_vma_resource_unbind(struct i915_vma_resource *vma_res,
+                                          u32 *tlb);
 
 void __i915_vma_resource_init(struct i915_vma_resource *vma_res);
 
index 157e166..5595639 100644 (file)
@@ -1076,7 +1076,8 @@ static int iterate_skl_plus_mmio(struct intel_gvt_mmio_table_iter *iter)
        MMIO_D(GEN8_HDC_CHICKEN1);
        MMIO_D(GEN9_WM_CHICKEN3);
 
-       if (IS_KABYLAKE(dev_priv) || IS_COFFEELAKE(dev_priv))
+       if (IS_KABYLAKE(dev_priv) ||
+           IS_COFFEELAKE(dev_priv) || IS_COMETLAKE(dev_priv))
                MMIO_D(GAMT_CHKN_BIT_REG);
        if (!IS_BROXTON(dev_priv))
                MMIO_D(GEN9_CTX_PREEMPT_REG);
index f06babd..9fe4b58 100644 (file)
@@ -6561,7 +6561,10 @@ void skl_wm_get_hw_state(struct drm_i915_private *dev_priv)
                enum plane_id plane_id;
                u8 slices;
 
-               skl_pipe_wm_get_hw_state(crtc, &crtc_state->wm.skl.optimal);
+               memset(&crtc_state->wm.skl.optimal, 0,
+                      sizeof(crtc_state->wm.skl.optimal));
+               if (crtc_state->hw.active)
+                       skl_pipe_wm_get_hw_state(crtc, &crtc_state->wm.skl.optimal);
                crtc_state->wm.skl.raw = crtc_state->wm.skl.optimal;
 
                memset(&dbuf_state->ddb[pipe], 0, sizeof(dbuf_state->ddb[pipe]));
@@ -6572,6 +6575,9 @@ void skl_wm_get_hw_state(struct drm_i915_private *dev_priv)
                        struct skl_ddb_entry *ddb_y =
                                &crtc_state->wm.skl.plane_ddb_y[plane_id];
 
+                       if (!crtc_state->hw.active)
+                               continue;
+
                        skl_ddb_get_hw_plane_state(dev_priv, crtc->pipe,
                                                   plane_id, ddb, ddb_y);
 
index 9b84df3..8cf3352 100644 (file)
@@ -142,8 +142,6 @@ struct dcss_kms_dev *dcss_kms_attach(struct dcss_dev *dcss)
 
        drm_kms_helper_poll_init(drm);
 
-       drm_bridge_connector_enable_hpd(kms->connector);
-
        ret = drm_dev_register(drm, 0);
        if (ret)
                goto cleanup_crtc;
index 1b70938..bd4ca11 100644 (file)
@@ -115,8 +115,11 @@ static bool meson_vpu_has_available_connectors(struct device *dev)
        for_each_endpoint_of_node(dev->of_node, ep) {
                /* If the endpoint node exists, consider it enabled */
                remote = of_graph_get_remote_port(ep);
-               if (remote)
+               if (remote) {
+                       of_node_put(remote);
+                       of_node_put(ep);
                        return true;
+               }
        }
 
        return false;
index b9ac932..03acc68 100644 (file)
@@ -170,7 +170,7 @@ static void meson_plane_atomic_update(struct drm_plane *plane,
 
        /* Enable OSD and BLK0, set max global alpha */
        priv->viu.osd1_ctrl_stat = OSD_ENABLE |
-                                  (0xFF << OSD_GLOBAL_ALPHA_SHIFT) |
+                                  (0x100 << OSD_GLOBAL_ALPHA_SHIFT) |
                                   OSD_BLK0_ENABLE;
 
        priv->viu.osd1_ctrl_stat2 = readl(priv->io_base +
index bb7e109..d4b9078 100644 (file)
@@ -94,7 +94,7 @@ static void meson_viu_set_g12a_osd1_matrix(struct meson_drm *priv,
                priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF11_12));
        writel(((m[9] & 0x1fff) << 16) | (m[10] & 0x1fff),
                priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF20_21));
-       writel((m[11] & 0x1fff) << 16,
+       writel((m[11] & 0x1fff),
                priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF22));
 
        writel(((m[18] & 0xfff) << 16) | (m[19] & 0xfff),
index c682d4e..52a6261 100644 (file)
@@ -2061,6 +2061,12 @@ void dpu_encoder_helper_phys_cleanup(struct dpu_encoder_phys *phys_enc)
 
        intf_cfg.stream_sel = 0; /* Don't care value for video mode */
        intf_cfg.mode_3d = dpu_encoder_helper_get_3d_blend_mode(phys_enc);
+
+       if (phys_enc->hw_intf)
+               intf_cfg.intf = phys_enc->hw_intf->idx;
+       if (phys_enc->hw_wb)
+               intf_cfg.wb = phys_enc->hw_wb->idx;
+
        if (phys_enc->hw_pp->merge_3d)
                intf_cfg.merge_3d = phys_enc->hw_pp->merge_3d->idx;
 
index ab6aa13..013ca02 100644 (file)
@@ -1214,7 +1214,7 @@ static int dp_ctrl_link_train_2(struct dp_ctrl_private *ctrl,
        if (ret)
                return ret;
 
-       dp_ctrl_train_pattern_set(ctrl, pattern | DP_RECOVERED_CLOCK_OUT_EN);
+       dp_ctrl_train_pattern_set(ctrl, pattern);
 
        for (tries = 0; tries <= maximum_retries; tries++) {
                drm_dp_link_train_channel_eq_delay(ctrl->aux, ctrl->panel->dpcd);
index 2c23324..72c018e 100644 (file)
@@ -109,7 +109,7 @@ static const char * const dsi_8996_bus_clk_names[] = {
 static const struct msm_dsi_config msm8996_dsi_cfg = {
        .io_offset = DSI_6G_REG_SHIFT,
        .reg_cfg = {
-               .num = 2,
+               .num = 3,
                .regs = {
                        {"vdda", 18160, 1 },    /* 1.25 V */
                        {"vcca", 17000, 32 },   /* 0.925 V */
@@ -148,7 +148,7 @@ static const char * const dsi_sdm660_bus_clk_names[] = {
 static const struct msm_dsi_config sdm660_dsi_cfg = {
        .io_offset = DSI_6G_REG_SHIFT,
        .reg_cfg = {
-               .num = 2,
+               .num = 1,
                .regs = {
                        {"vdda", 12560, 4 },    /* 1.2 V */
                },
index a39de3b..56dfa2d 100644 (file)
@@ -347,7 +347,7 @@ int msm_dsi_dphy_timing_calc_v3(struct msm_dsi_dphy_timing *timing,
        } else {
                timing->shared_timings.clk_pre =
                        linear_inter(tmax, tmin, pcnt2, 0, false);
-                       timing->shared_timings.clk_pre_inc_by_2 = 0;
+               timing->shared_timings.clk_pre_inc_by_2 = 0;
        }
 
        timing->ta_go = 3;
index 1ed4cd0..16884db 100644 (file)
@@ -469,6 +469,8 @@ static int msm_drm_init(struct device *dev, const struct drm_driver *drv)
                }
        }
 
+       drm_helper_move_panel_connectors_to_head(ddev);
+
        ddev->mode_config.funcs = &mode_config_funcs;
        ddev->mode_config.helper_private = &mode_config_helper_funcs;
 
index d1f7042..85c443a 100644 (file)
@@ -213,6 +213,8 @@ void msm_devfreq_init(struct msm_gpu *gpu)
 
        if (IS_ERR(df->devfreq)) {
                DRM_DEV_ERROR(&gpu->pdev->dev, "Couldn't initialize GPU devfreq\n");
+               dev_pm_qos_remove_request(&df->idle_freq);
+               dev_pm_qos_remove_request(&df->boost_freq);
                df->devfreq = NULL;
                return;
        }
index a92ffde..db2f847 100644 (file)
@@ -196,6 +196,9 @@ static int rd_open(struct inode *inode, struct file *file)
        file->private_data = rd;
        rd->open = true;
 
+       /* Reset fifo to clear any previously unread data: */
+       rd->fifo.head = rd->fifo.tail = 0;
+
        /* the parsing tools need to know gpu-id to know which
         * register database to load.
         *
index 05076e5..e29175e 100644 (file)
@@ -820,6 +820,15 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict,
                if (ret == 0) {
                        ret = nouveau_fence_new(chan, false, &fence);
                        if (ret == 0) {
+                               /* TODO: figure out a better solution here
+                                *
+                                * wait on the fence here explicitly as going through
+                                * ttm_bo_move_accel_cleanup somehow doesn't seem to do it.
+                                *
+                                * Without this the operation can timeout and we'll fallback to a
+                                * software copy, which might take several minutes to finish.
+                                */
+                               nouveau_fence_wait(fence, false, false);
                                ret = ttm_bo_move_accel_cleanup(bo,
                                                                &fence->base,
                                                                evict, false,
index 568182e..d8cf71f 100644 (file)
@@ -2605,6 +2605,27 @@ nv172_chipset = {
 };
 
 static const struct nvkm_device_chip
+nv173_chipset = {
+       .name = "GA103",
+       .bar      = { 0x00000001, tu102_bar_new },
+       .bios     = { 0x00000001, nvkm_bios_new },
+       .devinit  = { 0x00000001, ga100_devinit_new },
+       .fb       = { 0x00000001, ga102_fb_new },
+       .gpio     = { 0x00000001, ga102_gpio_new },
+       .i2c      = { 0x00000001, gm200_i2c_new },
+       .imem     = { 0x00000001, nv50_instmem_new },
+       .mc       = { 0x00000001, ga100_mc_new },
+       .mmu      = { 0x00000001, tu102_mmu_new },
+       .pci      = { 0x00000001, gp100_pci_new },
+       .privring = { 0x00000001, gm200_privring_new },
+       .timer    = { 0x00000001, gk20a_timer_new },
+       .top      = { 0x00000001, ga100_top_new },
+       .disp     = { 0x00000001, ga102_disp_new },
+       .dma      = { 0x00000001, gv100_dma_new },
+       .fifo     = { 0x00000001, ga102_fifo_new },
+};
+
+static const struct nvkm_device_chip
 nv174_chipset = {
        .name = "GA104",
        .bar      = { 0x00000001, tu102_bar_new },
@@ -3067,6 +3088,7 @@ nvkm_device_ctor(const struct nvkm_device_func *func,
                case 0x167: device->chip = &nv167_chipset; break;
                case 0x168: device->chip = &nv168_chipset; break;
                case 0x172: device->chip = &nv172_chipset; break;
+               case 0x173: device->chip = &nv173_chipset; break;
                case 0x174: device->chip = &nv174_chipset; break;
                case 0x176: device->chip = &nv176_chipset; break;
                case 0x177: device->chip = &nv177_chipset; break;
index cdb154c..b75c690 100644 (file)
@@ -1295,7 +1295,8 @@ static const struct panel_desc innolux_n116bca_ea1 = {
        },
        .delay = {
                .hpd_absent = 200,
-               .prepare_to_enable = 80,
+               .enable = 80,
+               .disable = 50,
                .unprepare = 500,
        },
 };
index 5110cd9..fe5f12f 100644 (file)
@@ -131,6 +131,17 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev)
                return PTR_ERR(opp);
 
        panfrost_devfreq_profile.initial_freq = cur_freq;
+
+       /*
+        * Set the recommend OPP this will enable and configure the regulator
+        * if any and will avoid a switch off by regulator_late_cleanup()
+        */
+       ret = dev_pm_opp_set_opp(dev, opp);
+       if (ret) {
+               DRM_DEV_ERROR(dev, "Couldn't set recommended OPP\n");
+               return ret;
+       }
+
        dev_pm_opp_put(opp);
 
        /*
index 2b12389..ee01656 100644 (file)
@@ -1605,6 +1605,9 @@ int radeon_suspend_kms(struct drm_device *dev, bool suspend,
                if (r) {
                        /* delay GPU reset to resume */
                        radeon_fence_driver_force_completion(rdev, i);
+               } else {
+                       /* finish executing delayed work */
+                       flush_delayed_work(&rdev->fence_drv[i].lockup_work);
                }
        }
 
index c204e9b..518ee13 100644 (file)
@@ -283,8 +283,9 @@ static int cdn_dp_connector_get_modes(struct drm_connector *connector)
        return ret;
 }
 
-static int cdn_dp_connector_mode_valid(struct drm_connector *connector,
-                                      struct drm_display_mode *mode)
+static enum drm_mode_status
+cdn_dp_connector_mode_valid(struct drm_connector *connector,
+                           struct drm_display_mode *mode)
 {
        struct cdn_dp_device *dp = connector_to_dp(connector);
        struct drm_display_info *display_info = &dp->connector.display_info;
index e4631f5..f9aa8b9 100644 (file)
@@ -1439,11 +1439,15 @@ static void rk3568_set_intf_mux(struct vop2_video_port *vp, int id,
                die &= ~RK3568_SYS_DSP_INFACE_EN_HDMI_MUX;
                die |= RK3568_SYS_DSP_INFACE_EN_HDMI |
                           FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_HDMI_MUX, vp->id);
+               dip &= ~RK3568_DSP_IF_POL__HDMI_PIN_POL;
+               dip |= FIELD_PREP(RK3568_DSP_IF_POL__HDMI_PIN_POL, polflags);
                break;
        case ROCKCHIP_VOP2_EP_EDP0:
                die &= ~RK3568_SYS_DSP_INFACE_EN_EDP_MUX;
                die |= RK3568_SYS_DSP_INFACE_EN_EDP |
                           FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_EDP_MUX, vp->id);
+               dip &= ~RK3568_DSP_IF_POL__EDP_PIN_POL;
+               dip |= FIELD_PREP(RK3568_DSP_IF_POL__EDP_PIN_POL, polflags);
                break;
        case ROCKCHIP_VOP2_EP_MIPI0:
                die &= ~RK3568_SYS_DSP_INFACE_EN_MIPI0_MUX;
index b4dfa16..34234a1 100644 (file)
@@ -531,7 +531,7 @@ static void sun6i_dsi_setup_timings(struct sun6i_dsi *dsi,
                                    struct drm_display_mode *mode)
 {
        struct mipi_dsi_device *device = dsi->device;
-       unsigned int Bpp = mipi_dsi_pixel_format_to_bpp(device->format) / 8;
+       int Bpp = mipi_dsi_pixel_format_to_bpp(device->format) / 8;
        u16 hbp = 0, hfp = 0, hsa = 0, hblk = 0, vblk = 0;
        u32 basic_ctl = 0;
        size_t bytes;
@@ -555,7 +555,7 @@ static void sun6i_dsi_setup_timings(struct sun6i_dsi *dsi,
                 * (4 bytes). Its minimal size is therefore 10 bytes
                 */
 #define HSA_PACKET_OVERHEAD    10
-               hsa = max((unsigned int)HSA_PACKET_OVERHEAD,
+               hsa = max(HSA_PACKET_OVERHEAD,
                          (mode->hsync_end - mode->hsync_start) * Bpp - HSA_PACKET_OVERHEAD);
 
                /*
@@ -564,7 +564,7 @@ static void sun6i_dsi_setup_timings(struct sun6i_dsi *dsi,
                 * therefore 6 bytes
                 */
 #define HBP_PACKET_OVERHEAD    6
-               hbp = max((unsigned int)HBP_PACKET_OVERHEAD,
+               hbp = max(HBP_PACKET_OVERHEAD,
                          (mode->htotal - mode->hsync_end) * Bpp - HBP_PACKET_OVERHEAD);
 
                /*
@@ -574,7 +574,7 @@ static void sun6i_dsi_setup_timings(struct sun6i_dsi *dsi,
                 * 16 bytes
                 */
 #define HFP_PACKET_OVERHEAD    16
-               hfp = max((unsigned int)HFP_PACKET_OVERHEAD,
+               hfp = max(HFP_PACKET_OVERHEAD,
                          (mode->hsync_start - mode->hdisplay) * Bpp - HFP_PACKET_OVERHEAD);
 
                /*
@@ -583,7 +583,7 @@ static void sun6i_dsi_setup_timings(struct sun6i_dsi *dsi,
                 * bytes). Its minimal size is therefore 10 bytes.
                 */
 #define HBLK_PACKET_OVERHEAD   10
-               hblk = max((unsigned int)HBLK_PACKET_OVERHEAD,
+               hblk = max(HBLK_PACKET_OVERHEAD,
                           (mode->htotal - (mode->hsync_end - mode->hsync_start)) * Bpp -
                           HBLK_PACKET_OVERHEAD);
 
index 0e210df..97184c3 100644 (file)
@@ -912,7 +912,7 @@ int ttm_bo_validate(struct ttm_buffer_object *bo,
        /*
         * We might need to add a TTM.
         */
-       if (bo->resource->mem_type == TTM_PL_SYSTEM) {
+       if (!bo->resource || bo->resource->mem_type == TTM_PL_SYSTEM) {
                ret = ttm_tt_create(bo, true);
                if (ret)
                        return ret;
index 1cbfb00..911141d 100644 (file)
@@ -236,16 +236,19 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo,
        if (bo->type != ttm_bo_type_sg)
                fbo->base.base.resv = &fbo->base.base._resv;
 
-       if (fbo->base.resource) {
-               ttm_resource_set_bo(fbo->base.resource, &fbo->base);
-               bo->resource = NULL;
-       }
-
        dma_resv_init(&fbo->base.base._resv);
        fbo->base.base.dev = NULL;
        ret = dma_resv_trylock(&fbo->base.base._resv);
        WARN_ON(!ret);
 
+       if (fbo->base.resource) {
+               ttm_resource_set_bo(fbo->base.resource, &fbo->base);
+               bo->resource = NULL;
+               ttm_bo_set_bulk_move(&fbo->base, NULL);
+       } else {
+               fbo->base.bulk_move = NULL;
+       }
+
        ret = dma_resv_reserve_fences(&fbo->base.base._resv, 1);
        if (ret) {
                kfree(fbo);
index 061be9a..b0f3117 100644 (file)
@@ -8,6 +8,7 @@ config DRM_VC4
        depends on DRM
        depends on SND && SND_SOC
        depends on COMMON_CLK
+       depends on PM
        select DRM_DISPLAY_HDMI_HELPER
        select DRM_DISPLAY_HELPER
        select DRM_KMS_HELPER
index 592c3b5..1e5f687 100644 (file)
@@ -2855,7 +2855,7 @@ static int vc5_hdmi_init_resources(struct vc4_hdmi *vc4_hdmi)
        return 0;
 }
 
-static int __maybe_unused vc4_hdmi_runtime_suspend(struct device *dev)
+static int vc4_hdmi_runtime_suspend(struct device *dev)
 {
        struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev);
 
@@ -2972,17 +2972,15 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
                        vc4_hdmi->disable_4kp60 = true;
        }
 
+       pm_runtime_enable(dev);
+
        /*
-        * We need to have the device powered up at this point to call
-        * our reset hook and for the CEC init.
+        *  We need to have the device powered up at this point to call
+        *  our reset hook and for the CEC init.
         */
-       ret = vc4_hdmi_runtime_resume(dev);
+       ret = pm_runtime_resume_and_get(dev);
        if (ret)
-               goto err_put_ddc;
-
-       pm_runtime_get_noresume(dev);
-       pm_runtime_set_active(dev);
-       pm_runtime_enable(dev);
+               goto err_disable_runtime_pm;
 
        if ((of_device_is_compatible(dev->of_node, "brcm,bcm2711-hdmi0") ||
             of_device_is_compatible(dev->of_node, "brcm,bcm2711-hdmi1")) &&
@@ -3028,6 +3026,7 @@ err_destroy_conn:
 err_destroy_encoder:
        drm_encoder_cleanup(encoder);
        pm_runtime_put_sync(dev);
+err_disable_runtime_pm:
        pm_runtime_disable(dev);
 err_put_ddc:
        put_device(&vc4_hdmi->ddc->dev);
index 4b90c86..47774b9 100644 (file)
@@ -288,11 +288,29 @@ int amd_sfh_irq_init(struct amd_mp2_dev *privdata)
        return 0;
 }
 
+static const struct dmi_system_id dmi_nodevs[] = {
+       {
+               /*
+                * Google Chromebooks use Chrome OS Embedded Controller Sensor
+                * Hub instead of Sensor Hub Fusion and leaves MP2
+                * uninitialized, which disables all functionalities, even
+                * including the registers necessary for feature detections.
+                */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Google"),
+               },
+       },
+       { }
+};
+
 static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        struct amd_mp2_dev *privdata;
        int rc;
 
+       if (dmi_first_match(dmi_nodevs))
+               return -ENODEV;
+
        privdata = devm_kzalloc(&pdev->dev, sizeof(*privdata), GFP_KERNEL);
        if (!privdata)
                return -ENOMEM;
index 08c9a9a..b59c3da 100644 (file)
@@ -1212,6 +1212,13 @@ static __u8 *asus_report_fixup(struct hid_device *hdev, __u8 *rdesc,
                rdesc = new_rdesc;
        }
 
+       if (drvdata->quirks & QUIRK_ROG_NKEY_KEYBOARD &&
+                       *rsize == 331 && rdesc[190] == 0x85 && rdesc[191] == 0x5a &&
+                       rdesc[204] == 0x95 && rdesc[205] == 0x05) {
+               hid_info(hdev, "Fixing up Asus N-KEY keyb report descriptor\n");
+               rdesc[205] = 0x01;
+       }
+
        return rdesc;
 }
 
index 0fb720a..f80d619 100644 (file)
 #define USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021   0x029c
 #define USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2021   0x029a
 #define USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2021   0x029f
+#define USB_DEVICE_ID_APPLE_TOUCHBAR_BACKLIGHT 0x8102
+#define USB_DEVICE_ID_APPLE_TOUCHBAR_DISPLAY 0x8302
 
 #define USB_VENDOR_ID_ASUS             0x0486
 #define USB_DEVICE_ID_ASUS_T91MT       0x0185
 #define USB_DEVICE_ID_ASUS_UX550_TOUCHSCREEN   0x2706
 #define I2C_DEVICE_ID_SURFACE_GO_TOUCHSCREEN   0x261A
 #define I2C_DEVICE_ID_SURFACE_GO2_TOUCHSCREEN  0x2A1C
+#define I2C_DEVICE_ID_LENOVO_YOGA_C630_TOUCHSCREEN     0x279F
 
 #define USB_VENDOR_ID_ELECOM           0x056e
 #define USB_DEVICE_ID_ELECOM_BM084     0x0061
index 48c1c02..859aeb0 100644 (file)
@@ -383,6 +383,8 @@ static const struct hid_device_id hid_battery_quirks[] = {
          HID_BATTERY_QUIRK_IGNORE },
        { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_SURFACE_GO2_TOUCHSCREEN),
          HID_BATTERY_QUIRK_IGNORE },
+       { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_LENOVO_YOGA_C630_TOUCHSCREEN),
+         HID_BATTERY_QUIRK_IGNORE },
        {}
 };
 
@@ -1532,7 +1534,10 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
                         * assume ours
                         */
                        if (!report->tool)
-                               hid_report_set_tool(report, input, usage->code);
+                               report->tool = usage->code;
+
+                       /* drivers may have changed the value behind our back, resend it */
+                       hid_report_set_tool(report, input, report->tool);
                } else {
                        hid_report_release_tool(report, input, usage->code);
                }
index 92ac4f6..6028af3 100644 (file)
@@ -1221,6 +1221,7 @@ static void joycon_parse_report(struct joycon_ctlr *ctlr,
 
        spin_lock_irqsave(&ctlr->lock, flags);
        if (IS_ENABLED(CONFIG_NINTENDO_FF) && rep->vibrator_report &&
+           ctlr->ctlr_state != JOYCON_CTLR_STATE_REMOVED &&
            (msecs - ctlr->rumble_msecs) >= JC_RUMBLE_PERIOD_MS &&
            (ctlr->rumble_queue_head != ctlr->rumble_queue_tail ||
             ctlr->rumble_zero_countdown > 0)) {
@@ -1545,12 +1546,13 @@ static int joycon_set_rumble(struct joycon_ctlr *ctlr, u16 amp_r, u16 amp_l,
                ctlr->rumble_queue_head = 0;
        memcpy(ctlr->rumble_data[ctlr->rumble_queue_head], data,
               JC_RUMBLE_DATA_SIZE);
-       spin_unlock_irqrestore(&ctlr->lock, flags);
 
        /* don't wait for the periodic send (reduces latency) */
-       if (schedule_now)
+       if (schedule_now && ctlr->ctlr_state != JOYCON_CTLR_STATE_REMOVED)
                queue_work(ctlr->rumble_queue, &ctlr->rumble_worker);
 
+       spin_unlock_irqrestore(&ctlr->lock, flags);
+
        return 0;
 }
 
index dc67717..70f602c 100644 (file)
@@ -314,6 +314,8 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2021) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_TOUCHBAR_BACKLIGHT) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_TOUCHBAR_DISPLAY) },
 #endif
 #if IS_ENABLED(CONFIG_HID_APPLEIR)
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL) },
index a3b151b..fc616db 100644 (file)
@@ -134,6 +134,11 @@ static int steam_recv_report(struct steam_device *steam,
        int ret;
 
        r = steam->hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[0];
+       if (!r) {
+               hid_err(steam->hdev, "No HID_FEATURE_REPORT submitted -  nothing to read\n");
+               return -EINVAL;
+       }
+
        if (hid_report_len(r) < 64)
                return -EINVAL;
 
@@ -165,6 +170,11 @@ static int steam_send_report(struct steam_device *steam,
        int ret;
 
        r = steam->hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[0];
+       if (!r) {
+               hid_err(steam->hdev, "No HID_FEATURE_REPORT submitted -  nothing to read\n");
+               return -EINVAL;
+       }
+
        if (hid_report_len(r) < 64)
                return -EINVAL;
 
index c3e6d69..cf1679b 100644 (file)
@@ -67,12 +67,13 @@ static const struct tm_wheel_info tm_wheels_infos[] = {
        {0x0200, 0x0005, "Thrustmaster T300RS (Missing Attachment)"},
        {0x0206, 0x0005, "Thrustmaster T300RS"},
        {0x0209, 0x0005, "Thrustmaster T300RS (Open Wheel Attachment)"},
+       {0x020a, 0x0005, "Thrustmaster T300RS (Sparco R383 Mod)"},
        {0x0204, 0x0005, "Thrustmaster T300 Ferrari Alcantara Edition"},
        {0x0002, 0x0002, "Thrustmaster T500RS"}
        //{0x0407, 0x0001, "Thrustmaster TMX"}
 };
 
-static const uint8_t tm_wheels_infos_length = 4;
+static const uint8_t tm_wheels_infos_length = 7;
 
 /*
  * This structs contains (in little endian) the response data
index 681614a..197b1e7 100644 (file)
@@ -350,6 +350,8 @@ static int hidraw_release(struct inode * inode, struct file * file)
        down_write(&minors_rwsem);
 
        spin_lock_irqsave(&hidraw_table[minor]->list_lock, flags);
+       for (int i = list->tail; i < list->head; i++)
+               kfree(list->buffer[i].value);
        list_del(&list->node);
        spin_unlock_irqrestore(&hidraw_table[minor]->list_lock, flags);
        kfree(list);
index e600dbf..fc108f1 100644 (file)
@@ -32,6 +32,7 @@
 #define ADL_P_DEVICE_ID                0x51FC
 #define ADL_N_DEVICE_ID                0x54FC
 #define RPL_S_DEVICE_ID                0x7A78
+#define MTL_P_DEVICE_ID                0x7E45
 
 #define        REVISION_ID_CHT_A0      0x6
 #define        REVISION_ID_CHT_Ax_SI   0x0
index 2c67ec1..7120b30 100644 (file)
@@ -43,6 +43,7 @@ static const struct pci_device_id ish_pci_tbl[] = {
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, ADL_P_DEVICE_ID)},
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, ADL_N_DEVICE_ID)},
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, RPL_S_DEVICE_ID)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MTL_P_DEVICE_ID)},
        {0, }
 };
 MODULE_DEVICE_TABLE(pci, ish_pci_tbl);
index 6a5cc11..35dddc5 100644 (file)
@@ -105,7 +105,7 @@ struct report_list {
  * @multi_packet_cnt:  Count of fragmented packet count
  *
  * This structure is used to store completion flags and per client data like
- * like report description, number of HID devices etc.
+ * report description, number of HID devices etc.
  */
 struct ishtp_cl_data {
        /* completion flags */
index 405e0d5..df0a825 100644 (file)
@@ -626,13 +626,14 @@ static void ishtp_cl_read_complete(struct ishtp_cl_rb *rb)
 }
 
 /**
- * ipc_tx_callback() - IPC tx callback function
+ * ipc_tx_send() - IPC tx send function
  * @prm: Pointer to client device instance
  *
- * Send message over IPC either first time or on callback on previous message
- * completion
+ * Send message over IPC. Message will be split into fragments
+ * if message size is bigger than IPC FIFO size, and all
+ * fragments will be sent one by one.
  */
-static void ipc_tx_callback(void *prm)
+static void ipc_tx_send(void *prm)
 {
        struct ishtp_cl *cl = prm;
        struct ishtp_cl_tx_ring *cl_msg;
@@ -677,32 +678,41 @@ static void ipc_tx_callback(void *prm)
                            list);
        rem = cl_msg->send_buf.size - cl->tx_offs;
 
-       ishtp_hdr.host_addr = cl->host_client_id;
-       ishtp_hdr.fw_addr = cl->fw_client_id;
-       ishtp_hdr.reserved = 0;
-       pmsg = cl_msg->send_buf.data + cl->tx_offs;
+       while (rem > 0) {
+               ishtp_hdr.host_addr = cl->host_client_id;
+               ishtp_hdr.fw_addr = cl->fw_client_id;
+               ishtp_hdr.reserved = 0;
+               pmsg = cl_msg->send_buf.data + cl->tx_offs;
+
+               if (rem <= dev->mtu) {
+                       /* Last fragment or only one packet */
+                       ishtp_hdr.length = rem;
+                       ishtp_hdr.msg_complete = 1;
+                       /* Submit to IPC queue with no callback */
+                       ishtp_write_message(dev, &ishtp_hdr, pmsg);
+                       cl->tx_offs = 0;
+                       cl->sending = 0;
 
-       if (rem <= dev->mtu) {
-               ishtp_hdr.length = rem;
-               ishtp_hdr.msg_complete = 1;
-               cl->sending = 0;
-               list_del_init(&cl_msg->list);   /* Must be before write */
-               spin_unlock_irqrestore(&cl->tx_list_spinlock, tx_flags);
-               /* Submit to IPC queue with no callback */
-               ishtp_write_message(dev, &ishtp_hdr, pmsg);
-               spin_lock_irqsave(&cl->tx_free_list_spinlock, tx_free_flags);
-               list_add_tail(&cl_msg->list, &cl->tx_free_list.list);
-               ++cl->tx_ring_free_size;
-               spin_unlock_irqrestore(&cl->tx_free_list_spinlock,
-                       tx_free_flags);
-       } else {
-               /* Send IPC fragment */
-               spin_unlock_irqrestore(&cl->tx_list_spinlock, tx_flags);
-               cl->tx_offs += dev->mtu;
-               ishtp_hdr.length = dev->mtu;
-               ishtp_hdr.msg_complete = 0;
-               ishtp_send_msg(dev, &ishtp_hdr, pmsg, ipc_tx_callback, cl);
+                       break;
+               } else {
+                       /* Send ipc fragment */
+                       ishtp_hdr.length = dev->mtu;
+                       ishtp_hdr.msg_complete = 0;
+                       /* All fregments submitted to IPC queue with no callback */
+                       ishtp_write_message(dev, &ishtp_hdr, pmsg);
+                       cl->tx_offs += dev->mtu;
+                       rem = cl_msg->send_buf.size - cl->tx_offs;
+               }
        }
+
+       list_del_init(&cl_msg->list);
+       spin_unlock_irqrestore(&cl->tx_list_spinlock, tx_flags);
+
+       spin_lock_irqsave(&cl->tx_free_list_spinlock, tx_free_flags);
+       list_add_tail(&cl_msg->list, &cl->tx_free_list.list);
+       ++cl->tx_ring_free_size;
+       spin_unlock_irqrestore(&cl->tx_free_list_spinlock,
+               tx_free_flags);
 }
 
 /**
@@ -720,7 +730,7 @@ static void ishtp_cl_send_msg_ipc(struct ishtp_device *dev,
                return;
 
        cl->tx_offs = 0;
-       ipc_tx_callback(cl);
+       ipc_tx_send(cl);
        ++cl->send_msg_cnt_ipc;
 }
 
index 660036d..922d83e 100644 (file)
@@ -129,7 +129,7 @@ static void fcopy_send_data(struct work_struct *dummy)
 
        /*
         * The  strings sent from the host are encoded in
-        * in utf16; convert it to utf8 strings.
+        * utf16; convert it to utf8 strings.
         * The host assures us that the utf16 strings will not exceed
         * the max lengths specified. We will however, reserve room
         * for the string terminating character - in the utf16s_utf8s()
index 23c680d..3c833ea 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/kernel.h>
 #include <linux/syscore_ops.h>
 #include <linux/dma-map-ops.h>
+#include <linux/pci.h>
 #include <clocksource/hyperv_timer.h>
 #include "hyperv_vmbus.h"
 
@@ -2262,26 +2263,43 @@ static int vmbus_acpi_remove(struct acpi_device *device)
 
 static void vmbus_reserve_fb(void)
 {
-       int size;
+       resource_size_t start = 0, size;
+       struct pci_dev *pdev;
+
+       if (efi_enabled(EFI_BOOT)) {
+               /* Gen2 VM: get FB base from EFI framebuffer */
+               start = screen_info.lfb_base;
+               size = max_t(__u32, screen_info.lfb_size, 0x800000);
+       } else {
+               /* Gen1 VM: get FB base from PCI */
+               pdev = pci_get_device(PCI_VENDOR_ID_MICROSOFT,
+                                     PCI_DEVICE_ID_HYPERV_VIDEO, NULL);
+               if (!pdev)
+                       return;
+
+               if (pdev->resource[0].flags & IORESOURCE_MEM) {
+                       start = pci_resource_start(pdev, 0);
+                       size = pci_resource_len(pdev, 0);
+               }
+
+               /*
+                * Release the PCI device so hyperv_drm or hyperv_fb driver can
+                * grab it later.
+                */
+               pci_dev_put(pdev);
+       }
+
+       if (!start)
+               return;
+
        /*
         * Make a claim for the frame buffer in the resource tree under the
         * first node, which will be the one below 4GB.  The length seems to
         * be underreported, particularly in a Generation 1 VM.  So start out
         * reserving a larger area and make it smaller until it succeeds.
         */
-
-       if (screen_info.lfb_base) {
-               if (efi_enabled(EFI_BOOT))
-                       size = max_t(__u32, screen_info.lfb_size, 0x800000);
-               else
-                       size = max_t(__u32, screen_info.lfb_size, 0x4000000);
-
-               for (; !fb_mmio && (size >= 0x100000); size >>= 1) {
-                       fb_mmio = __request_region(hyperv_mmio,
-                                                  screen_info.lfb_base, size,
-                                                  fb_mmio_name, 0);
-               }
-       }
+       for (; !fb_mmio && (size >= 0x100000); size >>= 1)
+               fb_mmio = __request_region(hyperv_mmio, start, size, fb_mmio_name, 0);
 }
 
 /**
@@ -2313,7 +2331,7 @@ int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj,
                        bool fb_overlap_ok)
 {
        struct resource *iter, *shadow;
-       resource_size_t range_min, range_max, start;
+       resource_size_t range_min, range_max, start, end;
        const char *dev_n = dev_name(&device_obj->device);
        int retval;
 
@@ -2348,6 +2366,14 @@ int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj,
                range_max = iter->end;
                start = (range_min + align - 1) & ~(align - 1);
                for (; start + size - 1 <= range_max; start += align) {
+                       end = start + size - 1;
+
+                       /* Skip the whole fb_mmio region if not fb_overlap_ok */
+                       if (!fb_overlap_ok && fb_mmio &&
+                           (((start >= fb_mmio->start) && (start <= fb_mmio->end)) ||
+                            ((end >= fb_mmio->start) && (end <= fb_mmio->end))))
+                               continue;
+
                        shadow = __request_region(iter, start, size, NULL,
                                                  IORESOURCE_BUSY);
                        if (!shadow)
index 61a4684..81e6889 100644 (file)
@@ -266,9 +266,7 @@ static const struct ec_sensor_info sensors_family_intel_600[] = {
 #define SENSOR_SET_WATER_BLOCK                                                 \
        (SENSOR_TEMP_WATER_BLOCK_IN | SENSOR_TEMP_WATER_BLOCK_OUT)
 
-
 struct ec_board_info {
-       const char *board_names[MAX_IDENTICAL_BOARD_VARIATIONS];
        unsigned long sensors;
        /*
         * Defines which mutex to use for guarding access to the state and the
@@ -281,152 +279,194 @@ struct ec_board_info {
        enum board_family family;
 };
 
-static const struct ec_board_info board_info[] = {
-       {
-               .board_names = {"PRIME X470-PRO"},
-               .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
-                       SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM |
-                       SENSOR_FAN_CPU_OPT |
-                       SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE,
-               .mutex_path = ACPI_GLOBAL_LOCK_PSEUDO_PATH,
-               .family = family_amd_400_series,
-       },
-       {
-               .board_names = {"PRIME X570-PRO"},
-               .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | SENSOR_TEMP_VRM |
-                       SENSOR_TEMP_T_SENSOR | SENSOR_FAN_CHIPSET,
-               .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
-               .family = family_amd_500_series,
-       },
-       {
-               .board_names = {"ProArt X570-CREATOR WIFI"},
-               .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | SENSOR_TEMP_VRM |
-                       SENSOR_TEMP_T_SENSOR | SENSOR_FAN_CPU_OPT |
-                       SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE,
-       },
-       {
-               .board_names = {"Pro WS X570-ACE"},
-               .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | SENSOR_TEMP_VRM |
-                       SENSOR_TEMP_T_SENSOR | SENSOR_FAN_CHIPSET |
-                       SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE,
-               .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
-               .family = family_amd_500_series,
-       },
-       {
-               .board_names = {"ROG CROSSHAIR VIII DARK HERO"},
-               .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
-                       SENSOR_TEMP_T_SENSOR |
-                       SENSOR_TEMP_VRM | SENSOR_SET_TEMP_WATER |
-                       SENSOR_FAN_CPU_OPT | SENSOR_FAN_WATER_FLOW |
-                       SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE,
-               .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
-               .family = family_amd_500_series,
-       },
-       {
-               .board_names = {
-                       "ROG CROSSHAIR VIII FORMULA",
-                       "ROG CROSSHAIR VIII HERO",
-                       "ROG CROSSHAIR VIII HERO (WI-FI)",
-               },
-               .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
-                       SENSOR_TEMP_T_SENSOR |
-                       SENSOR_TEMP_VRM | SENSOR_SET_TEMP_WATER |
-                       SENSOR_FAN_CPU_OPT | SENSOR_FAN_CHIPSET |
-                       SENSOR_FAN_WATER_FLOW | SENSOR_CURR_CPU |
-                       SENSOR_IN_CPU_CORE,
-               .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
-               .family = family_amd_500_series,
-       },
-       {
-               .board_names = {
-                       "ROG MAXIMUS XI HERO",
-                       "ROG MAXIMUS XI HERO (WI-FI)",
-               },
-               .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
-                       SENSOR_TEMP_T_SENSOR |
-                       SENSOR_TEMP_VRM | SENSOR_SET_TEMP_WATER |
-                       SENSOR_FAN_CPU_OPT | SENSOR_FAN_WATER_FLOW,
-               .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
-               .family = family_intel_300_series,
-       },
-       {
-               .board_names = {"ROG CROSSHAIR VIII IMPACT"},
-               .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
-                       SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM |
-                       SENSOR_FAN_CHIPSET | SENSOR_CURR_CPU |
-                       SENSOR_IN_CPU_CORE,
-               .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
-               .family = family_amd_500_series,
-       },
-       {
-               .board_names = {"ROG STRIX B550-E GAMING"},
-               .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
-                       SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM |
-                       SENSOR_FAN_CPU_OPT,
-               .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
-               .family = family_amd_500_series,
-       },
-       {
-               .board_names = {"ROG STRIX B550-I GAMING"},
-               .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
-                       SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM |
-                       SENSOR_FAN_VRM_HS | SENSOR_CURR_CPU |
-                       SENSOR_IN_CPU_CORE,
-               .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
-               .family = family_amd_500_series,
-       },
-       {
-               .board_names = {"ROG STRIX X570-E GAMING"},
-               .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
-                       SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM |
-                       SENSOR_FAN_CHIPSET | SENSOR_CURR_CPU |
-                       SENSOR_IN_CPU_CORE,
-               .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
-               .family = family_amd_500_series,
-       },
-       {
-               .board_names = {"ROG STRIX X570-E GAMING WIFI II"},
-               .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
-                       SENSOR_TEMP_T_SENSOR | SENSOR_CURR_CPU |
-                       SENSOR_IN_CPU_CORE,
-               .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
-               .family = family_amd_500_series,
-       },
-       {
-               .board_names = {"ROG STRIX X570-F GAMING"},
-               .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
-                       SENSOR_TEMP_T_SENSOR | SENSOR_FAN_CHIPSET,
-               .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
-               .family = family_amd_500_series,
-       },
-       {
-               .board_names = {"ROG STRIX X570-I GAMING"},
-               .sensors = SENSOR_TEMP_CHIPSET | SENSOR_TEMP_VRM |
-                       SENSOR_TEMP_T_SENSOR |
-                       SENSOR_FAN_VRM_HS | SENSOR_FAN_CHIPSET |
-                       SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE,
-               .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
-               .family = family_amd_500_series,
-       },
-       {
-               .board_names = {"ROG STRIX Z690-A GAMING WIFI D4"},
-               .sensors = SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM,
-               .mutex_path = ASUS_HW_ACCESS_MUTEX_RMTW_ASMX,
-               .family = family_intel_600_series,
-       },
-       {
-               .board_names = {"ROG ZENITH II EXTREME"},
-               .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | SENSOR_TEMP_T_SENSOR |
-                       SENSOR_TEMP_VRM | SENSOR_SET_TEMP_WATER |
-                       SENSOR_FAN_CPU_OPT | SENSOR_FAN_CHIPSET | SENSOR_FAN_VRM_HS |
-                       SENSOR_FAN_WATER_FLOW | SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE |
-                       SENSOR_SET_WATER_BLOCK |
-                       SENSOR_TEMP_T_SENSOR_2 | SENSOR_TEMP_SENSOR_EXTRA_1 |
-                       SENSOR_TEMP_SENSOR_EXTRA_2 | SENSOR_TEMP_SENSOR_EXTRA_3,
-               .mutex_path = ASUS_HW_ACCESS_MUTEX_SB_PCI0_SBRG_SIO1_MUT0,
-               .family = family_amd_500_series,
-       },
-       {}
+static const struct ec_board_info board_info_prime_x470_pro = {
+       .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
+               SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM |
+               SENSOR_FAN_CPU_OPT |
+               SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE,
+       .mutex_path = ACPI_GLOBAL_LOCK_PSEUDO_PATH,
+       .family = family_amd_400_series,
+};
+
+static const struct ec_board_info board_info_prime_x570_pro = {
+       .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | SENSOR_TEMP_VRM |
+               SENSOR_TEMP_T_SENSOR | SENSOR_FAN_CHIPSET,
+       .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
+       .family = family_amd_500_series,
+};
+
+static const struct ec_board_info board_info_pro_art_x570_creator_wifi = {
+       .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | SENSOR_TEMP_VRM |
+               SENSOR_TEMP_T_SENSOR | SENSOR_FAN_CPU_OPT |
+               SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE,
+       .family = family_amd_500_series,
+};
+
+static const struct ec_board_info board_info_pro_ws_x570_ace = {
+       .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | SENSOR_TEMP_VRM |
+               SENSOR_TEMP_T_SENSOR | SENSOR_FAN_CHIPSET |
+               SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE,
+       .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
+       .family = family_amd_500_series,
+};
+
+static const struct ec_board_info board_info_crosshair_viii_dark_hero = {
+       .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
+               SENSOR_TEMP_T_SENSOR |
+               SENSOR_TEMP_VRM | SENSOR_SET_TEMP_WATER |
+               SENSOR_FAN_CPU_OPT | SENSOR_FAN_WATER_FLOW |
+               SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE,
+       .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
+       .family = family_amd_500_series,
+};
+
+static const struct ec_board_info board_info_crosshair_viii_hero = {
+       .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
+               SENSOR_TEMP_T_SENSOR |
+               SENSOR_TEMP_VRM | SENSOR_SET_TEMP_WATER |
+               SENSOR_FAN_CPU_OPT | SENSOR_FAN_CHIPSET |
+               SENSOR_FAN_WATER_FLOW | SENSOR_CURR_CPU |
+               SENSOR_IN_CPU_CORE,
+       .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
+       .family = family_amd_500_series,
+};
+
+static const struct ec_board_info board_info_maximus_xi_hero = {
+       .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
+               SENSOR_TEMP_T_SENSOR |
+               SENSOR_TEMP_VRM | SENSOR_SET_TEMP_WATER |
+               SENSOR_FAN_CPU_OPT | SENSOR_FAN_WATER_FLOW,
+       .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
+       .family = family_intel_300_series,
+};
+
+static const struct ec_board_info board_info_crosshair_viii_impact = {
+       .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
+               SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM |
+               SENSOR_FAN_CHIPSET | SENSOR_CURR_CPU |
+               SENSOR_IN_CPU_CORE,
+       .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
+       .family = family_amd_500_series,
+};
+
+static const struct ec_board_info board_info_strix_b550_e_gaming = {
+       .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
+               SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM |
+               SENSOR_FAN_CPU_OPT,
+       .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
+       .family = family_amd_500_series,
+};
+
+static const struct ec_board_info board_info_strix_b550_i_gaming = {
+       .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
+               SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM |
+               SENSOR_FAN_VRM_HS | SENSOR_CURR_CPU |
+               SENSOR_IN_CPU_CORE,
+       .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
+       .family = family_amd_500_series,
+};
+
+static const struct ec_board_info board_info_strix_x570_e_gaming = {
+       .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
+               SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM |
+               SENSOR_FAN_CHIPSET | SENSOR_CURR_CPU |
+               SENSOR_IN_CPU_CORE,
+       .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
+       .family = family_amd_500_series,
+};
+
+static const struct ec_board_info board_info_strix_x570_e_gaming_wifi_ii = {
+       .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
+               SENSOR_TEMP_T_SENSOR | SENSOR_CURR_CPU |
+               SENSOR_IN_CPU_CORE,
+       .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
+       .family = family_amd_500_series,
+};
+
+static const struct ec_board_info board_info_strix_x570_f_gaming = {
+       .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
+               SENSOR_TEMP_T_SENSOR | SENSOR_FAN_CHIPSET,
+       .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
+       .family = family_amd_500_series,
+};
+
+static const struct ec_board_info board_info_strix_x570_i_gaming = {
+       .sensors = SENSOR_TEMP_CHIPSET | SENSOR_TEMP_VRM |
+               SENSOR_TEMP_T_SENSOR |
+               SENSOR_FAN_VRM_HS | SENSOR_FAN_CHIPSET |
+               SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE,
+       .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
+       .family = family_amd_500_series,
+};
+
+static const struct ec_board_info board_info_strix_z690_a_gaming_wifi_d4 = {
+       .sensors = SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM,
+       .mutex_path = ASUS_HW_ACCESS_MUTEX_RMTW_ASMX,
+       .family = family_intel_600_series,
+};
+
+static const struct ec_board_info board_info_zenith_ii_extreme = {
+       .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | SENSOR_TEMP_T_SENSOR |
+               SENSOR_TEMP_VRM | SENSOR_SET_TEMP_WATER |
+               SENSOR_FAN_CPU_OPT | SENSOR_FAN_CHIPSET | SENSOR_FAN_VRM_HS |
+               SENSOR_FAN_WATER_FLOW | SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE |
+               SENSOR_SET_WATER_BLOCK |
+               SENSOR_TEMP_T_SENSOR_2 | SENSOR_TEMP_SENSOR_EXTRA_1 |
+               SENSOR_TEMP_SENSOR_EXTRA_2 | SENSOR_TEMP_SENSOR_EXTRA_3,
+       .mutex_path = ASUS_HW_ACCESS_MUTEX_SB_PCI0_SBRG_SIO1_MUT0,
+       .family = family_amd_500_series,
+};
+
+#define DMI_EXACT_MATCH_ASUS_BOARD_NAME(name, board_info)                      \
+       {                                                                      \
+               .matches = {                                                   \
+                       DMI_EXACT_MATCH(DMI_BOARD_VENDOR,                      \
+                                       "ASUSTeK COMPUTER INC."),              \
+                       DMI_EXACT_MATCH(DMI_BOARD_NAME, name),                 \
+               },                                                             \
+               .driver_data = (void *)board_info,                              \
+       }
+
+static const struct dmi_system_id dmi_table[] = {
+       DMI_EXACT_MATCH_ASUS_BOARD_NAME("PRIME X470-PRO",
+                                       &board_info_prime_x470_pro),
+       DMI_EXACT_MATCH_ASUS_BOARD_NAME("PRIME X570-PRO",
+                                       &board_info_prime_x570_pro),
+       DMI_EXACT_MATCH_ASUS_BOARD_NAME("ProArt X570-CREATOR WIFI",
+                                       &board_info_pro_art_x570_creator_wifi),
+       DMI_EXACT_MATCH_ASUS_BOARD_NAME("Pro WS X570-ACE",
+                                       &board_info_pro_ws_x570_ace),
+       DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR VIII DARK HERO",
+                                       &board_info_crosshair_viii_dark_hero),
+       DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR VIII FORMULA",
+                                       &board_info_crosshair_viii_hero),
+       DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR VIII HERO",
+                                       &board_info_crosshair_viii_hero),
+       DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR VIII HERO (WI-FI)",
+                                       &board_info_crosshair_viii_hero),
+       DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG MAXIMUS XI HERO",
+                                       &board_info_maximus_xi_hero),
+       DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG MAXIMUS XI HERO (WI-FI)",
+                                       &board_info_maximus_xi_hero),
+       DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR VIII IMPACT",
+                                       &board_info_crosshair_viii_impact),
+       DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX B550-E GAMING",
+                                       &board_info_strix_b550_e_gaming),
+       DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX B550-I GAMING",
+                                       &board_info_strix_b550_i_gaming),
+       DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X570-E GAMING",
+                                       &board_info_strix_x570_e_gaming),
+       DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X570-E GAMING WIFI II",
+                                       &board_info_strix_x570_e_gaming_wifi_ii),
+       DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X570-F GAMING",
+                                       &board_info_strix_x570_f_gaming),
+       DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X570-I GAMING",
+                                       &board_info_strix_x570_i_gaming),
+       DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX Z690-A GAMING WIFI D4",
+                                       &board_info_strix_z690_a_gaming_wifi_d4),
+       DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG ZENITH II EXTREME",
+                                       &board_info_zenith_ii_extreme),
+       {},
 };
 
 struct ec_sensor {
@@ -537,12 +577,12 @@ static int find_ec_sensor_index(const struct ec_sensors_data *ec,
        return -ENOENT;
 }
 
-static int __init bank_compare(const void *a, const void *b)
+static int bank_compare(const void *a, const void *b)
 {
        return *((const s8 *)a) - *((const s8 *)b);
 }
 
-static void __init setup_sensor_data(struct ec_sensors_data *ec)
+static void setup_sensor_data(struct ec_sensors_data *ec)
 {
        struct ec_sensor *s = ec->sensors;
        bool bank_found;
@@ -574,7 +614,7 @@ static void __init setup_sensor_data(struct ec_sensors_data *ec)
        sort(ec->banks, ec->nr_banks, 1, bank_compare, NULL);
 }
 
-static void __init fill_ec_registers(struct ec_sensors_data *ec)
+static void fill_ec_registers(struct ec_sensors_data *ec)
 {
        const struct ec_sensor_info *si;
        unsigned int i, j, register_idx = 0;
@@ -589,7 +629,7 @@ static void __init fill_ec_registers(struct ec_sensors_data *ec)
        }
 }
 
-static int __init setup_lock_data(struct device *dev)
+static int setup_lock_data(struct device *dev)
 {
        const char *mutex_path;
        int status;
@@ -812,7 +852,7 @@ static umode_t asus_ec_hwmon_is_visible(const void *drvdata,
        return find_ec_sensor_index(state, type, channel) >= 0 ? S_IRUGO : 0;
 }
 
-static int __init
+static int
 asus_ec_hwmon_add_chan_info(struct hwmon_channel_info *asus_ec_hwmon_chan,
                             struct device *dev, int num,
                             enum hwmon_sensor_types type, u32 config)
@@ -841,27 +881,15 @@ static struct hwmon_chip_info asus_ec_chip_info = {
        .ops = &asus_ec_hwmon_ops,
 };
 
-static const struct ec_board_info * __init get_board_info(void)
+static const struct ec_board_info *get_board_info(void)
 {
-       const char *dmi_board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
-       const char *dmi_board_name = dmi_get_system_info(DMI_BOARD_NAME);
-       const struct ec_board_info *board;
-
-       if (!dmi_board_vendor || !dmi_board_name ||
-           strcasecmp(dmi_board_vendor, "ASUSTeK COMPUTER INC."))
-               return NULL;
-
-       for (board = board_info; board->sensors; board++) {
-               if (match_string(board->board_names,
-                                MAX_IDENTICAL_BOARD_VARIATIONS,
-                                dmi_board_name) >= 0)
-                       return board;
-       }
+       const struct dmi_system_id *dmi_entry;
 
-       return NULL;
+       dmi_entry = dmi_first_match(dmi_table);
+       return dmi_entry ? dmi_entry->driver_data : NULL;
 }
 
-static int __init asus_ec_probe(struct platform_device *pdev)
+static int asus_ec_probe(struct platform_device *pdev)
 {
        const struct hwmon_channel_info **ptr_asus_ec_ci;
        int nr_count[hwmon_max] = { 0 }, nr_types = 0;
@@ -970,29 +998,37 @@ static int __init asus_ec_probe(struct platform_device *pdev)
        return PTR_ERR_OR_ZERO(hwdev);
 }
 
-
-static const struct acpi_device_id acpi_ec_ids[] = {
-       /* Embedded Controller Device */
-       { "PNP0C09", 0 },
-       {}
-};
+MODULE_DEVICE_TABLE(dmi, dmi_table);
 
 static struct platform_driver asus_ec_sensors_platform_driver = {
        .driver = {
                .name   = "asus-ec-sensors",
-               .acpi_match_table = acpi_ec_ids,
        },
+       .probe = asus_ec_probe,
 };
 
-MODULE_DEVICE_TABLE(acpi, acpi_ec_ids);
-/*
- * we use module_platform_driver_probe() rather than module_platform_driver()
- * because the probe function (and its dependants) are marked with __init, which
- * means we can't put it into the .probe member of the platform_driver struct
- * above, and we can't mark the asus_ec_sensors_platform_driver object as __init
- * because the object is referenced from the module exit code.
- */
-module_platform_driver_probe(asus_ec_sensors_platform_driver, asus_ec_probe);
+static struct platform_device *asus_ec_sensors_platform_device;
+
+static int __init asus_ec_init(void)
+{
+       asus_ec_sensors_platform_device =
+               platform_create_bundle(&asus_ec_sensors_platform_driver,
+                                      asus_ec_probe, NULL, 0, NULL, 0);
+
+       if (IS_ERR(asus_ec_sensors_platform_device))
+               return PTR_ERR(asus_ec_sensors_platform_device);
+
+       return 0;
+}
+
+static void __exit asus_ec_exit(void)
+{
+       platform_device_unregister(asus_ec_sensors_platform_device);
+       platform_driver_unregister(&asus_ec_sensors_platform_driver);
+}
+
+module_init(asus_ec_init);
+module_exit(asus_ec_exit);
 
 module_param_named(mutex_path, mutex_path_override, charp, 0);
 MODULE_PARM_DESC(mutex_path,
index befe989..fbf3f5a 100644 (file)
@@ -391,6 +391,9 @@ static int gpio_fan_set_cur_state(struct thermal_cooling_device *cdev,
        if (!fan_data)
                return -EINVAL;
 
+       if (state >= fan_data->num_speed)
+               return -EINVAL;
+
        set_fan_speed(fan_data, state);
        return 0;
 }
index 26278b0..9259779 100644 (file)
@@ -68,8 +68,9 @@
 
 /* VM Individual Macro Register */
 #define VM_COM_REG_SIZE        0x200
-#define VM_SDIF_DONE(n)        (VM_COM_REG_SIZE + 0x34 + 0x200 * (n))
-#define VM_SDIF_DATA(n)        (VM_COM_REG_SIZE + 0x40 + 0x200 * (n))
+#define VM_SDIF_DONE(vm)       (VM_COM_REG_SIZE + 0x34 + 0x200 * (vm))
+#define VM_SDIF_DATA(vm, ch)   \
+       (VM_COM_REG_SIZE + 0x40 + 0x200 * (vm) + 0x4 * (ch))
 
 /* SDA Slave Register */
 #define IP_CTRL                        0x00
@@ -115,6 +116,7 @@ struct pvt_device {
        u32                     t_num;
        u32                     p_num;
        u32                     v_num;
+       u32                     c_num;
        u32                     ip_freq;
        u8                      *vm_idx;
 };
@@ -178,14 +180,15 @@ static int pvt_read_in(struct device *dev, u32 attr, int channel, long *val)
 {
        struct pvt_device *pvt = dev_get_drvdata(dev);
        struct regmap *v_map = pvt->v_map;
+       u8 vm_idx, ch_idx;
        u32 n, stat;
-       u8 vm_idx;
        int ret;
 
-       if (channel >= pvt->v_num)
+       if (channel >= pvt->v_num * pvt->c_num)
                return -EINVAL;
 
-       vm_idx = pvt->vm_idx[channel];
+       vm_idx = pvt->vm_idx[channel / pvt->c_num];
+       ch_idx = channel % pvt->c_num;
 
        switch (attr) {
        case hwmon_in_input:
@@ -196,13 +199,23 @@ static int pvt_read_in(struct device *dev, u32 attr, int channel, long *val)
                if (ret)
                        return ret;
 
-               ret = regmap_read(v_map, VM_SDIF_DATA(vm_idx), &n);
+               ret = regmap_read(v_map, VM_SDIF_DATA(vm_idx, ch_idx), &n);
                if(ret < 0)
                        return ret;
 
                n &= SAMPLE_DATA_MSK;
-               /* Convert the N bitstream count into voltage */
-               *val = (PVT_N_CONST * n - PVT_R_CONST) >> PVT_CONV_BITS;
+               /*
+                * Convert the N bitstream count into voltage.
+                * To support negative voltage calculation for 64bit machines
+                * n must be cast to long, since n and *val differ both in
+                * signedness and in size.
+                * Division is used instead of right shift, because for signed
+                * numbers, the sign bit is used to fill the vacated bit
+                * positions, and if the number is negative, 1 is used.
+                * BIT(x) may not be used instead of (1 << x) because it's
+                * unsigned.
+                */
+               *val = (PVT_N_CONST * (long)n - PVT_R_CONST) / (1 << PVT_CONV_BITS);
 
                return 0;
        default:
@@ -375,6 +388,19 @@ static int pvt_init(struct pvt_device *pvt)
                if (ret)
                        return ret;
 
+               val = (BIT(pvt->c_num) - 1) | VM_CH_INIT |
+                     IP_POLL << SDIF_ADDR_SFT | SDIF_WRN_W | SDIF_PROG;
+               ret = regmap_write(v_map, SDIF_W, val);
+               if (ret < 0)
+                       return ret;
+
+               ret = regmap_read_poll_timeout(v_map, SDIF_STAT,
+                                              val, !(val & SDIF_BUSY),
+                                              PVT_POLL_DELAY_US,
+                                              PVT_POLL_TIMEOUT_US);
+               if (ret)
+                       return ret;
+
                val = CFG1_VOL_MEAS_MODE | CFG1_PARALLEL_OUT |
                      CFG1_14_BIT | IP_CFG << SDIF_ADDR_SFT |
                      SDIF_WRN_W | SDIF_PROG;
@@ -489,8 +515,8 @@ static int pvt_reset_control_deassert(struct device *dev, struct pvt_device *pvt
 
 static int mr75203_probe(struct platform_device *pdev)
 {
+       u32 ts_num, vm_num, pd_num, ch_num, val, index, i;
        const struct hwmon_channel_info **pvt_info;
-       u32 ts_num, vm_num, pd_num, val, index, i;
        struct device *dev = &pdev->dev;
        u32 *temp_config, *in_config;
        struct device *hwmon_dev;
@@ -531,9 +557,11 @@ static int mr75203_probe(struct platform_device *pdev)
        ts_num = (val & TS_NUM_MSK) >> TS_NUM_SFT;
        pd_num = (val & PD_NUM_MSK) >> PD_NUM_SFT;
        vm_num = (val & VM_NUM_MSK) >> VM_NUM_SFT;
+       ch_num = (val & CH_NUM_MSK) >> CH_NUM_SFT;
        pvt->t_num = ts_num;
        pvt->p_num = pd_num;
        pvt->v_num = vm_num;
+       pvt->c_num = ch_num;
        val = 0;
        if (ts_num)
                val++;
@@ -570,7 +598,7 @@ static int mr75203_probe(struct platform_device *pdev)
        }
 
        if (vm_num) {
-               u32 num = vm_num;
+               u32 total_ch;
 
                ret = pvt_get_regmap(pdev, "vm", pvt);
                if (ret)
@@ -584,30 +612,30 @@ static int mr75203_probe(struct platform_device *pdev)
                ret = device_property_read_u8_array(dev, "intel,vm-map",
                                                    pvt->vm_idx, vm_num);
                if (ret) {
-                       num = 0;
+                       /*
+                        * Incase intel,vm-map property is not defined, we
+                        * assume incremental channel numbers.
+                        */
+                       for (i = 0; i < vm_num; i++)
+                               pvt->vm_idx[i] = i;
                } else {
                        for (i = 0; i < vm_num; i++)
                                if (pvt->vm_idx[i] >= vm_num ||
                                    pvt->vm_idx[i] == 0xff) {
-                                       num = i;
+                                       pvt->v_num = i;
+                                       vm_num = i;
                                        break;
                                }
                }
 
-               /*
-                * Incase intel,vm-map property is not defined, we assume
-                * incremental channel numbers.
-                */
-               for (i = num; i < vm_num; i++)
-                       pvt->vm_idx[i] = i;
-
-               in_config = devm_kcalloc(dev, num + 1,
+               total_ch = ch_num * vm_num;
+               in_config = devm_kcalloc(dev, total_ch + 1,
                                         sizeof(*in_config), GFP_KERNEL);
                if (!in_config)
                        return -ENOMEM;
 
-               memset32(in_config, HWMON_I_INPUT, num);
-               in_config[num] = 0;
+               memset32(in_config, HWMON_I_INPUT, total_ch);
+               in_config[total_ch] = 0;
                pvt_in.config = in_config;
 
                pvt_info[index++] = &pvt_in;
index f10bac8..81d3f91 100644 (file)
@@ -2861,7 +2861,7 @@ static int pmbus_regulator_get_low_margin(struct i2c_client *client, int page)
                .data = -1,
        };
 
-       if (!data->vout_low[page]) {
+       if (data->vout_low[page] < 0) {
                if (pmbus_check_word_register(client, page, PMBUS_MFR_VOUT_MIN))
                        s.data = _pmbus_read_word_data(client, page, 0xff,
                                                       PMBUS_MFR_VOUT_MIN);
@@ -2887,7 +2887,7 @@ static int pmbus_regulator_get_high_margin(struct i2c_client *client, int page)
                .data = -1,
        };
 
-       if (!data->vout_high[page]) {
+       if (data->vout_high[page] < 0) {
                if (pmbus_check_word_register(client, page, PMBUS_MFR_VOUT_MAX))
                        s.data = _pmbus_read_word_data(client, page, 0xff,
                                                       PMBUS_MFR_VOUT_MAX);
@@ -3016,11 +3016,10 @@ static int pmbus_regulator_register(struct pmbus_data *data)
 
                rdev = devm_regulator_register(dev, &info->reg_desc[i],
                                               &config);
-               if (IS_ERR(rdev)) {
-                       dev_err(dev, "Failed to register %s regulator\n",
-                               info->reg_desc[i].name);
-                       return PTR_ERR(rdev);
-               }
+               if (IS_ERR(rdev))
+                       return dev_err_probe(dev, PTR_ERR(rdev),
+                                            "Failed to register %s regulator\n",
+                                            info->reg_desc[i].name);
        }
 
        return 0;
@@ -3320,6 +3319,7 @@ int pmbus_do_probe(struct i2c_client *client, struct pmbus_driver_info *info)
        struct pmbus_data *data;
        size_t groups_num = 0;
        int ret;
+       int i;
        char *name;
 
        if (!info)
@@ -3353,6 +3353,11 @@ int pmbus_do_probe(struct i2c_client *client, struct pmbus_driver_info *info)
        data->currpage = -1;
        data->currphase = -1;
 
+       for (i = 0; i < ARRAY_SIZE(data->vout_low); i++) {
+               data->vout_low[i] = -1;
+               data->vout_high[i] = -1;
+       }
+
        ret = pmbus_init_common(client, data, info);
        if (ret < 0)
                return ret;
index 42762e8..f7c59ff 100644 (file)
@@ -493,18 +493,20 @@ static char *tps23861_port_poe_plus_status(struct tps23861_data *data, int port)
 
 static int tps23861_port_resistance(struct tps23861_data *data, int port)
 {
-       u16 regval;
+       unsigned int raw_val;
+       __le16 regval;
 
        regmap_bulk_read(data->regmap,
                         PORT_1_RESISTANCE_LSB + PORT_N_RESISTANCE_LSB_OFFSET * (port - 1),
                         &regval,
                         2);
 
-       switch (FIELD_GET(PORT_RESISTANCE_RSN_MASK, regval)) {
+       raw_val = le16_to_cpu(regval);
+       switch (FIELD_GET(PORT_RESISTANCE_RSN_MASK, raw_val)) {
        case PORT_RESISTANCE_RSN_OTHER:
-               return (FIELD_GET(PORT_RESISTANCE_MASK, regval) * RESISTANCE_LSB) / 10000;
+               return (FIELD_GET(PORT_RESISTANCE_MASK, raw_val) * RESISTANCE_LSB) / 10000;
        case PORT_RESISTANCE_RSN_LOW:
-               return (FIELD_GET(PORT_RESISTANCE_MASK, regval) * RESISTANCE_LSB_LOW) / 10000;
+               return (FIELD_GET(PORT_RESISTANCE_MASK, raw_val) * RESISTANCE_LSB_LOW) / 10000;
        case PORT_RESISTANCE_RSN_SHORT:
        case PORT_RESISTANCE_RSN_OPEN:
        default:
index 78fb1a4..e47fa34 100644 (file)
@@ -1572,9 +1572,7 @@ static int i2c_imx_remove(struct platform_device *pdev)
        struct imx_i2c_struct *i2c_imx = platform_get_drvdata(pdev);
        int irq, ret;
 
-       ret = pm_runtime_resume_and_get(&pdev->dev);
-       if (ret < 0)
-               return ret;
+       ret = pm_runtime_get_sync(&pdev->dev);
 
        hrtimer_cancel(&i2c_imx->slave_timer);
 
@@ -1585,17 +1583,21 @@ static int i2c_imx_remove(struct platform_device *pdev)
        if (i2c_imx->dma)
                i2c_imx_dma_free(i2c_imx);
 
-       /* setup chip registers to defaults */
-       imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IADR);
-       imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IFDR);
-       imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2CR);
-       imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2SR);
+       if (ret == 0) {
+               /* setup chip registers to defaults */
+               imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IADR);
+               imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IFDR);
+               imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2CR);
+               imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2SR);
+               clk_disable(i2c_imx->clk);
+       }
 
        clk_notifier_unregister(i2c_imx->clk, &i2c_imx->clk_change_nb);
        irq = platform_get_irq(pdev, 0);
        if (irq >= 0)
                free_irq(irq, i2c_imx);
-       clk_disable_unprepare(i2c_imx->clk);
+
+       clk_unprepare(i2c_imx->clk);
 
        pm_runtime_put_noidle(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
index 79798fc..6746aa4 100644 (file)
@@ -30,7 +30,7 @@ struct acpi_smbus_cmi {
        u8 cap_info:1;
        u8 cap_read:1;
        u8 cap_write:1;
-       const struct smbus_methods_t *methods;
+       struct smbus_methods_t *methods;
 };
 
 static const struct smbus_methods_t smbus_methods = {
@@ -361,6 +361,7 @@ static acpi_status acpi_smbus_cmi_query_methods(acpi_handle handle, u32 level,
 static int acpi_smbus_cmi_add(struct acpi_device *device)
 {
        struct acpi_smbus_cmi *smbus_cmi;
+       const struct acpi_device_id *id;
        int ret;
 
        smbus_cmi = kzalloc(sizeof(struct acpi_smbus_cmi), GFP_KERNEL);
@@ -368,7 +369,6 @@ static int acpi_smbus_cmi_add(struct acpi_device *device)
                return -ENOMEM;
 
        smbus_cmi->handle = device->handle;
-       smbus_cmi->methods = device_get_match_data(&device->dev);
        strcpy(acpi_device_name(device), ACPI_SMBUS_HC_DEVICE_NAME);
        strcpy(acpi_device_class(device), ACPI_SMBUS_HC_CLASS);
        device->driver_data = smbus_cmi;
@@ -376,6 +376,11 @@ static int acpi_smbus_cmi_add(struct acpi_device *device)
        smbus_cmi->cap_read = 0;
        smbus_cmi->cap_write = 0;
 
+       for (id = acpi_smbus_cmi_ids; id->id[0]; id++)
+               if (!strcmp(id->id, acpi_device_hid(device)))
+                       smbus_cmi->methods =
+                               (struct smbus_methods_t *) id->driver_data;
+
        acpi_walk_namespace(ACPI_TYPE_METHOD, smbus_cmi->handle, 1,
                            acpi_smbus_cmi_query_methods, NULL, smbus_cmi, NULL);
 
index 92c68d4..a2f9fda 100644 (file)
@@ -287,10 +287,8 @@ static int ad7292_probe(struct spi_device *spi)
 
                ret = devm_add_action_or_reset(&spi->dev,
                                               ad7292_regulator_disable, st);
-               if (ret) {
-                       regulator_disable(st->reg);
+               if (ret)
                        return ret;
-               }
 
                ret = regulator_get_voltage(st->reg);
                if (ret < 0)
index 1cb4590..890af7d 100644 (file)
@@ -40,8 +40,8 @@
 #define MCP3911_CHANNEL(x)             (MCP3911_REG_CHANNEL0 + x * 3)
 #define MCP3911_OFFCAL(x)              (MCP3911_REG_OFFCAL_CH0 + x * 6)
 
-/* Internal voltage reference in uV */
-#define MCP3911_INT_VREF_UV            1200000
+/* Internal voltage reference in mV */
+#define MCP3911_INT_VREF_MV            1200
 
 #define MCP3911_REG_READ(reg, id)      ((((reg) << 1) | ((id) << 5) | (1 << 0)) & 0xff)
 #define MCP3911_REG_WRITE(reg, id)     ((((reg) << 1) | ((id) << 5) | (0 << 0)) & 0xff)
@@ -113,6 +113,8 @@ static int mcp3911_read_raw(struct iio_dev *indio_dev,
                if (ret)
                        goto out;
 
+               *val = sign_extend32(*val, 23);
+
                ret = IIO_VAL_INT;
                break;
 
@@ -137,11 +139,18 @@ static int mcp3911_read_raw(struct iio_dev *indio_dev,
 
                        *val = ret / 1000;
                } else {
-                       *val = MCP3911_INT_VREF_UV;
+                       *val = MCP3911_INT_VREF_MV;
                }
 
-               *val2 = 24;
-               ret = IIO_VAL_FRACTIONAL_LOG2;
+               /*
+                * For 24bit Conversion
+                * Raw = ((Voltage)/(Vref) * 2^23 * Gain * 1.5
+                * Voltage = Raw * (Vref)/(2^23 * Gain * 1.5)
+                */
+
+               /* val2 = (2^23 * 1.5) */
+               *val2 = 12582912;
+               ret = IIO_VAL_FRACTIONAL;
                break;
        }
 
@@ -208,7 +217,14 @@ static int mcp3911_config(struct mcp3911 *adc)
        u32 configreg;
        int ret;
 
-       device_property_read_u32(dev, "device-addr", &adc->dev_addr);
+       ret = device_property_read_u32(dev, "microchip,device-addr", &adc->dev_addr);
+
+       /*
+        * Fallback to "device-addr" due to historical mismatch between
+        * dt-bindings and implementation
+        */
+       if (ret)
+               device_property_read_u32(dev, "device-addr", &adc->dev_addr);
        if (adc->dev_addr > 3) {
                dev_err(&adc->spi->dev,
                        "invalid device address (%i). Must be in range 0-3.\n",
index edbe6a3..001055d 100644 (file)
@@ -505,7 +505,7 @@ static int cm32181_resume(struct device *dev)
                                         cm32181->conf_regs[CM32181_REG_ADDR_CMD]);
 }
 
-DEFINE_SIMPLE_DEV_PM_OPS(cm32181_pm_ops, cm32181_suspend, cm32181_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(cm32181_pm_ops, cm32181_suspend, cm32181_resume);
 
 static const struct of_device_id cm32181_of_match[] = {
        { .compatible = "capella,cm3218" },
index c721b69..0b30db7 100644 (file)
@@ -226,8 +226,10 @@ static int cm3605_probe(struct platform_device *pdev)
        }
 
        irq = platform_get_irq(pdev, 0);
-       if (irq < 0)
-               return dev_err_probe(dev, irq, "failed to get irq\n");
+       if (irq < 0) {
+               ret = dev_err_probe(dev, irq, "failed to get irq\n");
+               goto out_disable_aset;
+       }
 
        ret = devm_request_threaded_irq(dev, irq, cm3605_prox_irq,
                                        NULL, 0, "cm3605", indio_dev);
index 46d0667..be317f2 100644 (file)
@@ -1841,8 +1841,8 @@ cma_ib_id_from_event(struct ib_cm_id *cm_id,
                }
 
                if (!validate_net_dev(*net_dev,
-                                (struct sockaddr *)&req->listen_addr_storage,
-                                (struct sockaddr *)&req->src_addr_storage)) {
+                                (struct sockaddr *)&req->src_addr_storage,
+                                (struct sockaddr *)&req->listen_addr_storage)) {
                        id_priv = ERR_PTR(-EHOSTUNREACH);
                        goto err;
                }
index fce80a4..04c04e6 100644 (file)
@@ -18,6 +18,7 @@ int ib_umem_dmabuf_map_pages(struct ib_umem_dmabuf *umem_dmabuf)
        struct scatterlist *sg;
        unsigned long start, end, cur = 0;
        unsigned int nmap = 0;
+       long ret;
        int i;
 
        dma_resv_assert_held(umem_dmabuf->attach->dmabuf->resv);
@@ -67,9 +68,14 @@ wait_fence:
         * may be not up-to-date. Wait for the exporter to finish
         * the migration.
         */
-       return dma_resv_wait_timeout(umem_dmabuf->attach->dmabuf->resv,
+       ret = dma_resv_wait_timeout(umem_dmabuf->attach->dmabuf->resv,
                                     DMA_RESV_USAGE_KERNEL,
                                     false, MAX_SCHEDULE_TIMEOUT);
+       if (ret < 0)
+               return ret;
+       if (ret == 0)
+               return -ETIMEDOUT;
+       return 0;
 }
 EXPORT_SYMBOL(ib_umem_dmabuf_map_pages);
 
index 186ed88..d39e16c 100644 (file)
@@ -462,7 +462,7 @@ retry:
                mutex_unlock(&umem_odp->umem_mutex);
 
 out_put_mm:
-       mmput(owning_mm);
+       mmput_async(owning_mm);
 out_put_task:
        if (owning_process)
                put_task_struct(owning_process);
index c16017f..14392c9 100644 (file)
@@ -2468,31 +2468,24 @@ static int accept_cr(struct c4iw_ep *ep, struct sk_buff *skb,
                        opt2 |= CCTRL_ECN_V(1);
        }
 
-       skb_get(skb);
-       rpl = cplhdr(skb);
        if (!is_t4(adapter_type)) {
-               BUILD_BUG_ON(sizeof(*rpl5) != roundup(sizeof(*rpl5), 16));
-               skb_trim(skb, sizeof(*rpl5));
-               rpl5 = (void *)rpl;
-               INIT_TP_WR(rpl5, ep->hwtid);
-       } else {
-               skb_trim(skb, sizeof(*rpl));
-               INIT_TP_WR(rpl, ep->hwtid);
-       }
-       OPCODE_TID(rpl) = cpu_to_be32(MK_OPCODE_TID(CPL_PASS_ACCEPT_RPL,
-                                                   ep->hwtid));
-
-       if (CHELSIO_CHIP_VERSION(adapter_type) > CHELSIO_T4) {
                u32 isn = (prandom_u32() & ~7UL) - 1;
+
+               skb = get_skb(skb, roundup(sizeof(*rpl5), 16), GFP_KERNEL);
+               rpl5 = __skb_put_zero(skb, roundup(sizeof(*rpl5), 16));
+               rpl = (void *)rpl5;
+               INIT_TP_WR_CPL(rpl5, CPL_PASS_ACCEPT_RPL, ep->hwtid);
                opt2 |= T5_OPT_2_VALID_F;
                opt2 |= CONG_CNTRL_V(CONG_ALG_TAHOE);
                opt2 |= T5_ISS_F;
-               rpl5 = (void *)rpl;
-               memset_after(rpl5, 0, iss);
                if (peer2peer)
                        isn += 4;
                rpl5->iss = cpu_to_be32(isn);
                pr_debug("iss %u\n", be32_to_cpu(rpl5->iss));
+       } else {
+               skb = get_skb(skb, sizeof(*rpl), GFP_KERNEL);
+               rpl = __skb_put_zero(skb, sizeof(*rpl));
+               INIT_TP_WR_CPL(rpl, CPL_PASS_ACCEPT_RPL, ep->hwtid);
        }
 
        rpl->opt0 = cpu_to_be64(opt0);
index 72f0817..bc3ec22 100644 (file)
@@ -407,7 +407,7 @@ static int erdma_push_one_sqe(struct erdma_qp *qp, u16 *pi,
                             to_erdma_access_flags(reg_wr(send_wr)->access);
                regmr_sge->addr = cpu_to_le64(mr->ibmr.iova);
                regmr_sge->length = cpu_to_le32(mr->ibmr.length);
-               regmr_sge->stag = cpu_to_le32(mr->ibmr.lkey);
+               regmr_sge->stag = cpu_to_le32(reg_wr(send_wr)->key);
                attrs = FIELD_PREP(ERDMA_SQE_MR_MODE_MASK, 0) |
                        FIELD_PREP(ERDMA_SQE_MR_ACCESS_MASK, mr->access) |
                        FIELD_PREP(ERDMA_SQE_MR_MTT_CNT_MASK,
index a7a3d42..699bd3f 100644 (file)
@@ -280,7 +280,7 @@ int erdma_query_device(struct ib_device *ibdev, struct ib_device_attr *attr,
        attr->vendor_id = PCI_VENDOR_ID_ALIBABA;
        attr->vendor_part_id = dev->pdev->device;
        attr->hw_ver = dev->pdev->revision;
-       attr->max_qp = dev->attrs.max_qp;
+       attr->max_qp = dev->attrs.max_qp - 1;
        attr->max_qp_wr = min(dev->attrs.max_send_wr, dev->attrs.max_recv_wr);
        attr->max_qp_rd_atom = dev->attrs.max_ord;
        attr->max_qp_init_rd_atom = dev->attrs.max_ird;
@@ -291,7 +291,7 @@ int erdma_query_device(struct ib_device *ibdev, struct ib_device_attr *attr,
        attr->max_send_sge = dev->attrs.max_send_sge;
        attr->max_recv_sge = dev->attrs.max_recv_sge;
        attr->max_sge_rd = dev->attrs.max_sge_rd;
-       attr->max_cq = dev->attrs.max_cq;
+       attr->max_cq = dev->attrs.max_cq - 1;
        attr->max_cqe = dev->attrs.max_cqe;
        attr->max_mr = dev->attrs.max_mr;
        attr->max_pd = dev->attrs.max_pd;
index f848eed..d249965 100644 (file)
@@ -730,7 +730,6 @@ struct hns_roce_caps {
        u32             num_qps;
        u32             num_pi_qps;
        u32             reserved_qps;
-       int             num_qpc_timer;
        u32             num_srqs;
        u32             max_wqes;
        u32             max_srq_wrs;
index cbdafaa..c780646 100644 (file)
@@ -1977,7 +1977,7 @@ static void set_default_caps(struct hns_roce_dev *hr_dev)
 
        caps->num_mtpts         = HNS_ROCE_V2_MAX_MTPT_NUM;
        caps->num_pds           = HNS_ROCE_V2_MAX_PD_NUM;
-       caps->num_qpc_timer     = HNS_ROCE_V2_MAX_QPC_TIMER_NUM;
+       caps->qpc_timer_bt_num  = HNS_ROCE_V2_MAX_QPC_TIMER_BT_NUM;
        caps->cqc_timer_bt_num  = HNS_ROCE_V2_MAX_CQC_TIMER_BT_NUM;
 
        caps->max_qp_init_rdma  = HNS_ROCE_V2_MAX_QP_INIT_RDMA;
@@ -2273,7 +2273,6 @@ static int hns_roce_query_pf_caps(struct hns_roce_dev *hr_dev)
        caps->max_rq_sg              = le16_to_cpu(resp_a->max_rq_sg);
        caps->max_rq_sg = roundup_pow_of_two(caps->max_rq_sg);
        caps->max_extend_sg          = le32_to_cpu(resp_a->max_extend_sg);
-       caps->num_qpc_timer          = le16_to_cpu(resp_a->num_qpc_timer);
        caps->max_srq_sges           = le16_to_cpu(resp_a->max_srq_sges);
        caps->max_srq_sges = roundup_pow_of_two(caps->max_srq_sges);
        caps->num_aeq_vectors        = resp_a->num_aeq_vectors;
index f96deba..6479710 100644 (file)
 #include <linux/bitops.h>
 
 #define HNS_ROCE_V2_MAX_QP_NUM                 0x1000
-#define HNS_ROCE_V2_MAX_QPC_TIMER_NUM          0x200
 #define HNS_ROCE_V2_MAX_WQE_NUM                        0x8000
 #define HNS_ROCE_V2_MAX_SRQ_WR                 0x8000
 #define HNS_ROCE_V2_MAX_SRQ_SGE                        64
 #define HNS_ROCE_V2_MAX_CQ_NUM                 0x100000
+#define HNS_ROCE_V2_MAX_QPC_TIMER_BT_NUM       0x100
 #define HNS_ROCE_V2_MAX_CQC_TIMER_BT_NUM       0x100
 #define HNS_ROCE_V2_MAX_SRQ_NUM                        0x100000
 #define HNS_ROCE_V2_MAX_CQE_NUM                        0x400000
@@ -83,7 +83,7 @@
 
 #define HNS_ROCE_V2_QPC_TIMER_ENTRY_SZ         PAGE_SIZE
 #define HNS_ROCE_V2_CQC_TIMER_ENTRY_SZ         PAGE_SIZE
-#define HNS_ROCE_V2_PAGE_SIZE_SUPPORTED                0xFFFFF000
+#define HNS_ROCE_V2_PAGE_SIZE_SUPPORTED                0xFFFF000
 #define HNS_ROCE_V2_MAX_INNER_MTPT_NUM         2
 #define HNS_ROCE_INVALID_LKEY                  0x0
 #define HNS_ROCE_INVALID_SGE_LENGTH            0x80000000
index c8af4eb..4ccb217 100644 (file)
@@ -725,7 +725,7 @@ static int hns_roce_init_hem(struct hns_roce_dev *hr_dev)
                ret = hns_roce_init_hem_table(hr_dev, &hr_dev->qpc_timer_table,
                                              HEM_TYPE_QPC_TIMER,
                                              hr_dev->caps.qpc_timer_entry_sz,
-                                             hr_dev->caps.num_qpc_timer, 1);
+                                             hr_dev->caps.qpc_timer_bt_num, 1);
                if (ret) {
                        dev_err(dev,
                                "Failed to init QPC timer memory, aborting.\n");
index 48d3616..7bee7f6 100644 (file)
@@ -462,11 +462,8 @@ static int set_rq_size(struct hns_roce_dev *hr_dev, struct ib_qp_cap *cap,
        hr_qp->rq.max_gs = roundup_pow_of_two(max(1U, cap->max_recv_sge) +
                                              hr_qp->rq.rsv_sge);
 
-       if (hr_dev->caps.max_rq_sg <= HNS_ROCE_SGE_IN_WQE)
-               hr_qp->rq.wqe_shift = ilog2(hr_dev->caps.max_rq_desc_sz);
-       else
-               hr_qp->rq.wqe_shift = ilog2(hr_dev->caps.max_rq_desc_sz *
-                                           hr_qp->rq.max_gs);
+       hr_qp->rq.wqe_shift = ilog2(hr_dev->caps.max_rq_desc_sz *
+                                   hr_qp->rq.max_gs);
 
        hr_qp->rq.wqe_cnt = cnt;
        if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_RQ_INLINE &&
index daeab5d..a6e5d35 100644 (file)
@@ -497,7 +497,8 @@ int irdma_uk_send(struct irdma_qp_uk *qp, struct irdma_post_sq_info *info,
                              FIELD_PREP(IRDMAQPSQ_IMMDATA, info->imm_data));
                i = 0;
        } else {
-               qp->wqe_ops.iw_set_fragment(wqe, 0, op_info->sg_list,
+               qp->wqe_ops.iw_set_fragment(wqe, 0,
+                                           frag_cnt ? op_info->sg_list : NULL,
                                            qp->swqe_polarity);
                i = 1;
        }
@@ -1005,6 +1006,7 @@ int irdma_uk_cq_poll_cmpl(struct irdma_cq_uk *cq,
        int ret_code;
        bool move_cq_head = true;
        u8 polarity;
+       u8 op_type;
        bool ext_valid;
        __le64 *ext_cqe;
 
@@ -1187,7 +1189,6 @@ int irdma_uk_cq_poll_cmpl(struct irdma_cq_uk *cq,
                        do {
                                __le64 *sw_wqe;
                                u64 wqe_qword;
-                               u8 op_type;
                                u32 tail;
 
                                tail = qp->sq_ring.tail;
@@ -1204,6 +1205,8 @@ int irdma_uk_cq_poll_cmpl(struct irdma_cq_uk *cq,
                                        break;
                                }
                        } while (1);
+                       if (op_type == IRDMA_OP_TYPE_BIND_MW && info->minor_err == FLUSH_PROT_ERR)
+                               info->minor_err = FLUSH_MW_BIND_ERR;
                        qp->sq_flush_seen = true;
                        if (!IRDMA_RING_MORE_WORK(qp->sq_ring))
                                qp->sq_flush_complete = true;
index fdf4cc8..075defa 100644 (file)
@@ -590,11 +590,14 @@ static int irdma_wait_event(struct irdma_pci_f *rf,
        cqp_error = cqp_request->compl_info.error;
        if (cqp_error) {
                err_code = -EIO;
-               if (cqp_request->compl_info.maj_err_code == 0xFFFF &&
-                   cqp_request->compl_info.min_err_code == 0x8029) {
-                       if (!rf->reset) {
-                               rf->reset = true;
-                               rf->gen_ops.request_reset(rf);
+               if (cqp_request->compl_info.maj_err_code == 0xFFFF) {
+                       if (cqp_request->compl_info.min_err_code == 0x8002)
+                               err_code = -EBUSY;
+                       else if (cqp_request->compl_info.min_err_code == 0x8029) {
+                               if (!rf->reset) {
+                                       rf->reset = true;
+                                       rf->gen_ops.request_reset(rf);
+                               }
                        }
                }
        }
@@ -2598,7 +2601,7 @@ void irdma_generate_flush_completions(struct irdma_qp *iwqp)
                spin_unlock_irqrestore(&iwqp->lock, flags2);
                spin_unlock_irqrestore(&iwqp->iwscq->lock, flags1);
                if (compl_generated)
-                       irdma_comp_handler(iwqp->iwrcq);
+                       irdma_comp_handler(iwqp->iwscq);
        } else {
                spin_unlock_irqrestore(&iwqp->iwscq->lock, flags1);
                mod_delayed_work(iwqp->iwdev->cleanup_wq, &iwqp->dwork_flush,
index 9b07b8a..9b207f5 100644 (file)
@@ -39,15 +39,18 @@ static int irdma_query_device(struct ib_device *ibdev,
        props->max_send_sge = hw_attrs->uk_attrs.max_hw_wq_frags;
        props->max_recv_sge = hw_attrs->uk_attrs.max_hw_wq_frags;
        props->max_cq = rf->max_cq - rf->used_cqs;
-       props->max_cqe = rf->max_cqe;
+       props->max_cqe = rf->max_cqe - 1;
        props->max_mr = rf->max_mr - rf->used_mrs;
        props->max_mw = props->max_mr;
        props->max_pd = rf->max_pd - rf->used_pds;
        props->max_sge_rd = hw_attrs->uk_attrs.max_hw_read_sges;
        props->max_qp_rd_atom = hw_attrs->max_hw_ird;
        props->max_qp_init_rd_atom = hw_attrs->max_hw_ord;
-       if (rdma_protocol_roce(ibdev, 1))
+       if (rdma_protocol_roce(ibdev, 1)) {
+               props->device_cap_flags |= IB_DEVICE_RC_RNR_NAK_GEN;
                props->max_pkeys = IRDMA_PKEY_TBL_SZ;
+       }
+
        props->max_ah = rf->max_ah;
        props->max_mcast_grp = rf->max_mcg;
        props->max_mcast_qp_attach = IRDMA_MAX_MGS_PER_CTX;
@@ -3009,6 +3012,7 @@ static int irdma_dereg_mr(struct ib_mr *ib_mr, struct ib_udata *udata)
        struct irdma_pble_alloc *palloc = &iwpbl->pble_alloc;
        struct irdma_cqp_request *cqp_request;
        struct cqp_cmds_info *cqp_info;
+       int status;
 
        if (iwmr->type != IRDMA_MEMREG_TYPE_MEM) {
                if (iwmr->region) {
@@ -3039,8 +3043,11 @@ static int irdma_dereg_mr(struct ib_mr *ib_mr, struct ib_udata *udata)
        cqp_info->post_sq = 1;
        cqp_info->in.u.dealloc_stag.dev = &iwdev->rf->sc_dev;
        cqp_info->in.u.dealloc_stag.scratch = (uintptr_t)cqp_request;
-       irdma_handle_cqp_op(iwdev->rf, cqp_request);
+       status = irdma_handle_cqp_op(iwdev->rf, cqp_request);
        irdma_put_cqp_request(&iwdev->rf->cqp, cqp_request);
+       if (status)
+               return status;
+
        irdma_free_stag(iwdev, iwmr->stag);
 done:
        if (iwpbl->pbl_allocated)
index 293ed70..b4dc523 100644 (file)
@@ -166,6 +166,12 @@ static int process_pma_cmd(struct mlx5_ib_dev *dev, u32 port_num,
                mdev = dev->mdev;
                mdev_port_num = 1;
        }
+       if (MLX5_CAP_GEN(dev->mdev, num_ports) == 1) {
+               /* set local port to one for Function-Per-Port HCA. */
+               mdev = dev->mdev;
+               mdev_port_num = 1;
+       }
+
        /* Declaring support of extended counters */
        if (in_mad->mad_hdr.attr_id == IB_PMA_CLASS_PORT_INFO) {
                struct ib_class_port_info cpi = {};
index a174a0e..883d7c6 100644 (file)
@@ -2738,26 +2738,24 @@ static int set_has_smi_cap(struct mlx5_ib_dev *dev)
        int err;
        int port;
 
-       for (port = 1; port <= ARRAY_SIZE(dev->port_caps); port++) {
-               dev->port_caps[port - 1].has_smi = false;
-               if (MLX5_CAP_GEN(dev->mdev, port_type) ==
-                   MLX5_CAP_PORT_TYPE_IB) {
-                       if (MLX5_CAP_GEN(dev->mdev, ib_virt)) {
-                               err = mlx5_query_hca_vport_context(dev->mdev, 0,
-                                                                  port, 0,
-                                                                  &vport_ctx);
-                               if (err) {
-                                       mlx5_ib_err(dev, "query_hca_vport_context for port=%d failed %d\n",
-                                                   port, err);
-                                       return err;
-                               }
-                               dev->port_caps[port - 1].has_smi =
-                                       vport_ctx.has_smi;
-                       } else {
-                               dev->port_caps[port - 1].has_smi = true;
-                       }
+       if (MLX5_CAP_GEN(dev->mdev, port_type) != MLX5_CAP_PORT_TYPE_IB)
+               return 0;
+
+       for (port = 1; port <= dev->num_ports; port++) {
+               if (!MLX5_CAP_GEN(dev->mdev, ib_virt)) {
+                       dev->port_caps[port - 1].has_smi = true;
+                       continue;
                }
+               err = mlx5_query_hca_vport_context(dev->mdev, 0, port, 0,
+                                                  &vport_ctx);
+               if (err) {
+                       mlx5_ib_err(dev, "query_hca_vport_context for port=%d failed %d\n",
+                                   port, err);
+                       return err;
+               }
+               dev->port_caps[port - 1].has_smi = vport_ctx.has_smi;
        }
+
        return 0;
 }
 
@@ -4338,7 +4336,7 @@ static int mlx5r_probe(struct auxiliary_device *adev,
        dev->mdev = mdev;
        dev->num_ports = num_ports;
 
-       if (ll == IB_LINK_LAYER_ETHERNET && !mlx5_is_roce_init_enabled(mdev))
+       if (ll == IB_LINK_LAYER_ETHERNET && !mlx5_get_roce_state(mdev))
                profile = &raw_eth_profile;
        else
                profile = &pf_profile;
index 2e2ad39..e66bf72 100644 (file)
@@ -708,6 +708,7 @@ struct mlx5_ib_umr_context {
 };
 
 enum {
+       MLX5_UMR_STATE_UNINIT,
        MLX5_UMR_STATE_ACTIVE,
        MLX5_UMR_STATE_RECOVER,
        MLX5_UMR_STATE_ERR,
index e00b94d..d5105b5 100644 (file)
@@ -177,6 +177,7 @@ int mlx5r_umr_resource_init(struct mlx5_ib_dev *dev)
 
        sema_init(&dev->umrc.sem, MAX_UMR_WR);
        mutex_init(&dev->umrc.lock);
+       dev->umrc.state = MLX5_UMR_STATE_ACTIVE;
 
        return 0;
 
@@ -191,6 +192,8 @@ destroy_pd:
 
 void mlx5r_umr_resource_cleanup(struct mlx5_ib_dev *dev)
 {
+       if (dev->umrc.state == MLX5_UMR_STATE_UNINIT)
+               return;
        ib_destroy_qp(dev->umrc.qp);
        ib_free_cq(dev->umrc.cq);
        ib_dealloc_pd(dev->umrc.pd);
index 1f4e602..7d47b52 100644 (file)
@@ -29,7 +29,7 @@ static struct page *siw_get_pblpage(struct siw_mem *mem, u64 addr, int *idx)
        dma_addr_t paddr = siw_pbl_get_buffer(pbl, offset, NULL, idx);
 
        if (paddr)
-               return virt_to_page(paddr);
+               return virt_to_page((void *)paddr);
 
        return NULL;
 }
@@ -533,13 +533,23 @@ static int siw_tx_hdt(struct siw_iwarp_tx *c_tx, struct socket *s)
                                        kunmap_local(kaddr);
                                }
                        } else {
-                               u64 va = sge->laddr + sge_off;
+                               /*
+                                * Cast to an uintptr_t to preserve all 64 bits
+                                * in sge->laddr.
+                                */
+                               uintptr_t va = (uintptr_t)(sge->laddr + sge_off);
 
-                               page_array[seg] = virt_to_page(va & PAGE_MASK);
+                               /*
+                                * virt_to_page() takes a (void *) pointer
+                                * so cast to a (void *) meaning it will be 64
+                                * bits on a 64 bit platform and 32 bits on a
+                                * 32 bit platform.
+                                */
+                               page_array[seg] = virt_to_page((void *)(va & PAGE_MASK));
                                if (do_crc)
                                        crypto_shash_update(
                                                c_tx->mpa_crc_hd,
-                                               (void *)(uintptr_t)va,
+                                               (void *)va,
                                                plen);
                        }
 
index bd5f3b5..7b83f48 100644 (file)
@@ -537,6 +537,7 @@ void iser_login_rsp(struct ib_cq *cq, struct ib_wc *wc)
        struct iscsi_hdr *hdr;
        char *data;
        int length;
+       bool full_feature_phase;
 
        if (unlikely(wc->status != IB_WC_SUCCESS)) {
                iser_err_comp(wc, "login_rsp");
@@ -550,6 +551,9 @@ void iser_login_rsp(struct ib_cq *cq, struct ib_wc *wc)
        hdr = desc->rsp + sizeof(struct iser_ctrl);
        data = desc->rsp + ISER_HEADERS_LEN;
        length = wc->byte_len - ISER_HEADERS_LEN;
+       full_feature_phase = ((hdr->flags & ISCSI_FULL_FEATURE_PHASE) ==
+                             ISCSI_FULL_FEATURE_PHASE) &&
+                            (hdr->flags & ISCSI_FLAG_CMD_FINAL);
 
        iser_dbg("op 0x%x itt 0x%x dlen %d\n", hdr->opcode,
                 hdr->itt, length);
@@ -560,7 +564,8 @@ void iser_login_rsp(struct ib_cq *cq, struct ib_wc *wc)
                                      desc->rsp_dma, ISER_RX_LOGIN_SIZE,
                                      DMA_FROM_DEVICE);
 
-       if (iser_conn->iscsi_conn->session->discovery_sess)
+       if (!full_feature_phase ||
+           iser_conn->iscsi_conn->session->discovery_sess)
                return;
 
        /* Post the first RX buffer that is skipped in iser_post_rx_bufs() */
index baecde4..449904d 100644 (file)
@@ -1004,7 +1004,8 @@ rtrs_clt_get_copy_req(struct rtrs_clt_path *alive_path,
 static int rtrs_post_rdma_write_sg(struct rtrs_clt_con *con,
                                   struct rtrs_clt_io_req *req,
                                   struct rtrs_rbuf *rbuf, bool fr_en,
-                                  u32 size, u32 imm, struct ib_send_wr *wr,
+                                  u32 count, u32 size, u32 imm,
+                                  struct ib_send_wr *wr,
                                   struct ib_send_wr *tail)
 {
        struct rtrs_clt_path *clt_path = to_clt_path(con->c.path);
@@ -1024,12 +1025,12 @@ static int rtrs_post_rdma_write_sg(struct rtrs_clt_con *con,
                num_sge = 2;
                ptail = tail;
        } else {
-               for_each_sg(req->sglist, sg, req->sg_cnt, i) {
+               for_each_sg(req->sglist, sg, count, i) {
                        sge[i].addr   = sg_dma_address(sg);
                        sge[i].length = sg_dma_len(sg);
                        sge[i].lkey   = clt_path->s.dev->ib_pd->local_dma_lkey;
                }
-               num_sge = 1 + req->sg_cnt;
+               num_sge = 1 + count;
        }
        sge[i].addr   = req->iu->dma_addr;
        sge[i].length = size;
@@ -1142,7 +1143,7 @@ static int rtrs_clt_write_req(struct rtrs_clt_io_req *req)
         */
        rtrs_clt_update_all_stats(req, WRITE);
 
-       ret = rtrs_post_rdma_write_sg(req->con, req, rbuf, fr_en,
+       ret = rtrs_post_rdma_write_sg(req->con, req, rbuf, fr_en, count,
                                      req->usr_len + sizeof(*msg),
                                      imm, wr, &inv_wr);
        if (ret) {
index 34c03bd..4894e73 100644 (file)
@@ -595,7 +595,7 @@ static int map_cont_bufs(struct rtrs_srv_path *srv_path)
                struct sg_table *sgt = &srv_mr->sgt;
                struct scatterlist *s;
                struct ib_mr *mr;
-               int nr, chunks;
+               int nr, nr_sgt, chunks;
 
                chunks = chunks_per_mr * mri;
                if (!always_invalidate)
@@ -610,19 +610,19 @@ static int map_cont_bufs(struct rtrs_srv_path *srv_path)
                        sg_set_page(s, srv->chunks[chunks + i],
                                    max_chunk_size, 0);
 
-               nr = ib_dma_map_sg(srv_path->s.dev->ib_dev, sgt->sgl,
+               nr_sgt = ib_dma_map_sg(srv_path->s.dev->ib_dev, sgt->sgl,
                                   sgt->nents, DMA_BIDIRECTIONAL);
-               if (nr < sgt->nents) {
-                       err = nr < 0 ? nr : -EINVAL;
+               if (!nr_sgt) {
+                       err = -EINVAL;
                        goto free_sg;
                }
                mr = ib_alloc_mr(srv_path->s.dev->ib_pd, IB_MR_TYPE_MEM_REG,
-                                sgt->nents);
+                                nr_sgt);
                if (IS_ERR(mr)) {
                        err = PTR_ERR(mr);
                        goto unmap_sg;
                }
-               nr = ib_map_mr_sg(mr, sgt->sgl, sgt->nents,
+               nr = ib_map_mr_sg(mr, sgt->sgl, nr_sgt,
                                  NULL, max_chunk_size);
                if (nr < 0 || nr < sgt->nents) {
                        err = nr < 0 ? nr : -EINVAL;
@@ -641,7 +641,7 @@ static int map_cont_bufs(struct rtrs_srv_path *srv_path)
                        }
                }
                /* Eventually dma addr for each chunk can be cached */
-               for_each_sg(sgt->sgl, s, sgt->orig_nents, i)
+               for_each_sg(sgt->sgl, s, nr_sgt, i)
                        srv_path->dma_addr[chunks + i] = sg_dma_address(s);
 
                ib_update_fast_reg_key(mr, ib_inc_rkey(mr->rkey));
index 7720ea2..d7f69e5 100644 (file)
@@ -1961,7 +1961,8 @@ static void srp_process_rsp(struct srp_rdma_ch *ch, struct srp_rsp *rsp)
                if (scmnd) {
                        req = scsi_cmd_priv(scmnd);
                        scmnd = srp_claim_req(ch, req, NULL, scmnd);
-               } else {
+               }
+               if (!scmnd) {
                        shost_printk(KERN_ERR, target->scsi_host,
                                     "Null scmnd for RSP w/tag %#016llx received on ch %td / QP %#x\n",
                                     rsp->tag, ch - target->ch, ch->qp->qp_num);
index b2a68bc..b86de13 100644 (file)
@@ -50,6 +50,7 @@ static struct iforce_device iforce_device[] = {
        { 0x046d, 0xc291, "Logitech WingMan Formula Force",             btn_wheel, abs_wheel, ff_iforce },
        { 0x05ef, 0x020a, "AVB Top Shot Pegasus",                       btn_joystick_avb, abs_avb_pegasus, ff_iforce },
        { 0x05ef, 0x8884, "AVB Mag Turbo Force",                        btn_wheel, abs_wheel, ff_iforce },
+       { 0x05ef, 0x8886, "Boeder Force Feedback Wheel",                btn_wheel, abs_wheel, ff_iforce },
        { 0x05ef, 0x8888, "AVB Top Shot Force Feedback Racing Wheel",   btn_wheel, abs_wheel, ff_iforce }, //?
        { 0x061c, 0xc0a4, "ACT LABS Force RS",                          btn_wheel, abs_wheel, ff_iforce }, //?
        { 0x061c, 0xc084, "ACT LABS Force RS",                          btn_wheel, abs_wheel, ff_iforce },
index f95a81b..2380546 100644 (file)
@@ -39,7 +39,7 @@ static void iforce_serio_xmit(struct iforce *iforce)
 
 again:
        if (iforce->xmit.head == iforce->xmit.tail) {
-               clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
+               iforce_clear_xmit_and_wake(iforce);
                spin_unlock_irqrestore(&iforce->xmit_lock, flags);
                return;
        }
@@ -64,7 +64,7 @@ again:
        if (test_and_clear_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags))
                goto again;
 
-       clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
+       iforce_clear_xmit_and_wake(iforce);
 
        spin_unlock_irqrestore(&iforce->xmit_lock, flags);
 }
@@ -169,7 +169,7 @@ static irqreturn_t iforce_serio_irq(struct serio *serio,
                        iforce_serio->cmd_response_len = iforce_serio->len;
 
                        /* Signal that command is done */
-                       wake_up(&iforce->wait);
+                       wake_up_all(&iforce->wait);
                } else if (likely(iforce->type)) {
                        iforce_process_packet(iforce, iforce_serio->id,
                                              iforce_serio->data_in,
index ea58805..cba92bd 100644 (file)
@@ -30,7 +30,7 @@ static void __iforce_usb_xmit(struct iforce *iforce)
        spin_lock_irqsave(&iforce->xmit_lock, flags);
 
        if (iforce->xmit.head == iforce->xmit.tail) {
-               clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
+               iforce_clear_xmit_and_wake(iforce);
                spin_unlock_irqrestore(&iforce->xmit_lock, flags);
                return;
        }
@@ -58,9 +58,9 @@ static void __iforce_usb_xmit(struct iforce *iforce)
        XMIT_INC(iforce->xmit.tail, n);
 
        if ( (n=usb_submit_urb(iforce_usb->out, GFP_ATOMIC)) ) {
-               clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
                dev_warn(&iforce_usb->intf->dev,
                         "usb_submit_urb failed %d\n", n);
+               iforce_clear_xmit_and_wake(iforce);
        }
 
        /* The IFORCE_XMIT_RUNNING bit is not cleared here. That's intended.
@@ -175,15 +175,15 @@ static void iforce_usb_out(struct urb *urb)
        struct iforce *iforce = &iforce_usb->iforce;
 
        if (urb->status) {
-               clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
                dev_dbg(&iforce_usb->intf->dev, "urb->status %d, exiting\n",
                        urb->status);
+               iforce_clear_xmit_and_wake(iforce);
                return;
        }
 
        __iforce_usb_xmit(iforce);
 
-       wake_up(&iforce->wait);
+       wake_up_all(&iforce->wait);
 }
 
 static int iforce_usb_probe(struct usb_interface *intf,
index 6aa761e..9ccb910 100644 (file)
@@ -119,6 +119,12 @@ static inline int iforce_get_id_packet(struct iforce *iforce, u8 id,
                                         response_data, response_len);
 }
 
+static inline void iforce_clear_xmit_and_wake(struct iforce *iforce)
+{
+       clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
+       wake_up_all(&iforce->wait);
+}
+
 /* Public functions */
 /* iforce-main.c */
 int iforce_init_device(struct device *parent, u16 bustype,
index 3fb64db..76873aa 100644 (file)
@@ -98,6 +98,7 @@ static struct platform_driver rk805_pwrkey_driver = {
 };
 module_platform_driver(rk805_pwrkey_driver);
 
+MODULE_ALIAS("platform:rk805-pwrkey");
 MODULE_AUTHOR("Joseph Chen <chenjh@rock-chips.com>");
 MODULE_DESCRIPTION("RK805 PMIC Power Key driver");
 MODULE_LICENSE("GPL");
index d016505..21c0ddd 100644 (file)
@@ -95,6 +95,7 @@ static const struct goodix_chip_data gt9x_chip_data = {
 
 static const struct goodix_chip_id goodix_chip_ids[] = {
        { .id = "1151", .data = &gt1x_chip_data },
+       { .id = "1158", .data = &gt1x_chip_data },
        { .id = "5663", .data = &gt1x_chip_data },
        { .id = "5688", .data = &gt1x_chip_data },
        { .id = "917S", .data = &gt1x_chip_data },
@@ -1508,6 +1509,7 @@ MODULE_DEVICE_TABLE(acpi, goodix_acpi_match);
 #ifdef CONFIG_OF
 static const struct of_device_id goodix_of_match[] = {
        { .compatible = "goodix,gt1151" },
+       { .compatible = "goodix,gt1158" },
        { .compatible = "goodix,gt5663" },
        { .compatible = "goodix,gt5688" },
        { .compatible = "goodix,gt911" },
index 65b8e4f..828672a 100644 (file)
@@ -939,7 +939,8 @@ static void build_completion_wait(struct iommu_cmd *cmd,
        memset(cmd, 0, sizeof(*cmd));
        cmd->data[0] = lower_32_bits(paddr) | CMD_COMPL_WAIT_STORE_MASK;
        cmd->data[1] = upper_32_bits(paddr);
-       cmd->data[2] = data;
+       cmd->data[2] = lower_32_bits(data);
+       cmd->data[3] = upper_32_bits(data);
        CMD_SET_TYPE(cmd, CMD_COMPL_WAIT);
 }
 
index 696d555..6a1f02c 100644 (file)
@@ -777,6 +777,8 @@ int amd_iommu_init_device(struct pci_dev *pdev, int pasids)
        if (dev_state->domain == NULL)
                goto out_free_states;
 
+       /* See iommu_is_default_domain() */
+       dev_state->domain->type = IOMMU_DOMAIN_IDENTITY;
        amd_iommu_domain_direct_map(dev_state->domain);
 
        ret = amd_iommu_domain_enable_v2(dev_state->domain, pasids);
index 51bd66a..e190bb8 100644 (file)
@@ -68,7 +68,6 @@ static int hyperv_irq_remapping_alloc(struct irq_domain *domain,
 {
        struct irq_alloc_info *info = arg;
        struct irq_data *irq_data;
-       struct irq_desc *desc;
        int ret = 0;
 
        if (!info || info->type != X86_IRQ_ALLOC_TYPE_IOAPIC || nr_irqs > 1)
@@ -90,8 +89,7 @@ static int hyperv_irq_remapping_alloc(struct irq_domain *domain,
         * Hypver-V IO APIC irq affinity should be in the scope of
         * ioapic_max_cpumask because no irq remapping support.
         */
-       desc = irq_data_to_desc(irq_data);
-       cpumask_copy(desc->irq_common_data.affinity, &ioapic_max_cpumask);
+       irq_data_update_affinity(irq_data, &ioapic_max_cpumask);
 
        return 0;
 }
index 7cca030..31bc50e 100644 (file)
@@ -163,38 +163,6 @@ static phys_addr_t root_entry_uctp(struct root_entry *re)
        return re->hi & VTD_PAGE_MASK;
 }
 
-static inline void context_clear_pasid_enable(struct context_entry *context)
-{
-       context->lo &= ~(1ULL << 11);
-}
-
-static inline bool context_pasid_enabled(struct context_entry *context)
-{
-       return !!(context->lo & (1ULL << 11));
-}
-
-static inline void context_set_copied(struct context_entry *context)
-{
-       context->hi |= (1ull << 3);
-}
-
-static inline bool context_copied(struct context_entry *context)
-{
-       return !!(context->hi & (1ULL << 3));
-}
-
-static inline bool __context_present(struct context_entry *context)
-{
-       return (context->lo & 1);
-}
-
-bool context_present(struct context_entry *context)
-{
-       return context_pasid_enabled(context) ?
-            __context_present(context) :
-            __context_present(context) && !context_copied(context);
-}
-
 static inline void context_set_present(struct context_entry *context)
 {
        context->lo |= 1;
@@ -242,6 +210,26 @@ static inline void context_clear_entry(struct context_entry *context)
        context->hi = 0;
 }
 
+static inline bool context_copied(struct intel_iommu *iommu, u8 bus, u8 devfn)
+{
+       if (!iommu->copied_tables)
+               return false;
+
+       return test_bit(((long)bus << 8) | devfn, iommu->copied_tables);
+}
+
+static inline void
+set_context_copied(struct intel_iommu *iommu, u8 bus, u8 devfn)
+{
+       set_bit(((long)bus << 8) | devfn, iommu->copied_tables);
+}
+
+static inline void
+clear_context_copied(struct intel_iommu *iommu, u8 bus, u8 devfn)
+{
+       clear_bit(((long)bus << 8) | devfn, iommu->copied_tables);
+}
+
 /*
  * This domain is a statically identity mapping domain.
  *     1. This domain creats a static 1:1 mapping to all usable memory.
@@ -402,14 +390,36 @@ static inline int domain_pfn_supported(struct dmar_domain *domain,
        return !(addr_width < BITS_PER_LONG && pfn >> addr_width);
 }
 
+/*
+ * Calculate the Supported Adjusted Guest Address Widths of an IOMMU.
+ * Refer to 11.4.2 of the VT-d spec for the encoding of each bit of
+ * the returned SAGAW.
+ */
+static unsigned long __iommu_calculate_sagaw(struct intel_iommu *iommu)
+{
+       unsigned long fl_sagaw, sl_sagaw;
+
+       fl_sagaw = BIT(2) | (cap_5lp_support(iommu->cap) ? BIT(3) : 0);
+       sl_sagaw = cap_sagaw(iommu->cap);
+
+       /* Second level only. */
+       if (!sm_supported(iommu) || !ecap_flts(iommu->ecap))
+               return sl_sagaw;
+
+       /* First level only. */
+       if (!ecap_slts(iommu->ecap))
+               return fl_sagaw;
+
+       return fl_sagaw & sl_sagaw;
+}
+
 static int __iommu_calculate_agaw(struct intel_iommu *iommu, int max_gaw)
 {
        unsigned long sagaw;
        int agaw;
 
-       sagaw = cap_sagaw(iommu->cap);
-       for (agaw = width_to_agaw(max_gaw);
-            agaw >= 0; agaw--) {
+       sagaw = __iommu_calculate_sagaw(iommu);
+       for (agaw = width_to_agaw(max_gaw); agaw >= 0; agaw--) {
                if (test_bit(agaw, &sagaw))
                        break;
        }
@@ -505,8 +515,9 @@ static int domain_update_device_node(struct dmar_domain *domain)
 {
        struct device_domain_info *info;
        int nid = NUMA_NO_NODE;
+       unsigned long flags;
 
-       spin_lock(&domain->lock);
+       spin_lock_irqsave(&domain->lock, flags);
        list_for_each_entry(info, &domain->devices, link) {
                /*
                 * There could possibly be multiple device numa nodes as devices
@@ -518,7 +529,7 @@ static int domain_update_device_node(struct dmar_domain *domain)
                if (nid != NUMA_NO_NODE)
                        break;
        }
-       spin_unlock(&domain->lock);
+       spin_unlock_irqrestore(&domain->lock, flags);
 
        return nid;
 }
@@ -578,6 +589,13 @@ struct context_entry *iommu_context_addr(struct intel_iommu *iommu, u8 bus,
        struct context_entry *context;
        u64 *entry;
 
+       /*
+        * Except that the caller requested to allocate a new entry,
+        * returning a copied context entry makes no sense.
+        */
+       if (!alloc && context_copied(iommu, bus, devfn))
+               return NULL;
+
        entry = &root->lo;
        if (sm_supported(iommu)) {
                if (devfn >= 0x80) {
@@ -795,32 +813,11 @@ static void free_context_table(struct intel_iommu *iommu)
 }
 
 #ifdef CONFIG_DMAR_DEBUG
-static void pgtable_walk(struct intel_iommu *iommu, unsigned long pfn, u8 bus, u8 devfn)
+static void pgtable_walk(struct intel_iommu *iommu, unsigned long pfn,
+                        u8 bus, u8 devfn, struct dma_pte *parent, int level)
 {
-       struct device_domain_info *info;
-       struct dma_pte *parent, *pte;
-       struct dmar_domain *domain;
-       struct pci_dev *pdev;
-       int offset, level;
-
-       pdev = pci_get_domain_bus_and_slot(iommu->segment, bus, devfn);
-       if (!pdev)
-               return;
-
-       info = dev_iommu_priv_get(&pdev->dev);
-       if (!info || !info->domain) {
-               pr_info("device [%02x:%02x.%d] not probed\n",
-                       bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
-               return;
-       }
-
-       domain = info->domain;
-       level = agaw_to_level(domain->agaw);
-       parent = domain->pgd;
-       if (!parent) {
-               pr_info("no page table setup\n");
-               return;
-       }
+       struct dma_pte *pte;
+       int offset;
 
        while (1) {
                offset = pfn_level_offset(pfn, level);
@@ -847,9 +844,10 @@ void dmar_fault_dump_ptes(struct intel_iommu *iommu, u16 source_id,
        struct pasid_entry *entries, *pte;
        struct context_entry *ctx_entry;
        struct root_entry *rt_entry;
+       int i, dir_index, index, level;
        u8 devfn = source_id & 0xff;
        u8 bus = source_id >> 8;
-       int i, dir_index, index;
+       struct dma_pte *pgtable;
 
        pr_info("Dump %s table entries for IOVA 0x%llx\n", iommu->name, addr);
 
@@ -877,8 +875,11 @@ void dmar_fault_dump_ptes(struct intel_iommu *iommu, u16 source_id,
                ctx_entry->hi, ctx_entry->lo);
 
        /* legacy mode does not require PASID entries */
-       if (!sm_supported(iommu))
+       if (!sm_supported(iommu)) {
+               level = agaw_to_level(ctx_entry->hi & 7);
+               pgtable = phys_to_virt(ctx_entry->lo & VTD_PAGE_MASK);
                goto pgtable_walk;
+       }
 
        /* get the pointer to pasid directory entry */
        dir = phys_to_virt(ctx_entry->lo & VTD_PAGE_MASK);
@@ -905,8 +906,16 @@ void dmar_fault_dump_ptes(struct intel_iommu *iommu, u16 source_id,
        for (i = 0; i < ARRAY_SIZE(pte->val); i++)
                pr_info("pasid table entry[%d]: 0x%016llx\n", i, pte->val[i]);
 
+       if (pasid_pte_get_pgtt(pte) == PASID_ENTRY_PGTT_FL_ONLY) {
+               level = pte->val[2] & BIT_ULL(2) ? 5 : 4;
+               pgtable = phys_to_virt(pte->val[2] & VTD_PAGE_MASK);
+       } else {
+               level = agaw_to_level((pte->val[0] >> 2) & 0x7);
+               pgtable = phys_to_virt(pte->val[0] & VTD_PAGE_MASK);
+       }
+
 pgtable_walk:
-       pgtable_walk(iommu, addr >> VTD_PAGE_SHIFT, bus, devfn);
+       pgtable_walk(iommu, addr >> VTD_PAGE_SHIFT, bus, devfn, pgtable, level);
 }
 #endif
 
@@ -1345,19 +1354,20 @@ iommu_support_dev_iotlb(struct dmar_domain *domain, struct intel_iommu *iommu,
                        u8 bus, u8 devfn)
 {
        struct device_domain_info *info;
+       unsigned long flags;
 
        if (!iommu->qi)
                return NULL;
 
-       spin_lock(&domain->lock);
+       spin_lock_irqsave(&domain->lock, flags);
        list_for_each_entry(info, &domain->devices, link) {
                if (info->iommu == iommu && info->bus == bus &&
                    info->devfn == devfn) {
-                       spin_unlock(&domain->lock);
+                       spin_unlock_irqrestore(&domain->lock, flags);
                        return info->ats_supported ? info : NULL;
                }
        }
-       spin_unlock(&domain->lock);
+       spin_unlock_irqrestore(&domain->lock, flags);
 
        return NULL;
 }
@@ -1366,8 +1376,9 @@ static void domain_update_iotlb(struct dmar_domain *domain)
 {
        struct device_domain_info *info;
        bool has_iotlb_device = false;
+       unsigned long flags;
 
-       spin_lock(&domain->lock);
+       spin_lock_irqsave(&domain->lock, flags);
        list_for_each_entry(info, &domain->devices, link) {
                if (info->ats_enabled) {
                        has_iotlb_device = true;
@@ -1375,7 +1386,7 @@ static void domain_update_iotlb(struct dmar_domain *domain)
                }
        }
        domain->has_iotlb_device = has_iotlb_device;
-       spin_unlock(&domain->lock);
+       spin_unlock_irqrestore(&domain->lock, flags);
 }
 
 static void iommu_enable_dev_iotlb(struct device_domain_info *info)
@@ -1467,14 +1478,15 @@ static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
                                  u64 addr, unsigned mask)
 {
        struct device_domain_info *info;
+       unsigned long flags;
 
        if (!domain->has_iotlb_device)
                return;
 
-       spin_lock(&domain->lock);
+       spin_lock_irqsave(&domain->lock, flags);
        list_for_each_entry(info, &domain->devices, link)
                __iommu_flush_dev_iotlb(info, addr, mask);
-       spin_unlock(&domain->lock);
+       spin_unlock_irqrestore(&domain->lock, flags);
 }
 
 static void iommu_flush_iotlb_psi(struct intel_iommu *iommu,
@@ -1688,6 +1700,11 @@ static void free_dmar_iommu(struct intel_iommu *iommu)
                iommu->domain_ids = NULL;
        }
 
+       if (iommu->copied_tables) {
+               bitmap_free(iommu->copied_tables);
+               iommu->copied_tables = NULL;
+       }
+
        /* free context mapping */
        free_context_table(iommu);
 
@@ -1913,7 +1930,7 @@ static int domain_context_mapping_one(struct dmar_domain *domain,
                goto out_unlock;
 
        ret = 0;
-       if (context_present(context))
+       if (context_present(context) && !context_copied(iommu, bus, devfn))
                goto out_unlock;
 
        /*
@@ -1925,7 +1942,7 @@ static int domain_context_mapping_one(struct dmar_domain *domain,
         * in-flight DMA will exist, and we don't need to worry anymore
         * hereafter.
         */
-       if (context_copied(context)) {
+       if (context_copied(iommu, bus, devfn)) {
                u16 did_old = context_domain_id(context);
 
                if (did_old < cap_ndoms(iommu->cap)) {
@@ -1936,6 +1953,8 @@ static int domain_context_mapping_one(struct dmar_domain *domain,
                        iommu->flush.flush_iotlb(iommu, did_old, 0, 0,
                                                 DMA_TLB_DSI_FLUSH);
                }
+
+               clear_context_copied(iommu, bus, devfn);
        }
 
        context_clear_entry(context);
@@ -2429,6 +2448,7 @@ static int domain_add_dev_info(struct dmar_domain *domain, struct device *dev)
 {
        struct device_domain_info *info = dev_iommu_priv_get(dev);
        struct intel_iommu *iommu;
+       unsigned long flags;
        u8 bus, devfn;
        int ret;
 
@@ -2440,9 +2460,9 @@ static int domain_add_dev_info(struct dmar_domain *domain, struct device *dev)
        if (ret)
                return ret;
        info->domain = domain;
-       spin_lock(&domain->lock);
+       spin_lock_irqsave(&domain->lock, flags);
        list_add(&info->link, &domain->devices);
-       spin_unlock(&domain->lock);
+       spin_unlock_irqrestore(&domain->lock, flags);
 
        /* PASID table is mandatory for a PCI device in scalable mode. */
        if (sm_supported(iommu) && !dev_is_real_dma_subdevice(dev)) {
@@ -2684,32 +2704,14 @@ static int copy_context_table(struct intel_iommu *iommu,
                /* Now copy the context entry */
                memcpy(&ce, old_ce + idx, sizeof(ce));
 
-               if (!__context_present(&ce))
+               if (!context_present(&ce))
                        continue;
 
                did = context_domain_id(&ce);
                if (did >= 0 && did < cap_ndoms(iommu->cap))
                        set_bit(did, iommu->domain_ids);
 
-               /*
-                * We need a marker for copied context entries. This
-                * marker needs to work for the old format as well as
-                * for extended context entries.
-                *
-                * Bit 67 of the context entry is used. In the old
-                * format this bit is available to software, in the
-                * extended format it is the PGE bit, but PGE is ignored
-                * by HW if PASIDs are disabled (and thus still
-                * available).
-                *
-                * So disable PASIDs first and then mark the entry
-                * copied. This means that we don't copy PASID
-                * translations from the old kernel, but this is fine as
-                * faults there are not fatal.
-                */
-               context_clear_pasid_enable(&ce);
-               context_set_copied(&ce);
-
+               set_context_copied(iommu, bus, devfn);
                new_ce[idx] = ce;
        }
 
@@ -2735,8 +2737,8 @@ static int copy_translation_tables(struct intel_iommu *iommu)
        bool new_ext, ext;
 
        rtaddr_reg = dmar_readq(iommu->reg + DMAR_RTADDR_REG);
-       ext        = !!(rtaddr_reg & DMA_RTADDR_RTT);
-       new_ext    = !!ecap_ecs(iommu->ecap);
+       ext        = !!(rtaddr_reg & DMA_RTADDR_SMT);
+       new_ext    = !!sm_supported(iommu);
 
        /*
         * The RTT bit can only be changed when translation is disabled,
@@ -2747,6 +2749,10 @@ static int copy_translation_tables(struct intel_iommu *iommu)
        if (new_ext != ext)
                return -EINVAL;
 
+       iommu->copied_tables = bitmap_zalloc(BIT_ULL(16), GFP_KERNEL);
+       if (!iommu->copied_tables)
+               return -ENOMEM;
+
        old_rt_phys = rtaddr_reg & VTD_PAGE_MASK;
        if (!old_rt_phys)
                return -EINVAL;
@@ -4080,6 +4086,7 @@ static void dmar_remove_one_dev_info(struct device *dev)
        struct device_domain_info *info = dev_iommu_priv_get(dev);
        struct dmar_domain *domain = info->domain;
        struct intel_iommu *iommu = info->iommu;
+       unsigned long flags;
 
        if (!dev_is_real_dma_subdevice(info->dev)) {
                if (dev_is_pci(info->dev) && sm_supported(iommu))
@@ -4091,9 +4098,9 @@ static void dmar_remove_one_dev_info(struct device *dev)
                intel_pasid_free_table(info->dev);
        }
 
-       spin_lock(&domain->lock);
+       spin_lock_irqsave(&domain->lock, flags);
        list_del(&info->link);
-       spin_unlock(&domain->lock);
+       spin_unlock_irqrestore(&domain->lock, flags);
 
        domain_detach_iommu(domain, iommu);
        info->domain = NULL;
@@ -4412,19 +4419,20 @@ static void domain_set_force_snooping(struct dmar_domain *domain)
 static bool intel_iommu_enforce_cache_coherency(struct iommu_domain *domain)
 {
        struct dmar_domain *dmar_domain = to_dmar_domain(domain);
+       unsigned long flags;
 
        if (dmar_domain->force_snooping)
                return true;
 
-       spin_lock(&dmar_domain->lock);
+       spin_lock_irqsave(&dmar_domain->lock, flags);
        if (!domain_support_force_snooping(dmar_domain)) {
-               spin_unlock(&dmar_domain->lock);
+               spin_unlock_irqrestore(&dmar_domain->lock, flags);
                return false;
        }
 
        domain_set_force_snooping(dmar_domain);
        dmar_domain->force_snooping = true;
-       spin_unlock(&dmar_domain->lock);
+       spin_unlock_irqrestore(&dmar_domain->lock, flags);
 
        return true;
 }
index fae45bb..74b0e19 100644 (file)
 #define ecap_dis(e)            (((e) >> 27) & 0x1)
 #define ecap_nest(e)           (((e) >> 26) & 0x1)
 #define ecap_mts(e)            (((e) >> 25) & 0x1)
-#define ecap_ecs(e)            (((e) >> 24) & 0x1)
 #define ecap_iotlb_offset(e)   ((((e) >> 8) & 0x3ff) * 16)
 #define ecap_max_iotlb_offset(e) (ecap_iotlb_offset(e) + 16)
 #define ecap_coherent(e)       ((e) & 0x1)
 #define DMA_GSTS_CFIS (((u32)1) << 23)
 
 /* DMA_RTADDR_REG */
-#define DMA_RTADDR_RTT (((u64)1) << 11)
 #define DMA_RTADDR_SMT (((u64)1) << 10)
 
 /* CCMD_REG */
@@ -579,6 +577,7 @@ struct intel_iommu {
 
 #ifdef CONFIG_INTEL_IOMMU
        unsigned long   *domain_ids; /* bitmap of domains */
+       unsigned long   *copied_tables; /* bitmap of copied tables */
        spinlock_t      lock; /* protect context, domain ids */
        struct root_entry *root_entry; /* virtual address */
 
@@ -701,6 +700,11 @@ static inline int nr_pte_to_next_page(struct dma_pte *pte)
                (struct dma_pte *)ALIGN((unsigned long)pte, VTD_PAGE_SIZE) - pte;
 }
 
+static inline bool context_present(struct context_entry *context)
+{
+       return (context->lo & 1);
+}
+
 extern struct dmar_drhd_unit * dmar_find_matched_drhd_unit(struct pci_dev *dev);
 
 extern int dmar_enable_qi(struct intel_iommu *iommu);
@@ -784,7 +788,6 @@ static inline void intel_iommu_debugfs_init(void) {}
 #endif /* CONFIG_INTEL_IOMMU_DEBUGFS */
 
 extern const struct attribute_group *intel_iommu_groups[];
-bool context_present(struct context_entry *context);
 struct context_entry *iommu_context_addr(struct intel_iommu *iommu, u8 bus,
                                         u8 devfn, int alloc);
 
index 780fb70..3a80814 100644 (file)
@@ -3076,6 +3076,24 @@ out:
        return ret;
 }
 
+static bool iommu_is_default_domain(struct iommu_group *group)
+{
+       if (group->domain == group->default_domain)
+               return true;
+
+       /*
+        * If the default domain was set to identity and it is still an identity
+        * domain then we consider this a pass. This happens because of
+        * amd_iommu_init_device() replacing the default idenytity domain with an
+        * identity domain that has a different configuration for AMDGPU.
+        */
+       if (group->default_domain &&
+           group->default_domain->type == IOMMU_DOMAIN_IDENTITY &&
+           group->domain && group->domain->type == IOMMU_DOMAIN_IDENTITY)
+               return true;
+       return false;
+}
+
 /**
  * iommu_device_use_default_domain() - Device driver wants to handle device
  *                                     DMA through the kernel DMA API.
@@ -3094,8 +3112,7 @@ int iommu_device_use_default_domain(struct device *dev)
 
        mutex_lock(&group->mutex);
        if (group->owner_cnt) {
-               if (group->domain != group->default_domain ||
-                   group->owner) {
+               if (group->owner || !iommu_is_default_domain(group)) {
                        ret = -EBUSY;
                        goto unlock_out;
                }
index 41f4eb0..5696314 100644 (file)
@@ -40,7 +40,7 @@ static int of_iommu_xlate(struct device *dev,
         * a proper probe-ordering dependency mechanism in future.
         */
        if (!ops)
-               return -ENODEV;
+               return driver_deferred_probe_check_state(dev);
 
        if (!try_module_get(ops->owner))
                return -ENODEV;
index 08eeafc..8015117 100644 (file)
@@ -1006,7 +1006,18 @@ static int viommu_of_xlate(struct device *dev, struct of_phandle_args *args)
        return iommu_fwspec_add_ids(dev, args->args, 1);
 }
 
+static bool viommu_capable(enum iommu_cap cap)
+{
+       switch (cap) {
+       case IOMMU_CAP_CACHE_COHERENCY:
+               return true;
+       default:
+               return false;
+       }
+}
+
 static struct iommu_ops viommu_ops = {
+       .capable                = viommu_capable,
        .domain_alloc           = viommu_domain_alloc,
        .probe_device           = viommu_probe_device,
        .probe_finalize         = viommu_probe_finalize,
index 327f3ab..741612b 100644 (file)
@@ -129,7 +129,7 @@ static int __init cpuintc_acpi_init(union acpi_subtable_headers *header,
        clear_csr_ecfg(ECFG0_IM);
        clear_csr_estat(ESTATF_IP);
 
-       cpuintc_handle = irq_domain_alloc_fwnode(NULL);
+       cpuintc_handle = irq_domain_alloc_named_fwnode("CPUINTC");
        irq_domain = irq_domain_create_linear(cpuintc_handle, EXCCODE_INT_NUM,
                                        &loongarch_cpu_intc_irq_domain_ops, NULL);
 
index 80d8ca6..16e9af8 100644 (file)
@@ -111,11 +111,15 @@ static int eiointc_set_irq_affinity(struct irq_data *d, const struct cpumask *af
        regaddr = EIOINTC_REG_ENABLE + ((vector >> 5) << 2);
 
        /* Mask target vector */
-       csr_any_send(regaddr, EIOINTC_ALL_ENABLE & (~BIT(vector & 0x1F)), 0x0, 0);
+       csr_any_send(regaddr, EIOINTC_ALL_ENABLE & (~BIT(vector & 0x1F)),
+                       0x0, priv->node * CORES_PER_EIO_NODE);
+
        /* Set route for target vector */
        eiointc_set_irq_route(vector, cpu, priv->node, &priv->node_map);
+
        /* Unmask target vector */
-       csr_any_send(regaddr, EIOINTC_ALL_ENABLE, 0x0, 0);
+       csr_any_send(regaddr, EIOINTC_ALL_ENABLE,
+                       0x0, priv->node * CORES_PER_EIO_NODE);
 
        irq_data_update_effective_affinity(d, cpumask_of(cpu));
 
@@ -286,7 +290,7 @@ static void acpi_set_vec_parent(int node, struct irq_domain *parent, struct acpi
        }
 }
 
-struct irq_domain *acpi_get_vec_parent(int node, struct acpi_vector_group *vec_group)
+static struct irq_domain *acpi_get_vec_parent(int node, struct acpi_vector_group *vec_group)
 {
        int i;
 
@@ -344,7 +348,8 @@ int __init eiointc_acpi_init(struct irq_domain *parent,
        if (!priv)
                return -ENOMEM;
 
-       priv->domain_handle = irq_domain_alloc_fwnode((phys_addr_t *)acpi_eiointc);
+       priv->domain_handle = irq_domain_alloc_named_id_fwnode("EIOPIC",
+                                                              acpi_eiointc->node);
        if (!priv->domain_handle) {
                pr_err("Unable to allocate domain handle\n");
                goto out_free_priv;
index c4f3c88..0da8716 100644 (file)
@@ -207,7 +207,7 @@ static int liointc_init(phys_addr_t addr, unsigned long size, int revision,
                                        "reg-names", core_reg_names[i]);
 
                        if (index < 0)
-                               return -EINVAL;
+                               goto out_iounmap;
 
                        priv->core_isr[i] = of_iomap(node, index);
                }
@@ -360,7 +360,7 @@ int __init liointc_acpi_init(struct irq_domain *parent, struct acpi_madt_lio_pic
        parent_irq[0] = irq_create_mapping(parent, acpi_liointc->cascade[0]);
        parent_irq[1] = irq_create_mapping(parent, acpi_liointc->cascade[1]);
 
-       domain_handle = irq_domain_alloc_fwnode((phys_addr_t *)acpi_liointc);
+       domain_handle = irq_domain_alloc_fwnode(&acpi_liointc->address);
        if (!domain_handle) {
                pr_err("Unable to allocate domain handle\n");
                return -ENOMEM;
index d0e8551..a72ede9 100644 (file)
@@ -282,7 +282,7 @@ int __init pch_msi_acpi_init(struct irq_domain *parent,
        int ret;
        struct fwnode_handle *domain_handle;
 
-       domain_handle = irq_domain_alloc_fwnode((phys_addr_t *)acpi_pchmsi);
+       domain_handle = irq_domain_alloc_fwnode(&acpi_pchmsi->msg_address);
        ret = pch_msi_init(acpi_pchmsi->msg_address, acpi_pchmsi->start,
                                acpi_pchmsi->count, parent, domain_handle);
        if (ret < 0)
index b6f1392..c01b9c2 100644 (file)
@@ -48,25 +48,6 @@ static struct pch_pic *pch_pic_priv[MAX_IO_PICS];
 
 struct fwnode_handle *pch_pic_handle[MAX_IO_PICS];
 
-int find_pch_pic(u32 gsi)
-{
-       int i;
-
-       /* Find the PCH_PIC that manages this GSI. */
-       for (i = 0; i < MAX_IO_PICS; i++) {
-               struct pch_pic *priv = pch_pic_priv[i];
-
-               if (!priv)
-                       return -1;
-
-               if (gsi >= priv->gsi_base && gsi < (priv->gsi_base + priv->vec_count))
-                       return i;
-       }
-
-       pr_err("ERROR: Unable to locate PCH_PIC for GSI %d\n", gsi);
-       return -1;
-}
-
 static void pch_pic_bitset(struct pch_pic *priv, int offset, int bit)
 {
        u32 reg;
@@ -325,6 +306,25 @@ IRQCHIP_DECLARE(pch_pic, "loongson,pch-pic-1.0", pch_pic_of_init);
 #endif
 
 #ifdef CONFIG_ACPI
+int find_pch_pic(u32 gsi)
+{
+       int i;
+
+       /* Find the PCH_PIC that manages this GSI. */
+       for (i = 0; i < MAX_IO_PICS; i++) {
+               struct pch_pic *priv = pch_pic_priv[i];
+
+               if (!priv)
+                       return -1;
+
+               if (gsi >= priv->gsi_base && gsi < (priv->gsi_base + priv->vec_count))
+                       return i;
+       }
+
+       pr_err("ERROR: Unable to locate PCH_PIC for GSI %d\n", gsi);
+       return -1;
+}
+
 static int __init
 pch_lpc_parse_madt(union acpi_subtable_headers *header,
                       const unsigned long end)
@@ -349,7 +349,7 @@ int __init pch_pic_acpi_init(struct irq_domain *parent,
 
        vec_base = acpi_pchpic->gsi_base - GSI_MIN_PCH_IRQ;
 
-       domain_handle = irq_domain_alloc_fwnode((phys_addr_t *)acpi_pchpic);
+       domain_handle = irq_domain_alloc_fwnode(&acpi_pchpic->address);
        if (!domain_handle) {
                pr_err("Unable to allocate domain handle\n");
                return -ENOMEM;
index afaf36b..729be2c 100644 (file)
@@ -5620,6 +5620,7 @@ struct mddev *md_alloc(dev_t dev, char *name)
         * removed (mddev_delayed_delete).
         */
        flush_workqueue(md_misc_wq);
+       flush_workqueue(md_rdev_misc_wq);
 
        mutex_lock(&disks_mutex);
        mddev = mddev_alloc(dev);
@@ -6238,11 +6239,11 @@ static void mddev_detach(struct mddev *mddev)
 static void __md_stop(struct mddev *mddev)
 {
        struct md_personality *pers = mddev->pers;
+       md_bitmap_destroy(mddev);
        mddev_detach(mddev);
        /* Ensure ->event_work is done */
        if (mddev->event_work.func)
                flush_workqueue(md_misc_wq);
-       md_bitmap_destroy(mddev);
        spin_lock(&mddev->lock);
        mddev->pers = NULL;
        spin_unlock(&mddev->lock);
@@ -6260,6 +6261,7 @@ void md_stop(struct mddev *mddev)
        /* stop the array and free an attached data structures.
         * This is called from dm-raid
         */
+       __md_stop_writes(mddev);
        __md_stop(mddev);
        bioset_exit(&mddev->bio_set);
        bioset_exit(&mddev->sync_set);
index 9117fcd..64d6e4c 100644 (file)
@@ -2639,18 +2639,18 @@ static void check_decay_read_errors(struct mddev *mddev, struct md_rdev *rdev)
 }
 
 static int r10_sync_page_io(struct md_rdev *rdev, sector_t sector,
-                           int sectors, struct page *page, int rw)
+                           int sectors, struct page *page, enum req_op op)
 {
        sector_t first_bad;
        int bad_sectors;
 
        if (is_badblock(rdev, sector, sectors, &first_bad, &bad_sectors)
-           && (rw == READ || test_bit(WriteErrorSeen, &rdev->flags)))
+           && (op == REQ_OP_READ || test_bit(WriteErrorSeen, &rdev->flags)))
                return -1;
-       if (sync_page_io(rdev, sector, sectors << 9, page, rw, false))
+       if (sync_page_io(rdev, sector, sectors << 9, page, op, false))
                /* success */
                return 1;
-       if (rw == WRITE) {
+       if (op == REQ_OP_WRITE) {
                set_bit(WriteErrorSeen, &rdev->flags);
                if (!test_and_set_bit(WantReplacement, &rdev->flags))
                        set_bit(MD_RECOVERY_NEEDED,
@@ -2780,7 +2780,7 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10
                        if (r10_sync_page_io(rdev,
                                             r10_bio->devs[sl].addr +
                                             sect,
-                                            s, conf->tmppage, WRITE)
+                                            s, conf->tmppage, REQ_OP_WRITE)
                            == 0) {
                                /* Well, this device is dead */
                                pr_notice("md/raid10:%s: read correction write failed (%d sectors at %llu on %pg)\n",
@@ -2814,8 +2814,7 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10
                        switch (r10_sync_page_io(rdev,
                                             r10_bio->devs[sl].addr +
                                             sect,
-                                            s, conf->tmppage,
-                                                READ)) {
+                                            s, conf->tmppage, REQ_OP_READ)) {
                        case 0:
                                /* Well, this device is dead */
                                pr_notice("md/raid10:%s: unable to read back corrected sectors (%d sectors at %llu on %pg)\n",
index 0834d5f..39d2b03 100644 (file)
@@ -1416,42 +1416,37 @@ static void mceusb_gen1_init(struct mceusb_dev *ir)
 {
        int ret;
        struct device *dev = ir->dev;
-       char *data;
-
-       data = kzalloc(USB_CTRL_MSG_SZ, GFP_KERNEL);
-       if (!data) {
-               dev_err(dev, "%s: memory allocation failed!", __func__);
-               return;
-       }
+       char data[USB_CTRL_MSG_SZ];
 
        /*
         * This is a strange one. Windows issues a set address to the device
         * on the receive control pipe and expect a certain value pair back
         */
-       ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0),
-                             USB_REQ_SET_ADDRESS, USB_TYPE_VENDOR, 0, 0,
-                             data, USB_CTRL_MSG_SZ, 3000);
+       ret = usb_control_msg_recv(ir->usbdev, 0, USB_REQ_SET_ADDRESS,
+                                  USB_DIR_IN | USB_TYPE_VENDOR,
+                                  0, 0, data, USB_CTRL_MSG_SZ, 3000,
+                                  GFP_KERNEL);
        dev_dbg(dev, "set address - ret = %d", ret);
        dev_dbg(dev, "set address - data[0] = %d, data[1] = %d",
                                                data[0], data[1]);
 
        /* set feature: bit rate 38400 bps */
-       ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0),
-                             USB_REQ_SET_FEATURE, USB_TYPE_VENDOR,
-                             0xc04e, 0x0000, NULL, 0, 3000);
+       ret = usb_control_msg_send(ir->usbdev, 0,
+                                  USB_REQ_SET_FEATURE, USB_TYPE_VENDOR,
+                                  0xc04e, 0x0000, NULL, 0, 3000, GFP_KERNEL);
 
        dev_dbg(dev, "set feature - ret = %d", ret);
 
        /* bRequest 4: set char length to 8 bits */
-       ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0),
-                             4, USB_TYPE_VENDOR,
-                             0x0808, 0x0000, NULL, 0, 3000);
+       ret = usb_control_msg_send(ir->usbdev, 0,
+                                  4, USB_TYPE_VENDOR,
+                                  0x0808, 0x0000, NULL, 0, 3000, GFP_KERNEL);
        dev_dbg(dev, "set char length - retB = %d", ret);
 
        /* bRequest 2: set handshaking to use DTR/DSR */
-       ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0),
-                             2, USB_TYPE_VENDOR,
-                             0x0000, 0x0100, NULL, 0, 3000);
+       ret = usb_control_msg_send(ir->usbdev, 0,
+                                  2, USB_TYPE_VENDOR,
+                                  0x0000, 0x0100, NULL, 0, 3000, GFP_KERNEL);
        dev_dbg(dev, "set handshake  - retC = %d", ret);
 
        /* device resume */
@@ -1459,8 +1454,6 @@ static void mceusb_gen1_init(struct mceusb_dev *ir)
 
        /* get hw/sw revision? */
        mce_command_out(ir, GET_REVISION, sizeof(GET_REVISION));
-
-       kfree(data);
 }
 
 static void mceusb_gen2_init(struct mceusb_dev *ir)
index 93ebd17..5d9e348 100644 (file)
@@ -25,7 +25,7 @@
 #define SDSP_DOMAIN_ID (2)
 #define CDSP_DOMAIN_ID (3)
 #define FASTRPC_DEV_MAX                4 /* adsp, mdsp, slpi, cdsp*/
-#define FASTRPC_MAX_SESSIONS   13 /*12 compute, 1 cpz*/
+#define FASTRPC_MAX_SESSIONS   14
 #define FASTRPC_MAX_VMIDS      16
 #define FASTRPC_ALIGN          128
 #define FASTRPC_MAX_FDLIST     16
@@ -1943,7 +1943,12 @@ static int fastrpc_cb_probe(struct platform_device *pdev)
        of_property_read_u32(dev->of_node, "qcom,nsessions", &sessions);
 
        spin_lock_irqsave(&cctx->lock, flags);
-       sess = &cctx->session[cctx->sesscount];
+       if (cctx->sesscount >= FASTRPC_MAX_SESSIONS) {
+               dev_err(&pdev->dev, "too many sessions\n");
+               spin_unlock_irqrestore(&cctx->lock, flags);
+               return -ENOSPC;
+       }
+       sess = &cctx->session[cctx->sesscount++];
        sess->used = false;
        sess->valid = true;
        sess->dev = dev;
@@ -1956,13 +1961,12 @@ static int fastrpc_cb_probe(struct platform_device *pdev)
                struct fastrpc_session_ctx *dup_sess;
 
                for (i = 1; i < sessions; i++) {
-                       if (cctx->sesscount++ >= FASTRPC_MAX_SESSIONS)
+                       if (cctx->sesscount >= FASTRPC_MAX_SESSIONS)
                                break;
-                       dup_sess = &cctx->session[cctx->sesscount];
+                       dup_sess = &cctx->session[cctx->sesscount++];
                        memcpy(dup_sess, sess, sizeof(*dup_sess));
                }
        }
-       cctx->sesscount++;
        spin_unlock_irqrestore(&cctx->lock, flags);
        rc = dma_set_mask(dev, DMA_BIT_MASK(32));
        if (rc) {
index cee4c0b..06aa62c 100644 (file)
@@ -949,16 +949,17 @@ int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,
 
                /* Erase init depends on CSD and SSR */
                mmc_init_erase(card);
-
-               /*
-                * Fetch switch information from card.
-                */
-               err = mmc_read_switch(card);
-               if (err)
-                       return err;
        }
 
        /*
+        * Fetch switch information from card. Note, sd3_bus_mode can change if
+        * voltage switch outcome changes, so do this always.
+        */
+       err = mmc_read_switch(card);
+       if (err)
+               return err;
+
+       /*
         * For SPI, enable CRC as appropriate.
         * This CRC enable is located AFTER the reading of the
         * card registers because some SDHC cards are not able
@@ -1480,26 +1481,15 @@ retry:
        if (!v18_fixup_failed && !mmc_host_is_spi(host) && mmc_host_uhs(host) &&
            mmc_sd_card_using_v18(card) &&
            host->ios.signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
-               /*
-                * Re-read switch information in case it has changed since
-                * oldcard was initialized.
-                */
-               if (oldcard) {
-                       err = mmc_read_switch(card);
-                       if (err)
-                               goto free_card;
-               }
-               if (mmc_sd_card_using_v18(card)) {
-                       if (mmc_host_set_uhs_voltage(host) ||
-                           mmc_sd_init_uhs_card(card)) {
-                               v18_fixup_failed = true;
-                               mmc_power_cycle(host, ocr);
-                               if (!oldcard)
-                                       mmc_remove_card(card);
-                               goto retry;
-                       }
-                       goto done;
+               if (mmc_host_set_uhs_voltage(host) ||
+                   mmc_sd_init_uhs_card(card)) {
+                       v18_fixup_failed = true;
+                       mmc_power_cycle(host, ocr);
+                       if (!oldcard)
+                               mmc_remove_card(card);
+                       goto retry;
                }
+               goto cont;
        }
 
        /* Initialization sequence for UHS-I cards */
@@ -1534,7 +1524,7 @@ retry:
                        mmc_set_bus_width(host, MMC_BUS_WIDTH_4);
                }
        }
-
+cont:
        if (!oldcard) {
                /* Read/parse the extension registers. */
                err = sd_read_ext_regs(card);
@@ -1566,7 +1556,7 @@ retry:
                err = -EINVAL;
                goto free_card;
        }
-done:
+
        host->card = card;
        return 0;
 
index 10c5639..e636088 100644 (file)
@@ -171,6 +171,7 @@ config MMC_SDHCI_OF_ASPEED
 config MMC_SDHCI_OF_ASPEED_TEST
        bool "Tests for the ASPEED SDHCI driver" if !KUNIT_ALL_TESTS
        depends on MMC_SDHCI_OF_ASPEED && KUNIT
+       depends on (MMC_SDHCI_OF_ASPEED=m || KUNIT=y)
        default KUNIT_ALL_TESTS
        help
          Enable KUnit tests for the ASPEED SDHCI driver. Select this
index 2f08d44..fc46299 100644 (file)
@@ -1172,8 +1172,10 @@ static int meson_mmc_probe(struct platform_device *pdev)
        }
 
        ret = device_reset_optional(&pdev->dev);
-       if (ret)
-               return dev_err_probe(&pdev->dev, ret, "device reset failed\n");
+       if (ret) {
+               dev_err_probe(&pdev->dev, ret, "device reset failed\n");
+               goto free_host;
+       }
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        host->regs = devm_ioremap_resource(&pdev->dev, res);
index 4ff73d1..69d7860 100644 (file)
@@ -2446,6 +2446,9 @@ static void msdc_cqe_disable(struct mmc_host *mmc, bool recovery)
        /* disable busy check */
        sdr_clr_bits(host->base + MSDC_PATCH_BIT1, MSDC_PB1_BUSY_CHECK_SEL);
 
+       val = readl(host->base + MSDC_INT);
+       writel(val, host->base + MSDC_INT);
+
        if (recovery) {
                sdr_set_field(host->base + MSDC_DMA_CTRL,
                              MSDC_DMA_CTRL_STOP, 1);
@@ -2932,11 +2935,14 @@ static int __maybe_unused msdc_suspend(struct device *dev)
        struct mmc_host *mmc = dev_get_drvdata(dev);
        struct msdc_host *host = mmc_priv(mmc);
        int ret;
+       u32 val;
 
        if (mmc->caps2 & MMC_CAP2_CQE) {
                ret = cqhci_suspend(mmc);
                if (ret)
                        return ret;
+               val = readl(host->base + MSDC_INT);
+               writel(val, host->base + MSDC_INT);
        }
 
        /*
index 0db9490..e4003f6 100644 (file)
@@ -648,7 +648,7 @@ static int pxamci_probe(struct platform_device *pdev)
 
        ret = pxamci_of_init(pdev, mmc);
        if (ret)
-               return ret;
+               goto out;
 
        host = mmc_priv(mmc);
        host->mmc = mmc;
@@ -672,7 +672,7 @@ static int pxamci_probe(struct platform_device *pdev)
 
        ret = pxamci_init_ocr(host);
        if (ret < 0)
-               return ret;
+               goto out;
 
        mmc->caps = 0;
        host->cmdat = 0;
index 4e90485..a7343d4 100644 (file)
@@ -349,6 +349,15 @@ static const struct sdhci_pltfm_data sdhci_dwcmshc_pdata = {
        .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
 };
 
+#ifdef CONFIG_ACPI
+static const struct sdhci_pltfm_data sdhci_dwcmshc_bf3_pdata = {
+       .ops = &sdhci_dwcmshc_ops,
+       .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
+       .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
+                  SDHCI_QUIRK2_ACMD23_BROKEN,
+};
+#endif
+
 static const struct sdhci_pltfm_data sdhci_dwcmshc_rk35xx_pdata = {
        .ops = &sdhci_dwcmshc_rk35xx_ops,
        .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
@@ -431,7 +440,10 @@ MODULE_DEVICE_TABLE(of, sdhci_dwcmshc_dt_ids);
 
 #ifdef CONFIG_ACPI
 static const struct acpi_device_id sdhci_dwcmshc_acpi_ids[] = {
-       { .id = "MLNXBF30" },
+       {
+               .id = "MLNXBF30",
+               .driver_data = (kernel_ulong_t)&sdhci_dwcmshc_bf3_pdata,
+       },
        {}
 };
 #endif
@@ -447,7 +459,7 @@ static int dwcmshc_probe(struct platform_device *pdev)
        int err;
        u32 extra;
 
-       pltfm_data = of_device_get_match_data(&pdev->dev);
+       pltfm_data = device_get_match_data(&pdev->dev);
        if (!pltfm_data) {
                dev_err(&pdev->dev, "Error: No device match data found\n");
                return -ENODEV;
index d7fb33c..184608b 100644 (file)
@@ -84,7 +84,8 @@ enum ad_link_speed_type {
 static const u8 null_mac_addr[ETH_ALEN + 2] __long_aligned = {
        0, 0, 0, 0, 0, 0
 };
-static u16 ad_ticks_per_sec;
+
+static const u16 ad_ticks_per_sec = 1000 / AD_TIMER_INTERVAL;
 static const int ad_delta_in_ticks = (AD_TIMER_INTERVAL * HZ) / 1000;
 
 static const u8 lacpdu_mcast_addr[ETH_ALEN + 2] __long_aligned =
@@ -2001,36 +2002,24 @@ void bond_3ad_initiate_agg_selection(struct bonding *bond, int timeout)
 /**
  * bond_3ad_initialize - initialize a bond's 802.3ad parameters and structures
  * @bond: bonding struct to work on
- * @tick_resolution: tick duration (millisecond resolution)
  *
  * Can be called only after the mac address of the bond is set.
  */
-void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution)
+void bond_3ad_initialize(struct bonding *bond)
 {
-       /* check that the bond is not initialized yet */
-       if (!MAC_ADDRESS_EQUAL(&(BOND_AD_INFO(bond).system.sys_mac_addr),
-                               bond->dev->dev_addr)) {
-
-               BOND_AD_INFO(bond).aggregator_identifier = 0;
-
-               BOND_AD_INFO(bond).system.sys_priority =
-                       bond->params.ad_actor_sys_prio;
-               if (is_zero_ether_addr(bond->params.ad_actor_system))
-                       BOND_AD_INFO(bond).system.sys_mac_addr =
-                           *((struct mac_addr *)bond->dev->dev_addr);
-               else
-                       BOND_AD_INFO(bond).system.sys_mac_addr =
-                           *((struct mac_addr *)bond->params.ad_actor_system);
-
-               /* initialize how many times this module is called in one
-                * second (should be about every 100ms)
-                */
-               ad_ticks_per_sec = tick_resolution;
+       BOND_AD_INFO(bond).aggregator_identifier = 0;
+       BOND_AD_INFO(bond).system.sys_priority =
+               bond->params.ad_actor_sys_prio;
+       if (is_zero_ether_addr(bond->params.ad_actor_system))
+               BOND_AD_INFO(bond).system.sys_mac_addr =
+                   *((struct mac_addr *)bond->dev->dev_addr);
+       else
+               BOND_AD_INFO(bond).system.sys_mac_addr =
+                   *((struct mac_addr *)bond->params.ad_actor_system);
 
-               bond_3ad_initiate_agg_selection(bond,
-                                               AD_AGGREGATOR_SELECTION_TIMER *
-                                               ad_ticks_per_sec);
-       }
+       bond_3ad_initiate_agg_selection(bond,
+                                       AD_AGGREGATOR_SELECTION_TIMER *
+                                       ad_ticks_per_sec);
 }
 
 /**
index 50e6084..5c2febe 100644 (file)
@@ -2081,7 +2081,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
                        /* Initialize AD with the number of times that the AD timer is called in 1 second
                         * can be called only after the mac address of the bond is set
                         */
-                       bond_3ad_initialize(bond, 1000/AD_TIMER_INTERVAL);
+                       bond_3ad_initialize(bond);
                } else {
                        SLAVE_AD_INFO(new_slave)->id =
                                SLAVE_AD_INFO(prev_slave)->id + 1;
@@ -3167,6 +3167,9 @@ static void bond_ns_send_all(struct bonding *bond, struct slave *slave)
 found:
                if (!ipv6_dev_get_saddr(dev_net(dst->dev), dst->dev, &targets[i], 0, &saddr))
                        bond_ns_send(slave, &targets[i], &saddr, tags);
+               else
+                       bond_ns_send(slave, &targets[i], &in6addr_any, tags);
+
                dst_release(dst);
                kfree(tags);
        }
@@ -3198,12 +3201,19 @@ static bool bond_has_this_ip6(struct bonding *bond, struct in6_addr *addr)
        return ret;
 }
 
-static void bond_validate_ns(struct bonding *bond, struct slave *slave,
+static void bond_validate_na(struct bonding *bond, struct slave *slave,
                             struct in6_addr *saddr, struct in6_addr *daddr)
 {
        int i;
 
-       if (ipv6_addr_any(saddr) || !bond_has_this_ip6(bond, daddr)) {
+       /* Ignore NAs that:
+        * 1. Source address is unspecified address.
+        * 2. Dest address is neither all-nodes multicast address nor
+        *    exist on bond interface.
+        */
+       if (ipv6_addr_any(saddr) ||
+           (!ipv6_addr_equal(daddr, &in6addr_linklocal_allnodes) &&
+            !bond_has_this_ip6(bond, daddr))) {
                slave_dbg(bond->dev, slave->dev, "%s: sip %pI6c tip %pI6c not found\n",
                          __func__, saddr, daddr);
                return;
@@ -3246,14 +3256,14 @@ static int bond_na_rcv(const struct sk_buff *skb, struct bonding *bond,
         * see bond_arp_rcv().
         */
        if (bond_is_active_slave(slave))
-               bond_validate_ns(bond, slave, saddr, daddr);
+               bond_validate_na(bond, slave, saddr, daddr);
        else if (curr_active_slave &&
                 time_after(slave_last_rx(bond, curr_active_slave),
                            curr_active_slave->last_link_up))
-               bond_validate_ns(bond, slave, saddr, daddr);
+               bond_validate_na(bond, slave, saddr, daddr);
        else if (curr_arp_slave &&
                 bond_time_in_interval(bond, slave_last_tx(curr_arp_slave), 1))
-               bond_validate_ns(bond, slave, saddr, daddr);
+               bond_validate_na(bond, slave, saddr, daddr);
 
 out:
        return RX_HANDLER_ANOTHER;
index 4b14d80..e4f446d 100644 (file)
@@ -613,6 +613,9 @@ int ksz9477_fdb_dump(struct ksz_device *dev, int port,
                        goto exit;
                }
 
+               if (!(ksz_data & ALU_VALID))
+                       continue;
+
                /* read ALU table */
                ksz9477_read_table(dev, alu_table);
 
index ed7d137..872aba6 100644 (file)
@@ -170,6 +170,13 @@ static const struct ksz_dev_ops ksz8_dev_ops = {
        .exit = ksz8_switch_exit,
 };
 
+static void ksz9477_phylink_mac_link_up(struct ksz_device *dev, int port,
+                                       unsigned int mode,
+                                       phy_interface_t interface,
+                                       struct phy_device *phydev, int speed,
+                                       int duplex, bool tx_pause,
+                                       bool rx_pause);
+
 static const struct ksz_dev_ops ksz9477_dev_ops = {
        .setup = ksz9477_setup,
        .get_port_addr = ksz9477_get_port_addr,
@@ -196,6 +203,7 @@ static const struct ksz_dev_ops ksz9477_dev_ops = {
        .mdb_del = ksz9477_mdb_del,
        .change_mtu = ksz9477_change_mtu,
        .max_mtu = ksz9477_max_mtu,
+       .phylink_mac_link_up = ksz9477_phylink_mac_link_up,
        .config_cpu_port = ksz9477_config_cpu_port,
        .enable_stp_addr = ksz9477_enable_stp_addr,
        .reset = ksz9477_reset_switch,
@@ -230,6 +238,7 @@ static const struct ksz_dev_ops lan937x_dev_ops = {
        .mdb_del = ksz9477_mdb_del,
        .change_mtu = lan937x_change_mtu,
        .max_mtu = ksz9477_max_mtu,
+       .phylink_mac_link_up = ksz9477_phylink_mac_link_up,
        .config_cpu_port = lan937x_config_cpu_port,
        .enable_stp_addr = ksz9477_enable_stp_addr,
        .reset = lan937x_reset_switch,
@@ -803,9 +812,15 @@ static void ksz_phylink_get_caps(struct dsa_switch *ds, int port,
        if (dev->info->supports_rgmii[port])
                phy_interface_set_rgmii(config->supported_interfaces);
 
-       if (dev->info->internal_phy[port])
+       if (dev->info->internal_phy[port]) {
                __set_bit(PHY_INTERFACE_MODE_INTERNAL,
                          config->supported_interfaces);
+               /* Compatibility for phylib's default interface type when the
+                * phy-mode property is absent
+                */
+               __set_bit(PHY_INTERFACE_MODE_GMII,
+                         config->supported_interfaces);
+       }
 
        if (dev->dev_ops->get_caps)
                dev->dev_ops->get_caps(dev, port, config);
@@ -962,6 +977,7 @@ static void ksz_update_port_member(struct ksz_device *dev, int port)
 static int ksz_setup(struct dsa_switch *ds)
 {
        struct ksz_device *dev = ds->priv;
+       struct ksz_port *p;
        const u16 *regs;
        int ret;
 
@@ -1001,6 +1017,14 @@ static int ksz_setup(struct dsa_switch *ds)
                        return ret;
        }
 
+       /* Start with learning disabled on standalone user ports, and enabled
+        * on the CPU port. In lack of other finer mechanisms, learning on the
+        * CPU port will avoid flooding bridge local addresses on the network
+        * in some cases.
+        */
+       p = &dev->ports[dev->cpu_port];
+       p->learning = true;
+
        /* start switch */
        regmap_update_bits(dev->regmap[0], regs[S_START_CTRL],
                           SW_START, SW_START);
@@ -1277,6 +1301,8 @@ void ksz_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
        ksz_pread8(dev, port, regs[P_STP_CTRL], &data);
        data &= ~(PORT_TX_ENABLE | PORT_RX_ENABLE | PORT_LEARN_DISABLE);
 
+       p = &dev->ports[port];
+
        switch (state) {
        case BR_STATE_DISABLED:
                data |= PORT_LEARN_DISABLE;
@@ -1286,9 +1312,13 @@ void ksz_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
                break;
        case BR_STATE_LEARNING:
                data |= PORT_RX_ENABLE;
+               if (!p->learning)
+                       data |= PORT_LEARN_DISABLE;
                break;
        case BR_STATE_FORWARDING:
                data |= (PORT_TX_ENABLE | PORT_RX_ENABLE);
+               if (!p->learning)
+                       data |= PORT_LEARN_DISABLE;
                break;
        case BR_STATE_BLOCKING:
                data |= PORT_LEARN_DISABLE;
@@ -1300,12 +1330,38 @@ void ksz_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
 
        ksz_pwrite8(dev, port, regs[P_STP_CTRL], data);
 
-       p = &dev->ports[port];
        p->stp_state = state;
 
        ksz_update_port_member(dev, port);
 }
 
+static int ksz_port_pre_bridge_flags(struct dsa_switch *ds, int port,
+                                    struct switchdev_brport_flags flags,
+                                    struct netlink_ext_ack *extack)
+{
+       if (flags.mask & ~BR_LEARNING)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int ksz_port_bridge_flags(struct dsa_switch *ds, int port,
+                                struct switchdev_brport_flags flags,
+                                struct netlink_ext_ack *extack)
+{
+       struct ksz_device *dev = ds->priv;
+       struct ksz_port *p = &dev->ports[port];
+
+       if (flags.mask & BR_LEARNING) {
+               p->learning = !!(flags.val & BR_LEARNING);
+
+               /* Make the change take effect immediately */
+               ksz_port_stp_state_set(ds, port, p->stp_state);
+       }
+
+       return 0;
+}
+
 static enum dsa_tag_protocol ksz_get_tag_protocol(struct dsa_switch *ds,
                                                  int port,
                                                  enum dsa_tag_protocol mp)
@@ -1609,13 +1665,13 @@ static void ksz_duplex_flowctrl(struct ksz_device *dev, int port, int duplex,
        ksz_prmw8(dev, port, regs[P_XMII_CTRL_0], mask, val);
 }
 
-static void ksz_phylink_mac_link_up(struct dsa_switch *ds, int port,
-                                   unsigned int mode,
-                                   phy_interface_t interface,
-                                   struct phy_device *phydev, int speed,
-                                   int duplex, bool tx_pause, bool rx_pause)
+static void ksz9477_phylink_mac_link_up(struct ksz_device *dev, int port,
+                                       unsigned int mode,
+                                       phy_interface_t interface,
+                                       struct phy_device *phydev, int speed,
+                                       int duplex, bool tx_pause,
+                                       bool rx_pause)
 {
-       struct ksz_device *dev = ds->priv;
        struct ksz_port *p;
 
        p = &dev->ports[port];
@@ -1629,6 +1685,15 @@ static void ksz_phylink_mac_link_up(struct dsa_switch *ds, int port,
        ksz_port_set_xmii_speed(dev, port, speed);
 
        ksz_duplex_flowctrl(dev, port, duplex, tx_pause, rx_pause);
+}
+
+static void ksz_phylink_mac_link_up(struct dsa_switch *ds, int port,
+                                   unsigned int mode,
+                                   phy_interface_t interface,
+                                   struct phy_device *phydev, int speed,
+                                   int duplex, bool tx_pause, bool rx_pause)
+{
+       struct ksz_device *dev = ds->priv;
 
        if (dev->dev_ops->phylink_mac_link_up)
                dev->dev_ops->phylink_mac_link_up(dev, port, mode, interface,
@@ -1719,6 +1784,8 @@ static const struct dsa_switch_ops ksz_switch_ops = {
        .port_bridge_join       = ksz_port_bridge_join,
        .port_bridge_leave      = ksz_port_bridge_leave,
        .port_stp_state_set     = ksz_port_stp_state_set,
+       .port_pre_bridge_flags  = ksz_port_pre_bridge_flags,
+       .port_bridge_flags      = ksz_port_bridge_flags,
        .port_fast_age          = ksz_port_fast_age,
        .port_vlan_filtering    = ksz_port_vlan_filtering,
        .port_vlan_add          = ksz_port_vlan_add,
index 764ada3..0d9520d 100644 (file)
@@ -65,6 +65,7 @@ struct ksz_chip_data {
 
 struct ksz_port {
        bool remove_tag;                /* Remove Tag flag set, for ksz8795 only */
+       bool learning;
        int stp_state;
        struct phy_device phydev;
 
index a4c6eb9..83dca91 100644 (file)
@@ -118,6 +118,9 @@ static int mv88e6060_setup_port(struct mv88e6060_priv *priv, int p)
        int addr = REG_PORT(p);
        int ret;
 
+       if (dsa_is_unused_port(priv->ds, p))
+               return 0;
+
        /* Do not force flow control, disable Ingress and Egress
         * Header tagging, disable VLAN tunneling, and set the port
         * state to Forwarding.  Additionally, if this is the CPU
index b4034b7..f8f19a8 100644 (file)
@@ -22,6 +22,7 @@
 #define VSC9959_NUM_PORTS              6
 
 #define VSC9959_TAS_GCL_ENTRY_MAX      63
+#define VSC9959_TAS_MIN_GATE_LEN_NS    33
 #define VSC9959_VCAP_POLICER_BASE      63
 #define VSC9959_VCAP_POLICER_MAX       383
 #define VSC9959_SWITCH_PCI_BAR         4
@@ -274,27 +275,98 @@ static const u32 vsc9959_rew_regmap[] = {
 
 static const u32 vsc9959_sys_regmap[] = {
        REG(SYS_COUNT_RX_OCTETS,                0x000000),
+       REG(SYS_COUNT_RX_UNICAST,               0x000004),
        REG(SYS_COUNT_RX_MULTICAST,             0x000008),
+       REG(SYS_COUNT_RX_BROADCAST,             0x00000c),
        REG(SYS_COUNT_RX_SHORTS,                0x000010),
        REG(SYS_COUNT_RX_FRAGMENTS,             0x000014),
        REG(SYS_COUNT_RX_JABBERS,               0x000018),
+       REG(SYS_COUNT_RX_CRC_ALIGN_ERRS,        0x00001c),
+       REG(SYS_COUNT_RX_SYM_ERRS,              0x000020),
        REG(SYS_COUNT_RX_64,                    0x000024),
        REG(SYS_COUNT_RX_65_127,                0x000028),
        REG(SYS_COUNT_RX_128_255,               0x00002c),
-       REG(SYS_COUNT_RX_256_1023,              0x000030),
-       REG(SYS_COUNT_RX_1024_1526,             0x000034),
-       REG(SYS_COUNT_RX_1527_MAX,              0x000038),
-       REG(SYS_COUNT_RX_LONGS,                 0x000044),
+       REG(SYS_COUNT_RX_256_511,               0x000030),
+       REG(SYS_COUNT_RX_512_1023,              0x000034),
+       REG(SYS_COUNT_RX_1024_1526,             0x000038),
+       REG(SYS_COUNT_RX_1527_MAX,              0x00003c),
+       REG(SYS_COUNT_RX_PAUSE,                 0x000040),
+       REG(SYS_COUNT_RX_CONTROL,               0x000044),
+       REG(SYS_COUNT_RX_LONGS,                 0x000048),
+       REG(SYS_COUNT_RX_CLASSIFIED_DROPS,      0x00004c),
+       REG(SYS_COUNT_RX_RED_PRIO_0,            0x000050),
+       REG(SYS_COUNT_RX_RED_PRIO_1,            0x000054),
+       REG(SYS_COUNT_RX_RED_PRIO_2,            0x000058),
+       REG(SYS_COUNT_RX_RED_PRIO_3,            0x00005c),
+       REG(SYS_COUNT_RX_RED_PRIO_4,            0x000060),
+       REG(SYS_COUNT_RX_RED_PRIO_5,            0x000064),
+       REG(SYS_COUNT_RX_RED_PRIO_6,            0x000068),
+       REG(SYS_COUNT_RX_RED_PRIO_7,            0x00006c),
+       REG(SYS_COUNT_RX_YELLOW_PRIO_0,         0x000070),
+       REG(SYS_COUNT_RX_YELLOW_PRIO_1,         0x000074),
+       REG(SYS_COUNT_RX_YELLOW_PRIO_2,         0x000078),
+       REG(SYS_COUNT_RX_YELLOW_PRIO_3,         0x00007c),
+       REG(SYS_COUNT_RX_YELLOW_PRIO_4,         0x000080),
+       REG(SYS_COUNT_RX_YELLOW_PRIO_5,         0x000084),
+       REG(SYS_COUNT_RX_YELLOW_PRIO_6,         0x000088),
+       REG(SYS_COUNT_RX_YELLOW_PRIO_7,         0x00008c),
+       REG(SYS_COUNT_RX_GREEN_PRIO_0,          0x000090),
+       REG(SYS_COUNT_RX_GREEN_PRIO_1,          0x000094),
+       REG(SYS_COUNT_RX_GREEN_PRIO_2,          0x000098),
+       REG(SYS_COUNT_RX_GREEN_PRIO_3,          0x00009c),
+       REG(SYS_COUNT_RX_GREEN_PRIO_4,          0x0000a0),
+       REG(SYS_COUNT_RX_GREEN_PRIO_5,          0x0000a4),
+       REG(SYS_COUNT_RX_GREEN_PRIO_6,          0x0000a8),
+       REG(SYS_COUNT_RX_GREEN_PRIO_7,          0x0000ac),
        REG(SYS_COUNT_TX_OCTETS,                0x000200),
+       REG(SYS_COUNT_TX_UNICAST,               0x000204),
+       REG(SYS_COUNT_TX_MULTICAST,             0x000208),
+       REG(SYS_COUNT_TX_BROADCAST,             0x00020c),
        REG(SYS_COUNT_TX_COLLISION,             0x000210),
        REG(SYS_COUNT_TX_DROPS,                 0x000214),
+       REG(SYS_COUNT_TX_PAUSE,                 0x000218),
        REG(SYS_COUNT_TX_64,                    0x00021c),
        REG(SYS_COUNT_TX_65_127,                0x000220),
-       REG(SYS_COUNT_TX_128_511,               0x000224),
-       REG(SYS_COUNT_TX_512_1023,              0x000228),
-       REG(SYS_COUNT_TX_1024_1526,             0x00022c),
-       REG(SYS_COUNT_TX_1527_MAX,              0x000230),
+       REG(SYS_COUNT_TX_128_255,               0x000224),
+       REG(SYS_COUNT_TX_256_511,               0x000228),
+       REG(SYS_COUNT_TX_512_1023,              0x00022c),
+       REG(SYS_COUNT_TX_1024_1526,             0x000230),
+       REG(SYS_COUNT_TX_1527_MAX,              0x000234),
+       REG(SYS_COUNT_TX_YELLOW_PRIO_0,         0x000238),
+       REG(SYS_COUNT_TX_YELLOW_PRIO_1,         0x00023c),
+       REG(SYS_COUNT_TX_YELLOW_PRIO_2,         0x000240),
+       REG(SYS_COUNT_TX_YELLOW_PRIO_3,         0x000244),
+       REG(SYS_COUNT_TX_YELLOW_PRIO_4,         0x000248),
+       REG(SYS_COUNT_TX_YELLOW_PRIO_5,         0x00024c),
+       REG(SYS_COUNT_TX_YELLOW_PRIO_6,         0x000250),
+       REG(SYS_COUNT_TX_YELLOW_PRIO_7,         0x000254),
+       REG(SYS_COUNT_TX_GREEN_PRIO_0,          0x000258),
+       REG(SYS_COUNT_TX_GREEN_PRIO_1,          0x00025c),
+       REG(SYS_COUNT_TX_GREEN_PRIO_2,          0x000260),
+       REG(SYS_COUNT_TX_GREEN_PRIO_3,          0x000264),
+       REG(SYS_COUNT_TX_GREEN_PRIO_4,          0x000268),
+       REG(SYS_COUNT_TX_GREEN_PRIO_5,          0x00026c),
+       REG(SYS_COUNT_TX_GREEN_PRIO_6,          0x000270),
+       REG(SYS_COUNT_TX_GREEN_PRIO_7,          0x000274),
        REG(SYS_COUNT_TX_AGING,                 0x000278),
+       REG(SYS_COUNT_DROP_LOCAL,               0x000400),
+       REG(SYS_COUNT_DROP_TAIL,                0x000404),
+       REG(SYS_COUNT_DROP_YELLOW_PRIO_0,       0x000408),
+       REG(SYS_COUNT_DROP_YELLOW_PRIO_1,       0x00040c),
+       REG(SYS_COUNT_DROP_YELLOW_PRIO_2,       0x000410),
+       REG(SYS_COUNT_DROP_YELLOW_PRIO_3,       0x000414),
+       REG(SYS_COUNT_DROP_YELLOW_PRIO_4,       0x000418),
+       REG(SYS_COUNT_DROP_YELLOW_PRIO_5,       0x00041c),
+       REG(SYS_COUNT_DROP_YELLOW_PRIO_6,       0x000420),
+       REG(SYS_COUNT_DROP_YELLOW_PRIO_7,       0x000424),
+       REG(SYS_COUNT_DROP_GREEN_PRIO_0,        0x000428),
+       REG(SYS_COUNT_DROP_GREEN_PRIO_1,        0x00042c),
+       REG(SYS_COUNT_DROP_GREEN_PRIO_2,        0x000430),
+       REG(SYS_COUNT_DROP_GREEN_PRIO_3,        0x000434),
+       REG(SYS_COUNT_DROP_GREEN_PRIO_4,        0x000438),
+       REG(SYS_COUNT_DROP_GREEN_PRIO_5,        0x00043c),
+       REG(SYS_COUNT_DROP_GREEN_PRIO_6,        0x000440),
+       REG(SYS_COUNT_DROP_GREEN_PRIO_7,        0x000444),
        REG(SYS_RESET_CFG,                      0x000e00),
        REG(SYS_SR_ETYPE_CFG,                   0x000e04),
        REG(SYS_VLAN_ETYPE_CFG,                 0x000e08),
@@ -547,100 +619,379 @@ static const struct reg_field vsc9959_regfields[REGFIELD_MAX] = {
        [SYS_PAUSE_CFG_PAUSE_ENA] = REG_FIELD_ID(SYS_PAUSE_CFG, 0, 1, 7, 4),
 };
 
-static const struct ocelot_stat_layout vsc9959_stats_layout[] = {
-       { .offset = 0x00,       .name = "rx_octets", },
-       { .offset = 0x01,       .name = "rx_unicast", },
-       { .offset = 0x02,       .name = "rx_multicast", },
-       { .offset = 0x03,       .name = "rx_broadcast", },
-       { .offset = 0x04,       .name = "rx_shorts", },
-       { .offset = 0x05,       .name = "rx_fragments", },
-       { .offset = 0x06,       .name = "rx_jabbers", },
-       { .offset = 0x07,       .name = "rx_crc_align_errs", },
-       { .offset = 0x08,       .name = "rx_sym_errs", },
-       { .offset = 0x09,       .name = "rx_frames_below_65_octets", },
-       { .offset = 0x0A,       .name = "rx_frames_65_to_127_octets", },
-       { .offset = 0x0B,       .name = "rx_frames_128_to_255_octets", },
-       { .offset = 0x0C,       .name = "rx_frames_256_to_511_octets", },
-       { .offset = 0x0D,       .name = "rx_frames_512_to_1023_octets", },
-       { .offset = 0x0E,       .name = "rx_frames_1024_to_1526_octets", },
-       { .offset = 0x0F,       .name = "rx_frames_over_1526_octets", },
-       { .offset = 0x10,       .name = "rx_pause", },
-       { .offset = 0x11,       .name = "rx_control", },
-       { .offset = 0x12,       .name = "rx_longs", },
-       { .offset = 0x13,       .name = "rx_classified_drops", },
-       { .offset = 0x14,       .name = "rx_red_prio_0", },
-       { .offset = 0x15,       .name = "rx_red_prio_1", },
-       { .offset = 0x16,       .name = "rx_red_prio_2", },
-       { .offset = 0x17,       .name = "rx_red_prio_3", },
-       { .offset = 0x18,       .name = "rx_red_prio_4", },
-       { .offset = 0x19,       .name = "rx_red_prio_5", },
-       { .offset = 0x1A,       .name = "rx_red_prio_6", },
-       { .offset = 0x1B,       .name = "rx_red_prio_7", },
-       { .offset = 0x1C,       .name = "rx_yellow_prio_0", },
-       { .offset = 0x1D,       .name = "rx_yellow_prio_1", },
-       { .offset = 0x1E,       .name = "rx_yellow_prio_2", },
-       { .offset = 0x1F,       .name = "rx_yellow_prio_3", },
-       { .offset = 0x20,       .name = "rx_yellow_prio_4", },
-       { .offset = 0x21,       .name = "rx_yellow_prio_5", },
-       { .offset = 0x22,       .name = "rx_yellow_prio_6", },
-       { .offset = 0x23,       .name = "rx_yellow_prio_7", },
-       { .offset = 0x24,       .name = "rx_green_prio_0", },
-       { .offset = 0x25,       .name = "rx_green_prio_1", },
-       { .offset = 0x26,       .name = "rx_green_prio_2", },
-       { .offset = 0x27,       .name = "rx_green_prio_3", },
-       { .offset = 0x28,       .name = "rx_green_prio_4", },
-       { .offset = 0x29,       .name = "rx_green_prio_5", },
-       { .offset = 0x2A,       .name = "rx_green_prio_6", },
-       { .offset = 0x2B,       .name = "rx_green_prio_7", },
-       { .offset = 0x80,       .name = "tx_octets", },
-       { .offset = 0x81,       .name = "tx_unicast", },
-       { .offset = 0x82,       .name = "tx_multicast", },
-       { .offset = 0x83,       .name = "tx_broadcast", },
-       { .offset = 0x84,       .name = "tx_collision", },
-       { .offset = 0x85,       .name = "tx_drops", },
-       { .offset = 0x86,       .name = "tx_pause", },
-       { .offset = 0x87,       .name = "tx_frames_below_65_octets", },
-       { .offset = 0x88,       .name = "tx_frames_65_to_127_octets", },
-       { .offset = 0x89,       .name = "tx_frames_128_255_octets", },
-       { .offset = 0x8B,       .name = "tx_frames_256_511_octets", },
-       { .offset = 0x8C,       .name = "tx_frames_1024_1526_octets", },
-       { .offset = 0x8D,       .name = "tx_frames_over_1526_octets", },
-       { .offset = 0x8E,       .name = "tx_yellow_prio_0", },
-       { .offset = 0x8F,       .name = "tx_yellow_prio_1", },
-       { .offset = 0x90,       .name = "tx_yellow_prio_2", },
-       { .offset = 0x91,       .name = "tx_yellow_prio_3", },
-       { .offset = 0x92,       .name = "tx_yellow_prio_4", },
-       { .offset = 0x93,       .name = "tx_yellow_prio_5", },
-       { .offset = 0x94,       .name = "tx_yellow_prio_6", },
-       { .offset = 0x95,       .name = "tx_yellow_prio_7", },
-       { .offset = 0x96,       .name = "tx_green_prio_0", },
-       { .offset = 0x97,       .name = "tx_green_prio_1", },
-       { .offset = 0x98,       .name = "tx_green_prio_2", },
-       { .offset = 0x99,       .name = "tx_green_prio_3", },
-       { .offset = 0x9A,       .name = "tx_green_prio_4", },
-       { .offset = 0x9B,       .name = "tx_green_prio_5", },
-       { .offset = 0x9C,       .name = "tx_green_prio_6", },
-       { .offset = 0x9D,       .name = "tx_green_prio_7", },
-       { .offset = 0x9E,       .name = "tx_aged", },
-       { .offset = 0x100,      .name = "drop_local", },
-       { .offset = 0x101,      .name = "drop_tail", },
-       { .offset = 0x102,      .name = "drop_yellow_prio_0", },
-       { .offset = 0x103,      .name = "drop_yellow_prio_1", },
-       { .offset = 0x104,      .name = "drop_yellow_prio_2", },
-       { .offset = 0x105,      .name = "drop_yellow_prio_3", },
-       { .offset = 0x106,      .name = "drop_yellow_prio_4", },
-       { .offset = 0x107,      .name = "drop_yellow_prio_5", },
-       { .offset = 0x108,      .name = "drop_yellow_prio_6", },
-       { .offset = 0x109,      .name = "drop_yellow_prio_7", },
-       { .offset = 0x10A,      .name = "drop_green_prio_0", },
-       { .offset = 0x10B,      .name = "drop_green_prio_1", },
-       { .offset = 0x10C,      .name = "drop_green_prio_2", },
-       { .offset = 0x10D,      .name = "drop_green_prio_3", },
-       { .offset = 0x10E,      .name = "drop_green_prio_4", },
-       { .offset = 0x10F,      .name = "drop_green_prio_5", },
-       { .offset = 0x110,      .name = "drop_green_prio_6", },
-       { .offset = 0x111,      .name = "drop_green_prio_7", },
-       OCELOT_STAT_END
+static const struct ocelot_stat_layout vsc9959_stats_layout[OCELOT_NUM_STATS] = {
+       [OCELOT_STAT_RX_OCTETS] = {
+               .name = "rx_octets",
+               .reg = SYS_COUNT_RX_OCTETS,
+       },
+       [OCELOT_STAT_RX_UNICAST] = {
+               .name = "rx_unicast",
+               .reg = SYS_COUNT_RX_UNICAST,
+       },
+       [OCELOT_STAT_RX_MULTICAST] = {
+               .name = "rx_multicast",
+               .reg = SYS_COUNT_RX_MULTICAST,
+       },
+       [OCELOT_STAT_RX_BROADCAST] = {
+               .name = "rx_broadcast",
+               .reg = SYS_COUNT_RX_BROADCAST,
+       },
+       [OCELOT_STAT_RX_SHORTS] = {
+               .name = "rx_shorts",
+               .reg = SYS_COUNT_RX_SHORTS,
+       },
+       [OCELOT_STAT_RX_FRAGMENTS] = {
+               .name = "rx_fragments",
+               .reg = SYS_COUNT_RX_FRAGMENTS,
+       },
+       [OCELOT_STAT_RX_JABBERS] = {
+               .name = "rx_jabbers",
+               .reg = SYS_COUNT_RX_JABBERS,
+       },
+       [OCELOT_STAT_RX_CRC_ALIGN_ERRS] = {
+               .name = "rx_crc_align_errs",
+               .reg = SYS_COUNT_RX_CRC_ALIGN_ERRS,
+       },
+       [OCELOT_STAT_RX_SYM_ERRS] = {
+               .name = "rx_sym_errs",
+               .reg = SYS_COUNT_RX_SYM_ERRS,
+       },
+       [OCELOT_STAT_RX_64] = {
+               .name = "rx_frames_below_65_octets",
+               .reg = SYS_COUNT_RX_64,
+       },
+       [OCELOT_STAT_RX_65_127] = {
+               .name = "rx_frames_65_to_127_octets",
+               .reg = SYS_COUNT_RX_65_127,
+       },
+       [OCELOT_STAT_RX_128_255] = {
+               .name = "rx_frames_128_to_255_octets",
+               .reg = SYS_COUNT_RX_128_255,
+       },
+       [OCELOT_STAT_RX_256_511] = {
+               .name = "rx_frames_256_to_511_octets",
+               .reg = SYS_COUNT_RX_256_511,
+       },
+       [OCELOT_STAT_RX_512_1023] = {
+               .name = "rx_frames_512_to_1023_octets",
+               .reg = SYS_COUNT_RX_512_1023,
+       },
+       [OCELOT_STAT_RX_1024_1526] = {
+               .name = "rx_frames_1024_to_1526_octets",
+               .reg = SYS_COUNT_RX_1024_1526,
+       },
+       [OCELOT_STAT_RX_1527_MAX] = {
+               .name = "rx_frames_over_1526_octets",
+               .reg = SYS_COUNT_RX_1527_MAX,
+       },
+       [OCELOT_STAT_RX_PAUSE] = {
+               .name = "rx_pause",
+               .reg = SYS_COUNT_RX_PAUSE,
+       },
+       [OCELOT_STAT_RX_CONTROL] = {
+               .name = "rx_control",
+               .reg = SYS_COUNT_RX_CONTROL,
+       },
+       [OCELOT_STAT_RX_LONGS] = {
+               .name = "rx_longs",
+               .reg = SYS_COUNT_RX_LONGS,
+       },
+       [OCELOT_STAT_RX_CLASSIFIED_DROPS] = {
+               .name = "rx_classified_drops",
+               .reg = SYS_COUNT_RX_CLASSIFIED_DROPS,
+       },
+       [OCELOT_STAT_RX_RED_PRIO_0] = {
+               .name = "rx_red_prio_0",
+               .reg = SYS_COUNT_RX_RED_PRIO_0,
+       },
+       [OCELOT_STAT_RX_RED_PRIO_1] = {
+               .name = "rx_red_prio_1",
+               .reg = SYS_COUNT_RX_RED_PRIO_1,
+       },
+       [OCELOT_STAT_RX_RED_PRIO_2] = {
+               .name = "rx_red_prio_2",
+               .reg = SYS_COUNT_RX_RED_PRIO_2,
+       },
+       [OCELOT_STAT_RX_RED_PRIO_3] = {
+               .name = "rx_red_prio_3",
+               .reg = SYS_COUNT_RX_RED_PRIO_3,
+       },
+       [OCELOT_STAT_RX_RED_PRIO_4] = {
+               .name = "rx_red_prio_4",
+               .reg = SYS_COUNT_RX_RED_PRIO_4,
+       },
+       [OCELOT_STAT_RX_RED_PRIO_5] = {
+               .name = "rx_red_prio_5",
+               .reg = SYS_COUNT_RX_RED_PRIO_5,
+       },
+       [OCELOT_STAT_RX_RED_PRIO_6] = {
+               .name = "rx_red_prio_6",
+               .reg = SYS_COUNT_RX_RED_PRIO_6,
+       },
+       [OCELOT_STAT_RX_RED_PRIO_7] = {
+               .name = "rx_red_prio_7",
+               .reg = SYS_COUNT_RX_RED_PRIO_7,
+       },
+       [OCELOT_STAT_RX_YELLOW_PRIO_0] = {
+               .name = "rx_yellow_prio_0",
+               .reg = SYS_COUNT_RX_YELLOW_PRIO_0,
+       },
+       [OCELOT_STAT_RX_YELLOW_PRIO_1] = {
+               .name = "rx_yellow_prio_1",
+               .reg = SYS_COUNT_RX_YELLOW_PRIO_1,
+       },
+       [OCELOT_STAT_RX_YELLOW_PRIO_2] = {
+               .name = "rx_yellow_prio_2",
+               .reg = SYS_COUNT_RX_YELLOW_PRIO_2,
+       },
+       [OCELOT_STAT_RX_YELLOW_PRIO_3] = {
+               .name = "rx_yellow_prio_3",
+               .reg = SYS_COUNT_RX_YELLOW_PRIO_3,
+       },
+       [OCELOT_STAT_RX_YELLOW_PRIO_4] = {
+               .name = "rx_yellow_prio_4",
+               .reg = SYS_COUNT_RX_YELLOW_PRIO_4,
+       },
+       [OCELOT_STAT_RX_YELLOW_PRIO_5] = {
+               .name = "rx_yellow_prio_5",
+               .reg = SYS_COUNT_RX_YELLOW_PRIO_5,
+       },
+       [OCELOT_STAT_RX_YELLOW_PRIO_6] = {
+               .name = "rx_yellow_prio_6",
+               .reg = SYS_COUNT_RX_YELLOW_PRIO_6,
+       },
+       [OCELOT_STAT_RX_YELLOW_PRIO_7] = {
+               .name = "rx_yellow_prio_7",
+               .reg = SYS_COUNT_RX_YELLOW_PRIO_7,
+       },
+       [OCELOT_STAT_RX_GREEN_PRIO_0] = {
+               .name = "rx_green_prio_0",
+               .reg = SYS_COUNT_RX_GREEN_PRIO_0,
+       },
+       [OCELOT_STAT_RX_GREEN_PRIO_1] = {
+               .name = "rx_green_prio_1",
+               .reg = SYS_COUNT_RX_GREEN_PRIO_1,
+       },
+       [OCELOT_STAT_RX_GREEN_PRIO_2] = {
+               .name = "rx_green_prio_2",
+               .reg = SYS_COUNT_RX_GREEN_PRIO_2,
+       },
+       [OCELOT_STAT_RX_GREEN_PRIO_3] = {
+               .name = "rx_green_prio_3",
+               .reg = SYS_COUNT_RX_GREEN_PRIO_3,
+       },
+       [OCELOT_STAT_RX_GREEN_PRIO_4] = {
+               .name = "rx_green_prio_4",
+               .reg = SYS_COUNT_RX_GREEN_PRIO_4,
+       },
+       [OCELOT_STAT_RX_GREEN_PRIO_5] = {
+               .name = "rx_green_prio_5",
+               .reg = SYS_COUNT_RX_GREEN_PRIO_5,
+       },
+       [OCELOT_STAT_RX_GREEN_PRIO_6] = {
+               .name = "rx_green_prio_6",
+               .reg = SYS_COUNT_RX_GREEN_PRIO_6,
+       },
+       [OCELOT_STAT_RX_GREEN_PRIO_7] = {
+               .name = "rx_green_prio_7",
+               .reg = SYS_COUNT_RX_GREEN_PRIO_7,
+       },
+       [OCELOT_STAT_TX_OCTETS] = {
+               .name = "tx_octets",
+               .reg = SYS_COUNT_TX_OCTETS,
+       },
+       [OCELOT_STAT_TX_UNICAST] = {
+               .name = "tx_unicast",
+               .reg = SYS_COUNT_TX_UNICAST,
+       },
+       [OCELOT_STAT_TX_MULTICAST] = {
+               .name = "tx_multicast",
+               .reg = SYS_COUNT_TX_MULTICAST,
+       },
+       [OCELOT_STAT_TX_BROADCAST] = {
+               .name = "tx_broadcast",
+               .reg = SYS_COUNT_TX_BROADCAST,
+       },
+       [OCELOT_STAT_TX_COLLISION] = {
+               .name = "tx_collision",
+               .reg = SYS_COUNT_TX_COLLISION,
+       },
+       [OCELOT_STAT_TX_DROPS] = {
+               .name = "tx_drops",
+               .reg = SYS_COUNT_TX_DROPS,
+       },
+       [OCELOT_STAT_TX_PAUSE] = {
+               .name = "tx_pause",
+               .reg = SYS_COUNT_TX_PAUSE,
+       },
+       [OCELOT_STAT_TX_64] = {
+               .name = "tx_frames_below_65_octets",
+               .reg = SYS_COUNT_TX_64,
+       },
+       [OCELOT_STAT_TX_65_127] = {
+               .name = "tx_frames_65_to_127_octets",
+               .reg = SYS_COUNT_TX_65_127,
+       },
+       [OCELOT_STAT_TX_128_255] = {
+               .name = "tx_frames_128_255_octets",
+               .reg = SYS_COUNT_TX_128_255,
+       },
+       [OCELOT_STAT_TX_256_511] = {
+               .name = "tx_frames_256_511_octets",
+               .reg = SYS_COUNT_TX_256_511,
+       },
+       [OCELOT_STAT_TX_512_1023] = {
+               .name = "tx_frames_512_1023_octets",
+               .reg = SYS_COUNT_TX_512_1023,
+       },
+       [OCELOT_STAT_TX_1024_1526] = {
+               .name = "tx_frames_1024_1526_octets",
+               .reg = SYS_COUNT_TX_1024_1526,
+       },
+       [OCELOT_STAT_TX_1527_MAX] = {
+               .name = "tx_frames_over_1526_octets",
+               .reg = SYS_COUNT_TX_1527_MAX,
+       },
+       [OCELOT_STAT_TX_YELLOW_PRIO_0] = {
+               .name = "tx_yellow_prio_0",
+               .reg = SYS_COUNT_TX_YELLOW_PRIO_0,
+       },
+       [OCELOT_STAT_TX_YELLOW_PRIO_1] = {
+               .name = "tx_yellow_prio_1",
+               .reg = SYS_COUNT_TX_YELLOW_PRIO_1,
+       },
+       [OCELOT_STAT_TX_YELLOW_PRIO_2] = {
+               .name = "tx_yellow_prio_2",
+               .reg = SYS_COUNT_TX_YELLOW_PRIO_2,
+       },
+       [OCELOT_STAT_TX_YELLOW_PRIO_3] = {
+               .name = "tx_yellow_prio_3",
+               .reg = SYS_COUNT_TX_YELLOW_PRIO_3,
+       },
+       [OCELOT_STAT_TX_YELLOW_PRIO_4] = {
+               .name = "tx_yellow_prio_4",
+               .reg = SYS_COUNT_TX_YELLOW_PRIO_4,
+       },
+       [OCELOT_STAT_TX_YELLOW_PRIO_5] = {
+               .name = "tx_yellow_prio_5",
+               .reg = SYS_COUNT_TX_YELLOW_PRIO_5,
+       },
+       [OCELOT_STAT_TX_YELLOW_PRIO_6] = {
+               .name = "tx_yellow_prio_6",
+               .reg = SYS_COUNT_TX_YELLOW_PRIO_6,
+       },
+       [OCELOT_STAT_TX_YELLOW_PRIO_7] = {
+               .name = "tx_yellow_prio_7",
+               .reg = SYS_COUNT_TX_YELLOW_PRIO_7,
+       },
+       [OCELOT_STAT_TX_GREEN_PRIO_0] = {
+               .name = "tx_green_prio_0",
+               .reg = SYS_COUNT_TX_GREEN_PRIO_0,
+       },
+       [OCELOT_STAT_TX_GREEN_PRIO_1] = {
+               .name = "tx_green_prio_1",
+               .reg = SYS_COUNT_TX_GREEN_PRIO_1,
+       },
+       [OCELOT_STAT_TX_GREEN_PRIO_2] = {
+               .name = "tx_green_prio_2",
+               .reg = SYS_COUNT_TX_GREEN_PRIO_2,
+       },
+       [OCELOT_STAT_TX_GREEN_PRIO_3] = {
+               .name = "tx_green_prio_3",
+               .reg = SYS_COUNT_TX_GREEN_PRIO_3,
+       },
+       [OCELOT_STAT_TX_GREEN_PRIO_4] = {
+               .name = "tx_green_prio_4",
+               .reg = SYS_COUNT_TX_GREEN_PRIO_4,
+       },
+       [OCELOT_STAT_TX_GREEN_PRIO_5] = {
+               .name = "tx_green_prio_5",
+               .reg = SYS_COUNT_TX_GREEN_PRIO_5,
+       },
+       [OCELOT_STAT_TX_GREEN_PRIO_6] = {
+               .name = "tx_green_prio_6",
+               .reg = SYS_COUNT_TX_GREEN_PRIO_6,
+       },
+       [OCELOT_STAT_TX_GREEN_PRIO_7] = {
+               .name = "tx_green_prio_7",
+               .reg = SYS_COUNT_TX_GREEN_PRIO_7,
+       },
+       [OCELOT_STAT_TX_AGED] = {
+               .name = "tx_aged",
+               .reg = SYS_COUNT_TX_AGING,
+       },
+       [OCELOT_STAT_DROP_LOCAL] = {
+               .name = "drop_local",
+               .reg = SYS_COUNT_DROP_LOCAL,
+       },
+       [OCELOT_STAT_DROP_TAIL] = {
+               .name = "drop_tail",
+               .reg = SYS_COUNT_DROP_TAIL,
+       },
+       [OCELOT_STAT_DROP_YELLOW_PRIO_0] = {
+               .name = "drop_yellow_prio_0",
+               .reg = SYS_COUNT_DROP_YELLOW_PRIO_0,
+       },
+       [OCELOT_STAT_DROP_YELLOW_PRIO_1] = {
+               .name = "drop_yellow_prio_1",
+               .reg = SYS_COUNT_DROP_YELLOW_PRIO_1,
+       },
+       [OCELOT_STAT_DROP_YELLOW_PRIO_2] = {
+               .name = "drop_yellow_prio_2",
+               .reg = SYS_COUNT_DROP_YELLOW_PRIO_2,
+       },
+       [OCELOT_STAT_DROP_YELLOW_PRIO_3] = {
+               .name = "drop_yellow_prio_3",
+               .reg = SYS_COUNT_DROP_YELLOW_PRIO_3,
+       },
+       [OCELOT_STAT_DROP_YELLOW_PRIO_4] = {
+               .name = "drop_yellow_prio_4",
+               .reg = SYS_COUNT_DROP_YELLOW_PRIO_4,
+       },
+       [OCELOT_STAT_DROP_YELLOW_PRIO_5] = {
+               .name = "drop_yellow_prio_5",
+               .reg = SYS_COUNT_DROP_YELLOW_PRIO_5,
+       },
+       [OCELOT_STAT_DROP_YELLOW_PRIO_6] = {
+               .name = "drop_yellow_prio_6",
+               .reg = SYS_COUNT_DROP_YELLOW_PRIO_6,
+       },
+       [OCELOT_STAT_DROP_YELLOW_PRIO_7] = {
+               .name = "drop_yellow_prio_7",
+               .reg = SYS_COUNT_DROP_YELLOW_PRIO_7,
+       },
+       [OCELOT_STAT_DROP_GREEN_PRIO_0] = {
+               .name = "drop_green_prio_0",
+               .reg = SYS_COUNT_DROP_GREEN_PRIO_0,
+       },
+       [OCELOT_STAT_DROP_GREEN_PRIO_1] = {
+               .name = "drop_green_prio_1",
+               .reg = SYS_COUNT_DROP_GREEN_PRIO_1,
+       },
+       [OCELOT_STAT_DROP_GREEN_PRIO_2] = {
+               .name = "drop_green_prio_2",
+               .reg = SYS_COUNT_DROP_GREEN_PRIO_2,
+       },
+       [OCELOT_STAT_DROP_GREEN_PRIO_3] = {
+               .name = "drop_green_prio_3",
+               .reg = SYS_COUNT_DROP_GREEN_PRIO_3,
+       },
+       [OCELOT_STAT_DROP_GREEN_PRIO_4] = {
+               .name = "drop_green_prio_4",
+               .reg = SYS_COUNT_DROP_GREEN_PRIO_4,
+       },
+       [OCELOT_STAT_DROP_GREEN_PRIO_5] = {
+               .name = "drop_green_prio_5",
+               .reg = SYS_COUNT_DROP_GREEN_PRIO_5,
+       },
+       [OCELOT_STAT_DROP_GREEN_PRIO_6] = {
+               .name = "drop_green_prio_6",
+               .reg = SYS_COUNT_DROP_GREEN_PRIO_6,
+       },
+       [OCELOT_STAT_DROP_GREEN_PRIO_7] = {
+               .name = "drop_green_prio_7",
+               .reg = SYS_COUNT_DROP_GREEN_PRIO_7,
+       },
 };
 
 static const struct vcap_field vsc9959_vcap_es0_keys[] = {
@@ -1128,6 +1479,23 @@ static void vsc9959_mdio_bus_free(struct ocelot *ocelot)
        mdiobus_free(felix->imdio);
 }
 
+/* The switch considers any frame (regardless of size) as eligible for
+ * transmission if the traffic class gate is open for at least 33 ns.
+ * Overruns are prevented by cropping an interval at the end of the gate time
+ * slot for which egress scheduling is blocked, but we need to still keep 33 ns
+ * available for one packet to be transmitted, otherwise the port tc will hang.
+ * This function returns the size of a gate interval that remains available for
+ * setting the guard band, after reserving the space for one egress frame.
+ */
+static u64 vsc9959_tas_remaining_gate_len_ps(u64 gate_len_ns)
+{
+       /* Gate always open */
+       if (gate_len_ns == U64_MAX)
+               return U64_MAX;
+
+       return (gate_len_ns - VSC9959_TAS_MIN_GATE_LEN_NS) * PSEC_PER_NSEC;
+}
+
 /* Extract shortest continuous gate open intervals in ns for each traffic class
  * of a cyclic tc-taprio schedule. If a gate is always open, the duration is
  * considered U64_MAX. If the gate is always closed, it is considered 0.
@@ -1189,6 +1557,65 @@ static void vsc9959_tas_min_gate_lengths(struct tc_taprio_qopt_offload *taprio,
                        min_gate_len[tc] = 0;
 }
 
+/* ocelot_write_rix is a macro that concatenates QSYS_MAXSDU_CFG_* with _RSZ,
+ * so we need to spell out the register access to each traffic class in helper
+ * functions, to simplify callers
+ */
+static void vsc9959_port_qmaxsdu_set(struct ocelot *ocelot, int port, int tc,
+                                    u32 max_sdu)
+{
+       switch (tc) {
+       case 0:
+               ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_0,
+                                port);
+               break;
+       case 1:
+               ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_1,
+                                port);
+               break;
+       case 2:
+               ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_2,
+                                port);
+               break;
+       case 3:
+               ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_3,
+                                port);
+               break;
+       case 4:
+               ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_4,
+                                port);
+               break;
+       case 5:
+               ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_5,
+                                port);
+               break;
+       case 6:
+               ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_6,
+                                port);
+               break;
+       case 7:
+               ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_7,
+                                port);
+               break;
+       }
+}
+
+static u32 vsc9959_port_qmaxsdu_get(struct ocelot *ocelot, int port, int tc)
+{
+       switch (tc) {
+       case 0: return ocelot_read_rix(ocelot, QSYS_QMAXSDU_CFG_0, port);
+       case 1: return ocelot_read_rix(ocelot, QSYS_QMAXSDU_CFG_1, port);
+       case 2: return ocelot_read_rix(ocelot, QSYS_QMAXSDU_CFG_2, port);
+       case 3: return ocelot_read_rix(ocelot, QSYS_QMAXSDU_CFG_3, port);
+       case 4: return ocelot_read_rix(ocelot, QSYS_QMAXSDU_CFG_4, port);
+       case 5: return ocelot_read_rix(ocelot, QSYS_QMAXSDU_CFG_5, port);
+       case 6: return ocelot_read_rix(ocelot, QSYS_QMAXSDU_CFG_6, port);
+       case 7: return ocelot_read_rix(ocelot, QSYS_QMAXSDU_CFG_7, port);
+       default:
+               return 0;
+       }
+}
+
 /* Update QSYS_PORT_MAX_SDU to make sure the static guard bands added by the
  * switch (see the ALWAYS_GUARD_BAND_SCH_Q comment) are correct at all MTU
  * values (the default value is 1518). Also, for traffic class windows smaller
@@ -1245,11 +1672,16 @@ static void vsc9959_tas_guard_bands_update(struct ocelot *ocelot, int port)
 
        vsc9959_tas_min_gate_lengths(ocelot_port->taprio, min_gate_len);
 
+       mutex_lock(&ocelot->fwd_domain_lock);
+
        for (tc = 0; tc < OCELOT_NUM_TC; tc++) {
+               u64 remaining_gate_len_ps;
                u32 max_sdu;
 
-               if (min_gate_len[tc] == U64_MAX /* Gate always open */ ||
-                   min_gate_len[tc] * PSEC_PER_NSEC > needed_bit_time_ps) {
+               remaining_gate_len_ps =
+                       vsc9959_tas_remaining_gate_len_ps(min_gate_len[tc]);
+
+               if (remaining_gate_len_ps > needed_bit_time_ps) {
                        /* Setting QMAXSDU_CFG to 0 disables oversized frame
                         * dropping.
                         */
@@ -1262,9 +1694,15 @@ static void vsc9959_tas_guard_bands_update(struct ocelot *ocelot, int port)
                        /* If traffic class doesn't support a full MTU sized
                         * frame, make sure to enable oversize frame dropping
                         * for frames larger than the smallest that would fit.
+                        *
+                        * However, the exact same register, QSYS_QMAXSDU_CFG_*,
+                        * controls not only oversized frame dropping, but also
+                        * per-tc static guard band lengths, so it reduces the
+                        * useful gate interval length. Therefore, be careful
+                        * to calculate a guard band (and therefore max_sdu)
+                        * that still leaves 33 ns available in the time slot.
                         */
-                       max_sdu = div_u64(min_gate_len[tc] * PSEC_PER_NSEC,
-                                         picos_per_byte);
+                       max_sdu = div_u64(remaining_gate_len_ps, picos_per_byte);
                        /* A TC gate may be completely closed, which is a
                         * special case where all packets are oversized.
                         * Any limit smaller than 64 octets accomplishes this
@@ -1287,47 +1725,14 @@ static void vsc9959_tas_guard_bands_update(struct ocelot *ocelot, int port)
                                 max_sdu);
                }
 
-               /* ocelot_write_rix is a macro that concatenates
-                * QSYS_MAXSDU_CFG_* with _RSZ, so we need to spell out
-                * the writes to each traffic class
-                */
-               switch (tc) {
-               case 0:
-                       ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_0,
-                                        port);
-                       break;
-               case 1:
-                       ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_1,
-                                        port);
-                       break;
-               case 2:
-                       ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_2,
-                                        port);
-                       break;
-               case 3:
-                       ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_3,
-                                        port);
-                       break;
-               case 4:
-                       ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_4,
-                                        port);
-                       break;
-               case 5:
-                       ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_5,
-                                        port);
-                       break;
-               case 6:
-                       ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_6,
-                                        port);
-                       break;
-               case 7:
-                       ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_7,
-                                        port);
-                       break;
-               }
+               vsc9959_port_qmaxsdu_set(ocelot, port, tc, max_sdu);
        }
 
        ocelot_write_rix(ocelot, maxlen, QSYS_PORT_MAX_SDU, port);
+
+       ocelot->ops->cut_through_fwd(ocelot);
+
+       mutex_unlock(&ocelot->fwd_domain_lock);
 }
 
 static void vsc9959_sched_speed_set(struct ocelot *ocelot, int port,
@@ -1354,13 +1759,13 @@ static void vsc9959_sched_speed_set(struct ocelot *ocelot, int port,
                break;
        }
 
+       mutex_lock(&ocelot->tas_lock);
+
        ocelot_rmw_rix(ocelot,
                       QSYS_TAG_CONFIG_LINK_SPEED(tas_speed),
                       QSYS_TAG_CONFIG_LINK_SPEED_M,
                       QSYS_TAG_CONFIG, port);
 
-       mutex_lock(&ocelot->tas_lock);
-
        if (ocelot_port->taprio)
                vsc9959_tas_guard_bands_update(ocelot, port);
 
@@ -2166,7 +2571,7 @@ static void vsc9959_psfp_sgi_table_del(struct ocelot *ocelot,
 static void vsc9959_psfp_counters_get(struct ocelot *ocelot, u32 index,
                                      struct felix_stream_filter_counters *counters)
 {
-       mutex_lock(&ocelot->stats_lock);
+       spin_lock(&ocelot->stats_lock);
 
        ocelot_rmw(ocelot, SYS_STAT_CFG_STAT_VIEW(index),
                   SYS_STAT_CFG_STAT_VIEW_M,
@@ -2183,7 +2588,7 @@ static void vsc9959_psfp_counters_get(struct ocelot *ocelot, u32 index,
                     SYS_STAT_CFG_STAT_CLEAR_SHOT(0x10),
                     SYS_STAT_CFG);
 
-       mutex_unlock(&ocelot->stats_lock);
+       spin_unlock(&ocelot->stats_lock);
 }
 
 static int vsc9959_psfp_filter_add(struct ocelot *ocelot, int port,
@@ -2420,7 +2825,7 @@ static void vsc9959_cut_through_fwd(struct ocelot *ocelot)
 {
        struct felix *felix = ocelot_to_felix(ocelot);
        struct dsa_switch *ds = felix->ds;
-       int port, other_port;
+       int tc, port, other_port;
 
        lockdep_assert_held(&ocelot->fwd_domain_lock);
 
@@ -2464,19 +2869,27 @@ static void vsc9959_cut_through_fwd(struct ocelot *ocelot)
                                min_speed = other_ocelot_port->speed;
                }
 
-               /* Enable cut-through forwarding for all traffic classes. */
-               if (ocelot_port->speed == min_speed)
+               /* Enable cut-through forwarding for all traffic classes that
+                * don't have oversized dropping enabled, since this check is
+                * bypassed in cut-through mode.
+                */
+               if (ocelot_port->speed == min_speed) {
                        val = GENMASK(7, 0);
 
+                       for (tc = 0; tc < OCELOT_NUM_TC; tc++)
+                               if (vsc9959_port_qmaxsdu_get(ocelot, port, tc))
+                                       val &= ~BIT(tc);
+               }
+
 set:
                tmp = ocelot_read_rix(ocelot, ANA_CUT_THRU_CFG, port);
                if (tmp == val)
                        continue;
 
                dev_dbg(ocelot->dev,
-                       "port %d fwd mask 0x%lx speed %d min_speed %d, %s cut-through forwarding\n",
+                       "port %d fwd mask 0x%lx speed %d min_speed %d, %s cut-through forwarding on TC mask 0x%x\n",
                        port, mask, ocelot_port->speed, min_speed,
-                       val ? "enabling" : "disabling");
+                       val ? "enabling" : "disabling", val);
 
                ocelot_write_rix(ocelot, val, ANA_CUT_THRU_CFG, port);
        }
index ea06492..b34f4cd 100644 (file)
@@ -270,27 +270,98 @@ static const u32 vsc9953_rew_regmap[] = {
 
 static const u32 vsc9953_sys_regmap[] = {
        REG(SYS_COUNT_RX_OCTETS,                0x000000),
+       REG(SYS_COUNT_RX_UNICAST,               0x000004),
        REG(SYS_COUNT_RX_MULTICAST,             0x000008),
+       REG(SYS_COUNT_RX_BROADCAST,             0x00000c),
        REG(SYS_COUNT_RX_SHORTS,                0x000010),
        REG(SYS_COUNT_RX_FRAGMENTS,             0x000014),
        REG(SYS_COUNT_RX_JABBERS,               0x000018),
+       REG(SYS_COUNT_RX_CRC_ALIGN_ERRS,        0x00001c),
+       REG(SYS_COUNT_RX_SYM_ERRS,              0x000020),
        REG(SYS_COUNT_RX_64,                    0x000024),
        REG(SYS_COUNT_RX_65_127,                0x000028),
        REG(SYS_COUNT_RX_128_255,               0x00002c),
-       REG(SYS_COUNT_RX_256_1023,              0x000030),
-       REG(SYS_COUNT_RX_1024_1526,             0x000034),
-       REG(SYS_COUNT_RX_1527_MAX,              0x000038),
+       REG(SYS_COUNT_RX_256_511,               0x000030),
+       REG(SYS_COUNT_RX_512_1023,              0x000034),
+       REG(SYS_COUNT_RX_1024_1526,             0x000038),
+       REG(SYS_COUNT_RX_1527_MAX,              0x00003c),
+       REG(SYS_COUNT_RX_PAUSE,                 0x000040),
+       REG(SYS_COUNT_RX_CONTROL,               0x000044),
        REG(SYS_COUNT_RX_LONGS,                 0x000048),
+       REG(SYS_COUNT_RX_CLASSIFIED_DROPS,      0x00004c),
+       REG(SYS_COUNT_RX_RED_PRIO_0,            0x000050),
+       REG(SYS_COUNT_RX_RED_PRIO_1,            0x000054),
+       REG(SYS_COUNT_RX_RED_PRIO_2,            0x000058),
+       REG(SYS_COUNT_RX_RED_PRIO_3,            0x00005c),
+       REG(SYS_COUNT_RX_RED_PRIO_4,            0x000060),
+       REG(SYS_COUNT_RX_RED_PRIO_5,            0x000064),
+       REG(SYS_COUNT_RX_RED_PRIO_6,            0x000068),
+       REG(SYS_COUNT_RX_RED_PRIO_7,            0x00006c),
+       REG(SYS_COUNT_RX_YELLOW_PRIO_0,         0x000070),
+       REG(SYS_COUNT_RX_YELLOW_PRIO_1,         0x000074),
+       REG(SYS_COUNT_RX_YELLOW_PRIO_2,         0x000078),
+       REG(SYS_COUNT_RX_YELLOW_PRIO_3,         0x00007c),
+       REG(SYS_COUNT_RX_YELLOW_PRIO_4,         0x000080),
+       REG(SYS_COUNT_RX_YELLOW_PRIO_5,         0x000084),
+       REG(SYS_COUNT_RX_YELLOW_PRIO_6,         0x000088),
+       REG(SYS_COUNT_RX_YELLOW_PRIO_7,         0x00008c),
+       REG(SYS_COUNT_RX_GREEN_PRIO_0,          0x000090),
+       REG(SYS_COUNT_RX_GREEN_PRIO_1,          0x000094),
+       REG(SYS_COUNT_RX_GREEN_PRIO_2,          0x000098),
+       REG(SYS_COUNT_RX_GREEN_PRIO_3,          0x00009c),
+       REG(SYS_COUNT_RX_GREEN_PRIO_4,          0x0000a0),
+       REG(SYS_COUNT_RX_GREEN_PRIO_5,          0x0000a4),
+       REG(SYS_COUNT_RX_GREEN_PRIO_6,          0x0000a8),
+       REG(SYS_COUNT_RX_GREEN_PRIO_7,          0x0000ac),
        REG(SYS_COUNT_TX_OCTETS,                0x000100),
+       REG(SYS_COUNT_TX_UNICAST,               0x000104),
+       REG(SYS_COUNT_TX_MULTICAST,             0x000108),
+       REG(SYS_COUNT_TX_BROADCAST,             0x00010c),
        REG(SYS_COUNT_TX_COLLISION,             0x000110),
        REG(SYS_COUNT_TX_DROPS,                 0x000114),
+       REG(SYS_COUNT_TX_PAUSE,                 0x000118),
        REG(SYS_COUNT_TX_64,                    0x00011c),
        REG(SYS_COUNT_TX_65_127,                0x000120),
-       REG(SYS_COUNT_TX_128_511,               0x000124),
-       REG(SYS_COUNT_TX_512_1023,              0x000128),
-       REG(SYS_COUNT_TX_1024_1526,             0x00012c),
-       REG(SYS_COUNT_TX_1527_MAX,              0x000130),
+       REG(SYS_COUNT_TX_128_255,               0x000124),
+       REG(SYS_COUNT_TX_256_511,               0x000128),
+       REG(SYS_COUNT_TX_512_1023,              0x00012c),
+       REG(SYS_COUNT_TX_1024_1526,             0x000130),
+       REG(SYS_COUNT_TX_1527_MAX,              0x000134),
+       REG(SYS_COUNT_TX_YELLOW_PRIO_0,         0x000138),
+       REG(SYS_COUNT_TX_YELLOW_PRIO_1,         0x00013c),
+       REG(SYS_COUNT_TX_YELLOW_PRIO_2,         0x000140),
+       REG(SYS_COUNT_TX_YELLOW_PRIO_3,         0x000144),
+       REG(SYS_COUNT_TX_YELLOW_PRIO_4,         0x000148),
+       REG(SYS_COUNT_TX_YELLOW_PRIO_5,         0x00014c),
+       REG(SYS_COUNT_TX_YELLOW_PRIO_6,         0x000150),
+       REG(SYS_COUNT_TX_YELLOW_PRIO_7,         0x000154),
+       REG(SYS_COUNT_TX_GREEN_PRIO_0,          0x000158),
+       REG(SYS_COUNT_TX_GREEN_PRIO_1,          0x00015c),
+       REG(SYS_COUNT_TX_GREEN_PRIO_2,          0x000160),
+       REG(SYS_COUNT_TX_GREEN_PRIO_3,          0x000164),
+       REG(SYS_COUNT_TX_GREEN_PRIO_4,          0x000168),
+       REG(SYS_COUNT_TX_GREEN_PRIO_5,          0x00016c),
+       REG(SYS_COUNT_TX_GREEN_PRIO_6,          0x000170),
+       REG(SYS_COUNT_TX_GREEN_PRIO_7,          0x000174),
        REG(SYS_COUNT_TX_AGING,                 0x000178),
+       REG(SYS_COUNT_DROP_LOCAL,               0x000200),
+       REG(SYS_COUNT_DROP_TAIL,                0x000204),
+       REG(SYS_COUNT_DROP_YELLOW_PRIO_0,       0x000208),
+       REG(SYS_COUNT_DROP_YELLOW_PRIO_1,       0x00020c),
+       REG(SYS_COUNT_DROP_YELLOW_PRIO_2,       0x000210),
+       REG(SYS_COUNT_DROP_YELLOW_PRIO_3,       0x000214),
+       REG(SYS_COUNT_DROP_YELLOW_PRIO_4,       0x000218),
+       REG(SYS_COUNT_DROP_YELLOW_PRIO_5,       0x00021c),
+       REG(SYS_COUNT_DROP_YELLOW_PRIO_6,       0x000220),
+       REG(SYS_COUNT_DROP_YELLOW_PRIO_7,       0x000224),
+       REG(SYS_COUNT_DROP_GREEN_PRIO_0,        0x000228),
+       REG(SYS_COUNT_DROP_GREEN_PRIO_1,        0x00022c),
+       REG(SYS_COUNT_DROP_GREEN_PRIO_2,        0x000230),
+       REG(SYS_COUNT_DROP_GREEN_PRIO_3,        0x000234),
+       REG(SYS_COUNT_DROP_GREEN_PRIO_4,        0x000238),
+       REG(SYS_COUNT_DROP_GREEN_PRIO_5,        0x00023c),
+       REG(SYS_COUNT_DROP_GREEN_PRIO_6,        0x000240),
+       REG(SYS_COUNT_DROP_GREEN_PRIO_7,        0x000244),
        REG(SYS_RESET_CFG,                      0x000318),
        REG_RESERVED(SYS_SR_ETYPE_CFG),
        REG(SYS_VLAN_ETYPE_CFG,                 0x000320),
@@ -543,101 +614,379 @@ static const struct reg_field vsc9953_regfields[REGFIELD_MAX] = {
        [SYS_PAUSE_CFG_PAUSE_ENA] = REG_FIELD_ID(SYS_PAUSE_CFG, 0, 1, 11, 4),
 };
 
-static const struct ocelot_stat_layout vsc9953_stats_layout[] = {
-       { .offset = 0x00,       .name = "rx_octets", },
-       { .offset = 0x01,       .name = "rx_unicast", },
-       { .offset = 0x02,       .name = "rx_multicast", },
-       { .offset = 0x03,       .name = "rx_broadcast", },
-       { .offset = 0x04,       .name = "rx_shorts", },
-       { .offset = 0x05,       .name = "rx_fragments", },
-       { .offset = 0x06,       .name = "rx_jabbers", },
-       { .offset = 0x07,       .name = "rx_crc_align_errs", },
-       { .offset = 0x08,       .name = "rx_sym_errs", },
-       { .offset = 0x09,       .name = "rx_frames_below_65_octets", },
-       { .offset = 0x0A,       .name = "rx_frames_65_to_127_octets", },
-       { .offset = 0x0B,       .name = "rx_frames_128_to_255_octets", },
-       { .offset = 0x0C,       .name = "rx_frames_256_to_511_octets", },
-       { .offset = 0x0D,       .name = "rx_frames_512_to_1023_octets", },
-       { .offset = 0x0E,       .name = "rx_frames_1024_to_1526_octets", },
-       { .offset = 0x0F,       .name = "rx_frames_over_1526_octets", },
-       { .offset = 0x10,       .name = "rx_pause", },
-       { .offset = 0x11,       .name = "rx_control", },
-       { .offset = 0x12,       .name = "rx_longs", },
-       { .offset = 0x13,       .name = "rx_classified_drops", },
-       { .offset = 0x14,       .name = "rx_red_prio_0", },
-       { .offset = 0x15,       .name = "rx_red_prio_1", },
-       { .offset = 0x16,       .name = "rx_red_prio_2", },
-       { .offset = 0x17,       .name = "rx_red_prio_3", },
-       { .offset = 0x18,       .name = "rx_red_prio_4", },
-       { .offset = 0x19,       .name = "rx_red_prio_5", },
-       { .offset = 0x1A,       .name = "rx_red_prio_6", },
-       { .offset = 0x1B,       .name = "rx_red_prio_7", },
-       { .offset = 0x1C,       .name = "rx_yellow_prio_0", },
-       { .offset = 0x1D,       .name = "rx_yellow_prio_1", },
-       { .offset = 0x1E,       .name = "rx_yellow_prio_2", },
-       { .offset = 0x1F,       .name = "rx_yellow_prio_3", },
-       { .offset = 0x20,       .name = "rx_yellow_prio_4", },
-       { .offset = 0x21,       .name = "rx_yellow_prio_5", },
-       { .offset = 0x22,       .name = "rx_yellow_prio_6", },
-       { .offset = 0x23,       .name = "rx_yellow_prio_7", },
-       { .offset = 0x24,       .name = "rx_green_prio_0", },
-       { .offset = 0x25,       .name = "rx_green_prio_1", },
-       { .offset = 0x26,       .name = "rx_green_prio_2", },
-       { .offset = 0x27,       .name = "rx_green_prio_3", },
-       { .offset = 0x28,       .name = "rx_green_prio_4", },
-       { .offset = 0x29,       .name = "rx_green_prio_5", },
-       { .offset = 0x2A,       .name = "rx_green_prio_6", },
-       { .offset = 0x2B,       .name = "rx_green_prio_7", },
-       { .offset = 0x40,       .name = "tx_octets", },
-       { .offset = 0x41,       .name = "tx_unicast", },
-       { .offset = 0x42,       .name = "tx_multicast", },
-       { .offset = 0x43,       .name = "tx_broadcast", },
-       { .offset = 0x44,       .name = "tx_collision", },
-       { .offset = 0x45,       .name = "tx_drops", },
-       { .offset = 0x46,       .name = "tx_pause", },
-       { .offset = 0x47,       .name = "tx_frames_below_65_octets", },
-       { .offset = 0x48,       .name = "tx_frames_65_to_127_octets", },
-       { .offset = 0x49,       .name = "tx_frames_128_255_octets", },
-       { .offset = 0x4A,       .name = "tx_frames_256_511_octets", },
-       { .offset = 0x4B,       .name = "tx_frames_512_1023_octets", },
-       { .offset = 0x4C,       .name = "tx_frames_1024_1526_octets", },
-       { .offset = 0x4D,       .name = "tx_frames_over_1526_octets", },
-       { .offset = 0x4E,       .name = "tx_yellow_prio_0", },
-       { .offset = 0x4F,       .name = "tx_yellow_prio_1", },
-       { .offset = 0x50,       .name = "tx_yellow_prio_2", },
-       { .offset = 0x51,       .name = "tx_yellow_prio_3", },
-       { .offset = 0x52,       .name = "tx_yellow_prio_4", },
-       { .offset = 0x53,       .name = "tx_yellow_prio_5", },
-       { .offset = 0x54,       .name = "tx_yellow_prio_6", },
-       { .offset = 0x55,       .name = "tx_yellow_prio_7", },
-       { .offset = 0x56,       .name = "tx_green_prio_0", },
-       { .offset = 0x57,       .name = "tx_green_prio_1", },
-       { .offset = 0x58,       .name = "tx_green_prio_2", },
-       { .offset = 0x59,       .name = "tx_green_prio_3", },
-       { .offset = 0x5A,       .name = "tx_green_prio_4", },
-       { .offset = 0x5B,       .name = "tx_green_prio_5", },
-       { .offset = 0x5C,       .name = "tx_green_prio_6", },
-       { .offset = 0x5D,       .name = "tx_green_prio_7", },
-       { .offset = 0x5E,       .name = "tx_aged", },
-       { .offset = 0x80,       .name = "drop_local", },
-       { .offset = 0x81,       .name = "drop_tail", },
-       { .offset = 0x82,       .name = "drop_yellow_prio_0", },
-       { .offset = 0x83,       .name = "drop_yellow_prio_1", },
-       { .offset = 0x84,       .name = "drop_yellow_prio_2", },
-       { .offset = 0x85,       .name = "drop_yellow_prio_3", },
-       { .offset = 0x86,       .name = "drop_yellow_prio_4", },
-       { .offset = 0x87,       .name = "drop_yellow_prio_5", },
-       { .offset = 0x88,       .name = "drop_yellow_prio_6", },
-       { .offset = 0x89,       .name = "drop_yellow_prio_7", },
-       { .offset = 0x8A,       .name = "drop_green_prio_0", },
-       { .offset = 0x8B,       .name = "drop_green_prio_1", },
-       { .offset = 0x8C,       .name = "drop_green_prio_2", },
-       { .offset = 0x8D,       .name = "drop_green_prio_3", },
-       { .offset = 0x8E,       .name = "drop_green_prio_4", },
-       { .offset = 0x8F,       .name = "drop_green_prio_5", },
-       { .offset = 0x90,       .name = "drop_green_prio_6", },
-       { .offset = 0x91,       .name = "drop_green_prio_7", },
-       OCELOT_STAT_END
+static const struct ocelot_stat_layout vsc9953_stats_layout[OCELOT_NUM_STATS] = {
+       [OCELOT_STAT_RX_OCTETS] = {
+               .name = "rx_octets",
+               .reg = SYS_COUNT_RX_OCTETS,
+       },
+       [OCELOT_STAT_RX_UNICAST] = {
+               .name = "rx_unicast",
+               .reg = SYS_COUNT_RX_UNICAST,
+       },
+       [OCELOT_STAT_RX_MULTICAST] = {
+               .name = "rx_multicast",
+               .reg = SYS_COUNT_RX_MULTICAST,
+       },
+       [OCELOT_STAT_RX_BROADCAST] = {
+               .name = "rx_broadcast",
+               .reg = SYS_COUNT_RX_BROADCAST,
+       },
+       [OCELOT_STAT_RX_SHORTS] = {
+               .name = "rx_shorts",
+               .reg = SYS_COUNT_RX_SHORTS,
+       },
+       [OCELOT_STAT_RX_FRAGMENTS] = {
+               .name = "rx_fragments",
+               .reg = SYS_COUNT_RX_FRAGMENTS,
+       },
+       [OCELOT_STAT_RX_JABBERS] = {
+               .name = "rx_jabbers",
+               .reg = SYS_COUNT_RX_JABBERS,
+       },
+       [OCELOT_STAT_RX_CRC_ALIGN_ERRS] = {
+               .name = "rx_crc_align_errs",
+               .reg = SYS_COUNT_RX_CRC_ALIGN_ERRS,
+       },
+       [OCELOT_STAT_RX_SYM_ERRS] = {
+               .name = "rx_sym_errs",
+               .reg = SYS_COUNT_RX_SYM_ERRS,
+       },
+       [OCELOT_STAT_RX_64] = {
+               .name = "rx_frames_below_65_octets",
+               .reg = SYS_COUNT_RX_64,
+       },
+       [OCELOT_STAT_RX_65_127] = {
+               .name = "rx_frames_65_to_127_octets",
+               .reg = SYS_COUNT_RX_65_127,
+       },
+       [OCELOT_STAT_RX_128_255] = {
+               .name = "rx_frames_128_to_255_octets",
+               .reg = SYS_COUNT_RX_128_255,
+       },
+       [OCELOT_STAT_RX_256_511] = {
+               .name = "rx_frames_256_to_511_octets",
+               .reg = SYS_COUNT_RX_256_511,
+       },
+       [OCELOT_STAT_RX_512_1023] = {
+               .name = "rx_frames_512_to_1023_octets",
+               .reg = SYS_COUNT_RX_512_1023,
+       },
+       [OCELOT_STAT_RX_1024_1526] = {
+               .name = "rx_frames_1024_to_1526_octets",
+               .reg = SYS_COUNT_RX_1024_1526,
+       },
+       [OCELOT_STAT_RX_1527_MAX] = {
+               .name = "rx_frames_over_1526_octets",
+               .reg = SYS_COUNT_RX_1527_MAX,
+       },
+       [OCELOT_STAT_RX_PAUSE] = {
+               .name = "rx_pause",
+               .reg = SYS_COUNT_RX_PAUSE,
+       },
+       [OCELOT_STAT_RX_CONTROL] = {
+               .name = "rx_control",
+               .reg = SYS_COUNT_RX_CONTROL,
+       },
+       [OCELOT_STAT_RX_LONGS] = {
+               .name = "rx_longs",
+               .reg = SYS_COUNT_RX_LONGS,
+       },
+       [OCELOT_STAT_RX_CLASSIFIED_DROPS] = {
+               .name = "rx_classified_drops",
+               .reg = SYS_COUNT_RX_CLASSIFIED_DROPS,
+       },
+       [OCELOT_STAT_RX_RED_PRIO_0] = {
+               .name = "rx_red_prio_0",
+               .reg = SYS_COUNT_RX_RED_PRIO_0,
+       },
+       [OCELOT_STAT_RX_RED_PRIO_1] = {
+               .name = "rx_red_prio_1",
+               .reg = SYS_COUNT_RX_RED_PRIO_1,
+       },
+       [OCELOT_STAT_RX_RED_PRIO_2] = {
+               .name = "rx_red_prio_2",
+               .reg = SYS_COUNT_RX_RED_PRIO_2,
+       },
+       [OCELOT_STAT_RX_RED_PRIO_3] = {
+               .name = "rx_red_prio_3",
+               .reg = SYS_COUNT_RX_RED_PRIO_3,
+       },
+       [OCELOT_STAT_RX_RED_PRIO_4] = {
+               .name = "rx_red_prio_4",
+               .reg = SYS_COUNT_RX_RED_PRIO_4,
+       },
+       [OCELOT_STAT_RX_RED_PRIO_5] = {
+               .name = "rx_red_prio_5",
+               .reg = SYS_COUNT_RX_RED_PRIO_5,
+       },
+       [OCELOT_STAT_RX_RED_PRIO_6] = {
+               .name = "rx_red_prio_6",
+               .reg = SYS_COUNT_RX_RED_PRIO_6,
+       },
+       [OCELOT_STAT_RX_RED_PRIO_7] = {
+               .name = "rx_red_prio_7",
+               .reg = SYS_COUNT_RX_RED_PRIO_7,
+       },
+       [OCELOT_STAT_RX_YELLOW_PRIO_0] = {
+               .name = "rx_yellow_prio_0",
+               .reg = SYS_COUNT_RX_YELLOW_PRIO_0,
+       },
+       [OCELOT_STAT_RX_YELLOW_PRIO_1] = {
+               .name = "rx_yellow_prio_1",
+               .reg = SYS_COUNT_RX_YELLOW_PRIO_1,
+       },
+       [OCELOT_STAT_RX_YELLOW_PRIO_2] = {
+               .name = "rx_yellow_prio_2",
+               .reg = SYS_COUNT_RX_YELLOW_PRIO_2,
+       },
+       [OCELOT_STAT_RX_YELLOW_PRIO_3] = {
+               .name = "rx_yellow_prio_3",
+               .reg = SYS_COUNT_RX_YELLOW_PRIO_3,
+       },
+       [OCELOT_STAT_RX_YELLOW_PRIO_4] = {
+               .name = "rx_yellow_prio_4",
+               .reg = SYS_COUNT_RX_YELLOW_PRIO_4,
+       },
+       [OCELOT_STAT_RX_YELLOW_PRIO_5] = {
+               .name = "rx_yellow_prio_5",
+               .reg = SYS_COUNT_RX_YELLOW_PRIO_5,
+       },
+       [OCELOT_STAT_RX_YELLOW_PRIO_6] = {
+               .name = "rx_yellow_prio_6",
+               .reg = SYS_COUNT_RX_YELLOW_PRIO_6,
+       },
+       [OCELOT_STAT_RX_YELLOW_PRIO_7] = {
+               .name = "rx_yellow_prio_7",
+               .reg = SYS_COUNT_RX_YELLOW_PRIO_7,
+       },
+       [OCELOT_STAT_RX_GREEN_PRIO_0] = {
+               .name = "rx_green_prio_0",
+               .reg = SYS_COUNT_RX_GREEN_PRIO_0,
+       },
+       [OCELOT_STAT_RX_GREEN_PRIO_1] = {
+               .name = "rx_green_prio_1",
+               .reg = SYS_COUNT_RX_GREEN_PRIO_1,
+       },
+       [OCELOT_STAT_RX_GREEN_PRIO_2] = {
+               .name = "rx_green_prio_2",
+               .reg = SYS_COUNT_RX_GREEN_PRIO_2,
+       },
+       [OCELOT_STAT_RX_GREEN_PRIO_3] = {
+               .name = "rx_green_prio_3",
+               .reg = SYS_COUNT_RX_GREEN_PRIO_3,
+       },
+       [OCELOT_STAT_RX_GREEN_PRIO_4] = {
+               .name = "rx_green_prio_4",
+               .reg = SYS_COUNT_RX_GREEN_PRIO_4,
+       },
+       [OCELOT_STAT_RX_GREEN_PRIO_5] = {
+               .name = "rx_green_prio_5",
+               .reg = SYS_COUNT_RX_GREEN_PRIO_5,
+       },
+       [OCELOT_STAT_RX_GREEN_PRIO_6] = {
+               .name = "rx_green_prio_6",
+               .reg = SYS_COUNT_RX_GREEN_PRIO_6,
+       },
+       [OCELOT_STAT_RX_GREEN_PRIO_7] = {
+               .name = "rx_green_prio_7",
+               .reg = SYS_COUNT_RX_GREEN_PRIO_7,
+       },
+       [OCELOT_STAT_TX_OCTETS] = {
+               .name = "tx_octets",
+               .reg = SYS_COUNT_TX_OCTETS,
+       },
+       [OCELOT_STAT_TX_UNICAST] = {
+               .name = "tx_unicast",
+               .reg = SYS_COUNT_TX_UNICAST,
+       },
+       [OCELOT_STAT_TX_MULTICAST] = {
+               .name = "tx_multicast",
+               .reg = SYS_COUNT_TX_MULTICAST,
+       },
+       [OCELOT_STAT_TX_BROADCAST] = {
+               .name = "tx_broadcast",
+               .reg = SYS_COUNT_TX_BROADCAST,
+       },
+       [OCELOT_STAT_TX_COLLISION] = {
+               .name = "tx_collision",
+               .reg = SYS_COUNT_TX_COLLISION,
+       },
+       [OCELOT_STAT_TX_DROPS] = {
+               .name = "tx_drops",
+               .reg = SYS_COUNT_TX_DROPS,
+       },
+       [OCELOT_STAT_TX_PAUSE] = {
+               .name = "tx_pause",
+               .reg = SYS_COUNT_TX_PAUSE,
+       },
+       [OCELOT_STAT_TX_64] = {
+               .name = "tx_frames_below_65_octets",
+               .reg = SYS_COUNT_TX_64,
+       },
+       [OCELOT_STAT_TX_65_127] = {
+               .name = "tx_frames_65_to_127_octets",
+               .reg = SYS_COUNT_TX_65_127,
+       },
+       [OCELOT_STAT_TX_128_255] = {
+               .name = "tx_frames_128_255_octets",
+               .reg = SYS_COUNT_TX_128_255,
+       },
+       [OCELOT_STAT_TX_256_511] = {
+               .name = "tx_frames_256_511_octets",
+               .reg = SYS_COUNT_TX_256_511,
+       },
+       [OCELOT_STAT_TX_512_1023] = {
+               .name = "tx_frames_512_1023_octets",
+               .reg = SYS_COUNT_TX_512_1023,
+       },
+       [OCELOT_STAT_TX_1024_1526] = {
+               .name = "tx_frames_1024_1526_octets",
+               .reg = SYS_COUNT_TX_1024_1526,
+       },
+       [OCELOT_STAT_TX_1527_MAX] = {
+               .name = "tx_frames_over_1526_octets",
+               .reg = SYS_COUNT_TX_1527_MAX,
+       },
+       [OCELOT_STAT_TX_YELLOW_PRIO_0] = {
+               .name = "tx_yellow_prio_0",
+               .reg = SYS_COUNT_TX_YELLOW_PRIO_0,
+       },
+       [OCELOT_STAT_TX_YELLOW_PRIO_1] = {
+               .name = "tx_yellow_prio_1",
+               .reg = SYS_COUNT_TX_YELLOW_PRIO_1,
+       },
+       [OCELOT_STAT_TX_YELLOW_PRIO_2] = {
+               .name = "tx_yellow_prio_2",
+               .reg = SYS_COUNT_TX_YELLOW_PRIO_2,
+       },
+       [OCELOT_STAT_TX_YELLOW_PRIO_3] = {
+               .name = "tx_yellow_prio_3",
+               .reg = SYS_COUNT_TX_YELLOW_PRIO_3,
+       },
+       [OCELOT_STAT_TX_YELLOW_PRIO_4] = {
+               .name = "tx_yellow_prio_4",
+               .reg = SYS_COUNT_TX_YELLOW_PRIO_4,
+       },
+       [OCELOT_STAT_TX_YELLOW_PRIO_5] = {
+               .name = "tx_yellow_prio_5",
+               .reg = SYS_COUNT_TX_YELLOW_PRIO_5,
+       },
+       [OCELOT_STAT_TX_YELLOW_PRIO_6] = {
+               .name = "tx_yellow_prio_6",
+               .reg = SYS_COUNT_TX_YELLOW_PRIO_6,
+       },
+       [OCELOT_STAT_TX_YELLOW_PRIO_7] = {
+               .name = "tx_yellow_prio_7",
+               .reg = SYS_COUNT_TX_YELLOW_PRIO_7,
+       },
+       [OCELOT_STAT_TX_GREEN_PRIO_0] = {
+               .name = "tx_green_prio_0",
+               .reg = SYS_COUNT_TX_GREEN_PRIO_0,
+       },
+       [OCELOT_STAT_TX_GREEN_PRIO_1] = {
+               .name = "tx_green_prio_1",
+               .reg = SYS_COUNT_TX_GREEN_PRIO_1,
+       },
+       [OCELOT_STAT_TX_GREEN_PRIO_2] = {
+               .name = "tx_green_prio_2",
+               .reg = SYS_COUNT_TX_GREEN_PRIO_2,
+       },
+       [OCELOT_STAT_TX_GREEN_PRIO_3] = {
+               .name = "tx_green_prio_3",
+               .reg = SYS_COUNT_TX_GREEN_PRIO_3,
+       },
+       [OCELOT_STAT_TX_GREEN_PRIO_4] = {
+               .name = "tx_green_prio_4",
+               .reg = SYS_COUNT_TX_GREEN_PRIO_4,
+       },
+       [OCELOT_STAT_TX_GREEN_PRIO_5] = {
+               .name = "tx_green_prio_5",
+               .reg = SYS_COUNT_TX_GREEN_PRIO_5,
+       },
+       [OCELOT_STAT_TX_GREEN_PRIO_6] = {
+               .name = "tx_green_prio_6",
+               .reg = SYS_COUNT_TX_GREEN_PRIO_6,
+       },
+       [OCELOT_STAT_TX_GREEN_PRIO_7] = {
+               .name = "tx_green_prio_7",
+               .reg = SYS_COUNT_TX_GREEN_PRIO_7,
+       },
+       [OCELOT_STAT_TX_AGED] = {
+               .name = "tx_aged",
+               .reg = SYS_COUNT_TX_AGING,
+       },
+       [OCELOT_STAT_DROP_LOCAL] = {
+               .name = "drop_local",
+               .reg = SYS_COUNT_DROP_LOCAL,
+       },
+       [OCELOT_STAT_DROP_TAIL] = {
+               .name = "drop_tail",
+               .reg = SYS_COUNT_DROP_TAIL,
+       },
+       [OCELOT_STAT_DROP_YELLOW_PRIO_0] = {
+               .name = "drop_yellow_prio_0",
+               .reg = SYS_COUNT_DROP_YELLOW_PRIO_0,
+       },
+       [OCELOT_STAT_DROP_YELLOW_PRIO_1] = {
+               .name = "drop_yellow_prio_1",
+               .reg = SYS_COUNT_DROP_YELLOW_PRIO_1,
+       },
+       [OCELOT_STAT_DROP_YELLOW_PRIO_2] = {
+               .name = "drop_yellow_prio_2",
+               .reg = SYS_COUNT_DROP_YELLOW_PRIO_2,
+       },
+       [OCELOT_STAT_DROP_YELLOW_PRIO_3] = {
+               .name = "drop_yellow_prio_3",
+               .reg = SYS_COUNT_DROP_YELLOW_PRIO_3,
+       },
+       [OCELOT_STAT_DROP_YELLOW_PRIO_4] = {
+               .name = "drop_yellow_prio_4",
+               .reg = SYS_COUNT_DROP_YELLOW_PRIO_4,
+       },
+       [OCELOT_STAT_DROP_YELLOW_PRIO_5] = {
+               .name = "drop_yellow_prio_5",
+               .reg = SYS_COUNT_DROP_YELLOW_PRIO_5,
+       },
+       [OCELOT_STAT_DROP_YELLOW_PRIO_6] = {
+               .name = "drop_yellow_prio_6",
+               .reg = SYS_COUNT_DROP_YELLOW_PRIO_6,
+       },
+       [OCELOT_STAT_DROP_YELLOW_PRIO_7] = {
+               .name = "drop_yellow_prio_7",
+               .reg = SYS_COUNT_DROP_YELLOW_PRIO_7,
+       },
+       [OCELOT_STAT_DROP_GREEN_PRIO_0] = {
+               .name = "drop_green_prio_0",
+               .reg = SYS_COUNT_DROP_GREEN_PRIO_0,
+       },
+       [OCELOT_STAT_DROP_GREEN_PRIO_1] = {
+               .name = "drop_green_prio_1",
+               .reg = SYS_COUNT_DROP_GREEN_PRIO_1,
+       },
+       [OCELOT_STAT_DROP_GREEN_PRIO_2] = {
+               .name = "drop_green_prio_2",
+               .reg = SYS_COUNT_DROP_GREEN_PRIO_2,
+       },
+       [OCELOT_STAT_DROP_GREEN_PRIO_3] = {
+               .name = "drop_green_prio_3",
+               .reg = SYS_COUNT_DROP_GREEN_PRIO_3,
+       },
+       [OCELOT_STAT_DROP_GREEN_PRIO_4] = {
+               .name = "drop_green_prio_4",
+               .reg = SYS_COUNT_DROP_GREEN_PRIO_4,
+       },
+       [OCELOT_STAT_DROP_GREEN_PRIO_5] = {
+               .name = "drop_green_prio_5",
+               .reg = SYS_COUNT_DROP_GREEN_PRIO_5,
+       },
+       [OCELOT_STAT_DROP_GREEN_PRIO_6] = {
+               .name = "drop_green_prio_6",
+               .reg = SYS_COUNT_DROP_GREEN_PRIO_6,
+       },
+       [OCELOT_STAT_DROP_GREEN_PRIO_7] = {
+               .name = "drop_green_prio_7",
+               .reg = SYS_COUNT_DROP_GREEN_PRIO_7,
+       },
 };
 
 static const struct vcap_field vsc9953_vcap_es0_keys[] = {
index 1d3e778..c181346 100644 (file)
@@ -1889,9 +1889,9 @@ qca8k_sw_probe(struct mdio_device *mdiodev)
        if (!priv)
                return -ENOMEM;
 
-       priv->info = of_device_get_match_data(priv->dev);
        priv->bus = mdiodev->bus;
        priv->dev = &mdiodev->dev;
+       priv->info = of_device_get_match_data(priv->dev);
 
        priv->reset_gpio = devm_gpiod_get_optional(priv->dev, "reset",
                                                   GPIOD_ASIS);
index 0569ff0..10c6fea 100644 (file)
@@ -93,7 +93,7 @@ static int sja1105_setup_devlink_regions(struct dsa_switch *ds)
 
                region = dsa_devlink_region_create(ds, ops, 1, size);
                if (IS_ERR(region)) {
-                       while (i-- >= 0)
+                       while (--i >= 0)
                                dsa_devlink_region_destroy(priv->regions[i]);
                        return PTR_ERR(region);
                }
index 3887ed3..fa62263 100644 (file)
@@ -109,6 +109,7 @@ static void xrs700x_read_port_counters(struct xrs700x *priv, int port)
 {
        struct xrs700x_port *p = &priv->ports[port];
        struct rtnl_link_stats64 stats;
+       unsigned long flags;
        int i;
 
        memset(&stats, 0, sizeof(stats));
@@ -138,9 +139,9 @@ static void xrs700x_read_port_counters(struct xrs700x *priv, int port)
         */
        stats.rx_packets += stats.multicast;
 
-       u64_stats_update_begin(&p->syncp);
+       flags = u64_stats_update_begin_irqsave(&p->syncp);
        p->stats64 = stats;
-       u64_stats_update_end(&p->syncp);
+       u64_stats_update_end_irqrestore(&p->syncp, flags);
 
        mutex_unlock(&p->mib_mutex);
 }
index 7071604..0280851 100644 (file)
@@ -13844,7 +13844,7 @@ static void bnx2x_check_kr2_wa(struct link_params *params,
 
        /* Once KR2 was disabled, wait 5 seconds before checking KR2 recovery
         * Since some switches tend to reinit the AN process and clear the
-        * the advertised BP/NP after ~2 seconds causing the KR2 to be disabled
+        * advertised BP/NP after ~2 seconds causing the KR2 to be disabled
         * and recovered many times
         */
        if (vars->check_kr2_recovery_cnt > 0) {
index ba0f1ff..f46eefb 100644 (file)
@@ -11178,10 +11178,7 @@ static netdev_features_t bnxt_fix_features(struct net_device *dev,
        if ((features & NETIF_F_NTUPLE) && !bnxt_rfs_capable(bp))
                features &= ~NETIF_F_NTUPLE;
 
-       if (bp->flags & BNXT_FLAG_NO_AGG_RINGS)
-               features &= ~(NETIF_F_LRO | NETIF_F_GRO_HW);
-
-       if (!(bp->flags & BNXT_FLAG_TPA))
+       if ((bp->flags & BNXT_FLAG_NO_AGG_RINGS) || bp->xdp_prog)
                features &= ~(NETIF_F_LRO | NETIF_F_GRO_HW);
 
        if (!(features & NETIF_F_GRO))
index 075c620..b1b17f9 100644 (file)
@@ -2130,6 +2130,7 @@ struct bnxt {
 #define BNXT_DUMP_CRASH                1
 
        struct bpf_prog         *xdp_prog;
+       u8                      xdp_has_frags;
 
        struct bnxt_ptp_cfg     *ptp_cfg;
        u8                      ptp_all_rx_tstamp;
index 059f96f..a36803e 100644 (file)
@@ -1306,6 +1306,7 @@ int bnxt_dl_register(struct bnxt *bp)
        if (rc)
                goto err_dl_port_unreg;
 
+       devlink_set_features(dl, DEVLINK_F_RELOAD);
 out:
        devlink_register(dl);
        return 0;
index 730febd..a4cba7c 100644 (file)
@@ -623,7 +623,7 @@ static int bnxt_hwrm_func_vf_resc_cfg(struct bnxt *bp, int num_vfs, bool reset)
                hw_resc->max_stat_ctxs -= le16_to_cpu(req->min_stat_ctx) * n;
                hw_resc->max_vnics -= le16_to_cpu(req->min_vnics) * n;
                if (bp->flags & BNXT_FLAG_CHIP_P5)
-                       hw_resc->max_irqs -= vf_msix * n;
+                       hw_resc->max_nqs -= vf_msix;
 
                rc = pf->active_vfs;
        }
index f53387e..c3065ec 100644 (file)
@@ -181,6 +181,7 @@ void bnxt_xdp_buff_init(struct bnxt *bp, struct bnxt_rx_ring_info *rxr,
                        struct xdp_buff *xdp)
 {
        struct bnxt_sw_rx_bd *rx_buf;
+       u32 buflen = PAGE_SIZE;
        struct pci_dev *pdev;
        dma_addr_t mapping;
        u32 offset;
@@ -192,7 +193,10 @@ void bnxt_xdp_buff_init(struct bnxt *bp, struct bnxt_rx_ring_info *rxr,
        mapping = rx_buf->mapping - bp->rx_dma_offset;
        dma_sync_single_for_cpu(&pdev->dev, mapping + offset, *len, bp->rx_dir);
 
-       xdp_init_buff(xdp, BNXT_PAGE_MODE_BUF_SIZE + offset, &rxr->xdp_rxq);
+       if (bp->xdp_has_frags)
+               buflen = BNXT_PAGE_MODE_BUF_SIZE + offset;
+
+       xdp_init_buff(xdp, buflen, &rxr->xdp_rxq);
        xdp_prepare_buff(xdp, *data_ptr - offset, offset, *len, false);
 }
 
@@ -397,8 +401,10 @@ static int bnxt_xdp_set(struct bnxt *bp, struct bpf_prog *prog)
                netdev_warn(dev, "ethtool rx/tx channels must be combined to support XDP.\n");
                return -EOPNOTSUPP;
        }
-       if (prog)
+       if (prog) {
                tx_xdp = bp->rx_nr_rings;
+               bp->xdp_has_frags = prog->aux->xdp_has_frags;
+       }
 
        tc = netdev_get_num_tc(dev);
        if (!tc)
index db1e9d8..89889d8 100644 (file)
@@ -18076,16 +18076,20 @@ static void tg3_shutdown(struct pci_dev *pdev)
        struct net_device *dev = pci_get_drvdata(pdev);
        struct tg3 *tp = netdev_priv(dev);
 
+       tg3_reset_task_cancel(tp);
+
        rtnl_lock();
+
        netif_device_detach(dev);
 
        if (netif_running(dev))
                dev_close(dev);
 
-       if (system_state == SYSTEM_POWER_OFF)
-               tg3_power_down(tp);
+       tg3_power_down(tp);
 
        rtnl_unlock();
+
+       pci_disable_device(pdev);
 }
 
 /**
index 84604af..89256b8 100644 (file)
@@ -243,7 +243,7 @@ static int cxgb_ulp_iscsi_ctl(struct adapter *adapter, unsigned int req,
 
                /*
                 * on rx, the iscsi pdu has to be < rx page size and the
-                * the max rx data length programmed in TP
+                * max rx data length programmed in TP
                 */
                val = min(adapter->params.tp.rx_pg_size,
                          ((t3_read_reg(adapter, A_TP_PARA_REG2)) >>
index 26433a6..fed5f93 100644 (file)
@@ -497,7 +497,7 @@ struct cpl_t5_pass_accept_rpl {
        __be32 opt2;
        __be64 opt0;
        __be32 iss;
-       __be32 rsvd[3];
+       __be32 rsvd;
 };
 
 struct cpl_act_open_req {
index 9e6de2f..6dae768 100644 (file)
@@ -1919,7 +1919,7 @@ static void gmac_get_stats64(struct net_device *netdev,
 
        /* Racing with RX NAPI */
        do {
-               start = u64_stats_fetch_begin(&port->rx_stats_syncp);
+               start = u64_stats_fetch_begin_irq(&port->rx_stats_syncp);
 
                stats->rx_packets = port->stats.rx_packets;
                stats->rx_bytes = port->stats.rx_bytes;
@@ -1931,11 +1931,11 @@ static void gmac_get_stats64(struct net_device *netdev,
                stats->rx_crc_errors = port->stats.rx_crc_errors;
                stats->rx_frame_errors = port->stats.rx_frame_errors;
 
-       } while (u64_stats_fetch_retry(&port->rx_stats_syncp, start));
+       } while (u64_stats_fetch_retry_irq(&port->rx_stats_syncp, start));
 
        /* Racing with MIB and TX completion interrupts */
        do {
-               start = u64_stats_fetch_begin(&port->ir_stats_syncp);
+               start = u64_stats_fetch_begin_irq(&port->ir_stats_syncp);
 
                stats->tx_errors = port->stats.tx_errors;
                stats->tx_packets = port->stats.tx_packets;
@@ -1945,15 +1945,15 @@ static void gmac_get_stats64(struct net_device *netdev,
                stats->rx_missed_errors = port->stats.rx_missed_errors;
                stats->rx_fifo_errors = port->stats.rx_fifo_errors;
 
-       } while (u64_stats_fetch_retry(&port->ir_stats_syncp, start));
+       } while (u64_stats_fetch_retry_irq(&port->ir_stats_syncp, start));
 
        /* Racing with hard_start_xmit */
        do {
-               start = u64_stats_fetch_begin(&port->tx_stats_syncp);
+               start = u64_stats_fetch_begin_irq(&port->tx_stats_syncp);
 
                stats->tx_dropped = port->stats.tx_dropped;
 
-       } while (u64_stats_fetch_retry(&port->tx_stats_syncp, start));
+       } while (u64_stats_fetch_retry_irq(&port->tx_stats_syncp, start));
 
        stats->rx_dropped += stats->rx_missed_errors;
 }
@@ -2031,18 +2031,18 @@ static void gmac_get_ethtool_stats(struct net_device *netdev,
        /* Racing with MIB interrupt */
        do {
                p = values;
-               start = u64_stats_fetch_begin(&port->ir_stats_syncp);
+               start = u64_stats_fetch_begin_irq(&port->ir_stats_syncp);
 
                for (i = 0; i < RX_STATS_NUM; i++)
                        *p++ = port->hw_stats[i];
 
-       } while (u64_stats_fetch_retry(&port->ir_stats_syncp, start));
+       } while (u64_stats_fetch_retry_irq(&port->ir_stats_syncp, start));
        values = p;
 
        /* Racing with RX NAPI */
        do {
                p = values;
-               start = u64_stats_fetch_begin(&port->rx_stats_syncp);
+               start = u64_stats_fetch_begin_irq(&port->rx_stats_syncp);
 
                for (i = 0; i < RX_STATUS_NUM; i++)
                        *p++ = port->rx_stats[i];
@@ -2050,13 +2050,13 @@ static void gmac_get_ethtool_stats(struct net_device *netdev,
                        *p++ = port->rx_csum_stats[i];
                *p++ = port->rx_napi_exits;
 
-       } while (u64_stats_fetch_retry(&port->rx_stats_syncp, start));
+       } while (u64_stats_fetch_retry_irq(&port->rx_stats_syncp, start));
        values = p;
 
        /* Racing with TX start_xmit */
        do {
                p = values;
-               start = u64_stats_fetch_begin(&port->tx_stats_syncp);
+               start = u64_stats_fetch_begin_irq(&port->tx_stats_syncp);
 
                for (i = 0; i < TX_MAX_FRAGS; i++) {
                        *values++ = port->tx_frag_stats[i];
@@ -2065,7 +2065,7 @@ static void gmac_get_ethtool_stats(struct net_device *netdev,
                *values++ = port->tx_frags_linearized;
                *values++ = port->tx_hw_csummed;
 
-       } while (u64_stats_fetch_retry(&port->tx_stats_syncp, start));
+       } while (u64_stats_fetch_retry_irq(&port->tx_stats_syncp, start));
 }
 
 static int gmac_get_ksettings(struct net_device *netdev,
index 4563457..a770bab 100644 (file)
@@ -2886,6 +2886,7 @@ static void dpaa_adjust_link(struct net_device *net_dev)
 
 /* The Aquantia PHYs are capable of performing rate adaptation */
 #define PHY_VEND_AQUANTIA      0x03a1b400
+#define PHY_VEND_AQUANTIA2     0x31c31c00
 
 static int dpaa_phy_init(struct net_device *net_dev)
 {
@@ -2893,6 +2894,7 @@ static int dpaa_phy_init(struct net_device *net_dev)
        struct mac_device *mac_dev;
        struct phy_device *phy_dev;
        struct dpaa_priv *priv;
+       u32 phy_vendor;
 
        priv = netdev_priv(net_dev);
        mac_dev = priv->mac_dev;
@@ -2905,9 +2907,11 @@ static int dpaa_phy_init(struct net_device *net_dev)
                return -ENODEV;
        }
 
+       phy_vendor = phy_dev->drv->phy_id & GENMASK(31, 10);
        /* Unless the PHY is capable of rate adaptation */
        if (mac_dev->phy_if != PHY_INTERFACE_MODE_XGMII ||
-           ((phy_dev->drv->phy_id & GENMASK(31, 10)) != PHY_VEND_AQUANTIA)) {
+           (phy_vendor != PHY_VEND_AQUANTIA &&
+            phy_vendor != PHY_VEND_AQUANTIA2)) {
                /* remove any features not supported by the controller */
                ethtool_convert_legacy_u32_to_link_mode(mask,
                                                        mac_dev->if_support);
index ed7301b..d77ee89 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <linux/clocksource.h>
 #include <linux/net_tstamp.h>
+#include <linux/pm_qos.h>
 #include <linux/ptp_clock_kernel.h>
 #include <linux/timecounter.h>
 
@@ -498,6 +499,9 @@ struct bufdesc_ex {
 /* i.MX8MQ SoC integration mix wakeup interrupt signal into "int2" interrupt line. */
 #define FEC_QUIRK_WAKEUP_FROM_INT2     (1 << 22)
 
+/* i.MX6Q adds pm_qos support */
+#define FEC_QUIRK_HAS_PMQOS                    BIT(23)
+
 struct bufdesc_prop {
        int qid;
        /* Address of Rx and Tx buffers */
@@ -557,7 +561,6 @@ struct fec_enet_private {
        struct clk *clk_2x_txclk;
 
        bool ptp_clk_on;
-       struct mutex ptp_clk_mutex;
        unsigned int num_tx_queues;
        unsigned int num_rx_queues;
 
@@ -608,6 +611,7 @@ struct fec_enet_private {
        struct delayed_work time_keep;
        struct regulator *reg_phy;
        struct fec_stop_mode_gpr stop_gpr;
+       struct pm_qos_request pm_qos_req;
 
        unsigned int tx_align;
        unsigned int rx_align;
@@ -634,6 +638,13 @@ struct fec_enet_private {
        int pps_enable;
        unsigned int next_counter;
 
+       struct {
+               struct timespec64 ts_phc;
+               u64 ns_sys;
+               u32 at_corr;
+               u8 at_inc_corr;
+       } ptp_saved_state;
+
        u64 ethtool_stats[];
 };
 
@@ -644,5 +655,8 @@ void fec_ptp_disable_hwts(struct net_device *ndev);
 int fec_ptp_set(struct net_device *ndev, struct ifreq *ifr);
 int fec_ptp_get(struct net_device *ndev, struct ifreq *ifr);
 
+void fec_ptp_save_state(struct fec_enet_private *fep);
+int fec_ptp_restore_state(struct fec_enet_private *fep);
+
 /****************************************************************************/
 #endif /* FEC_H */
index e8e2aa1..6152f6d 100644 (file)
@@ -111,7 +111,8 @@ static const struct fec_devinfo fec_imx6q_info = {
        .quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
                  FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
                  FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR006358 |
-                 FEC_QUIRK_HAS_RACC | FEC_QUIRK_CLEAR_SETUP_MII,
+                 FEC_QUIRK_HAS_RACC | FEC_QUIRK_CLEAR_SETUP_MII |
+                 FEC_QUIRK_HAS_PMQOS,
 };
 
 static const struct fec_devinfo fec_mvf600_info = {
@@ -285,8 +286,11 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
 #define FEC_MMFR_TA            (2 << 16)
 #define FEC_MMFR_DATA(v)       (v & 0xffff)
 /* FEC ECR bits definition */
-#define FEC_ECR_MAGICEN                (1 << 2)
-#define FEC_ECR_SLEEP          (1 << 3)
+#define FEC_ECR_RESET   BIT(0)
+#define FEC_ECR_ETHEREN BIT(1)
+#define FEC_ECR_MAGICEN BIT(2)
+#define FEC_ECR_SLEEP   BIT(3)
+#define FEC_ECR_EN1588  BIT(4)
 
 #define FEC_MII_TIMEOUT                30000 /* us */
 
@@ -982,6 +986,9 @@ fec_restart(struct net_device *ndev)
        u32 temp_mac[2];
        u32 rcntl = OPT_FRAME_SIZE | 0x04;
        u32 ecntl = 0x2; /* ETHEREN */
+       struct ptp_clock_request ptp_rq = { .type = PTP_CLK_REQ_PPS };
+
+       fec_ptp_save_state(fep);
 
        /* Whack a reset.  We should wait for this.
         * For i.MX6SX SOC, enet use AXI bus, we use disable MAC
@@ -1135,7 +1142,7 @@ fec_restart(struct net_device *ndev)
        }
 
        if (fep->bufdesc_ex)
-               ecntl |= (1 << 4);
+               ecntl |= FEC_ECR_EN1588;
 
        if (fep->quirks & FEC_QUIRK_DELAYED_CLKS_SUPPORT &&
            fep->rgmii_txc_dly)
@@ -1156,6 +1163,14 @@ fec_restart(struct net_device *ndev)
        if (fep->bufdesc_ex)
                fec_ptp_start_cyclecounter(ndev);
 
+       /* Restart PPS if needed */
+       if (fep->pps_enable) {
+               /* Clear flag so fec_ptp_enable_pps() doesn't return immediately */
+               fep->pps_enable = 0;
+               fec_ptp_restore_state(fep);
+               fep->ptp_caps.enable(&fep->ptp_caps, &ptp_rq, 1);
+       }
+
        /* Enable interrupts we wish to service */
        if (fep->link)
                writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
@@ -1206,6 +1221,8 @@ fec_stop(struct net_device *ndev)
        struct fec_enet_private *fep = netdev_priv(ndev);
        u32 rmii_mode = readl(fep->hwp + FEC_R_CNTRL) & (1 << 8);
        u32 val;
+       struct ptp_clock_request ptp_rq = { .type = PTP_CLK_REQ_PPS };
+       u32 ecntl = 0;
 
        /* We cannot expect a graceful transmit stop without link !!! */
        if (fep->link) {
@@ -1215,6 +1232,8 @@ fec_stop(struct net_device *ndev)
                        netdev_err(ndev, "Graceful transmit stop did not complete!\n");
        }
 
+       fec_ptp_save_state(fep);
+
        /* Whack a reset.  We should wait for this.
         * For i.MX6SX SOC, enet use AXI bus, we use disable MAC
         * instead of reset MAC itself.
@@ -1234,12 +1253,28 @@ fec_stop(struct net_device *ndev)
        writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
        writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
 
+       if (fep->bufdesc_ex)
+               ecntl |= FEC_ECR_EN1588;
+
        /* We have to keep ENET enabled to have MII interrupt stay working */
        if (fep->quirks & FEC_QUIRK_ENET_MAC &&
                !(fep->wol_flag & FEC_WOL_FLAG_SLEEP_ON)) {
-               writel(2, fep->hwp + FEC_ECNTRL);
+               ecntl |= FEC_ECR_ETHEREN;
                writel(rmii_mode, fep->hwp + FEC_R_CNTRL);
        }
+
+       writel(ecntl, fep->hwp + FEC_ECNTRL);
+
+       if (fep->bufdesc_ex)
+               fec_ptp_start_cyclecounter(ndev);
+
+       /* Restart PPS if needed */
+       if (fep->pps_enable) {
+               /* Clear flag so fec_ptp_enable_pps() doesn't return immediately */
+               fep->pps_enable = 0;
+               fec_ptp_restore_state(fep);
+               fep->ptp_caps.enable(&fep->ptp_caps, &ptp_rq, 1);
+       }
 }
 
 
@@ -1994,6 +2029,7 @@ static void fec_enet_phy_reset_after_clk_enable(struct net_device *ndev)
 static int fec_enet_clk_enable(struct net_device *ndev, bool enable)
 {
        struct fec_enet_private *fep = netdev_priv(ndev);
+       unsigned long flags;
        int ret;
 
        if (enable) {
@@ -2002,15 +2038,15 @@ static int fec_enet_clk_enable(struct net_device *ndev, bool enable)
                        return ret;
 
                if (fep->clk_ptp) {
-                       mutex_lock(&fep->ptp_clk_mutex);
+                       spin_lock_irqsave(&fep->tmreg_lock, flags);
                        ret = clk_prepare_enable(fep->clk_ptp);
                        if (ret) {
-                               mutex_unlock(&fep->ptp_clk_mutex);
+                               spin_unlock_irqrestore(&fep->tmreg_lock, flags);
                                goto failed_clk_ptp;
                        } else {
                                fep->ptp_clk_on = true;
                        }
-                       mutex_unlock(&fep->ptp_clk_mutex);
+                       spin_unlock_irqrestore(&fep->tmreg_lock, flags);
                }
 
                ret = clk_prepare_enable(fep->clk_ref);
@@ -2025,10 +2061,10 @@ static int fec_enet_clk_enable(struct net_device *ndev, bool enable)
        } else {
                clk_disable_unprepare(fep->clk_enet_out);
                if (fep->clk_ptp) {
-                       mutex_lock(&fep->ptp_clk_mutex);
+                       spin_lock_irqsave(&fep->tmreg_lock, flags);
                        clk_disable_unprepare(fep->clk_ptp);
                        fep->ptp_clk_on = false;
-                       mutex_unlock(&fep->ptp_clk_mutex);
+                       spin_unlock_irqrestore(&fep->tmreg_lock, flags);
                }
                clk_disable_unprepare(fep->clk_ref);
                clk_disable_unprepare(fep->clk_2x_txclk);
@@ -2041,10 +2077,10 @@ failed_clk_2x_txclk:
                clk_disable_unprepare(fep->clk_ref);
 failed_clk_ref:
        if (fep->clk_ptp) {
-               mutex_lock(&fep->ptp_clk_mutex);
+               spin_lock_irqsave(&fep->tmreg_lock, flags);
                clk_disable_unprepare(fep->clk_ptp);
                fep->ptp_clk_on = false;
-               mutex_unlock(&fep->ptp_clk_mutex);
+               spin_unlock_irqrestore(&fep->tmreg_lock, flags);
        }
 failed_clk_ptp:
        clk_disable_unprepare(fep->clk_enet_out);
@@ -3210,6 +3246,9 @@ fec_enet_open(struct net_device *ndev)
        if (fep->quirks & FEC_QUIRK_ERR006687)
                imx6q_cpuidle_fec_irqs_used();
 
+       if (fep->quirks & FEC_QUIRK_HAS_PMQOS)
+               cpu_latency_qos_add_request(&fep->pm_qos_req, 0);
+
        napi_enable(&fep->napi);
        phy_start(ndev->phydev);
        netif_tx_start_all_queues(ndev);
@@ -3251,6 +3290,9 @@ fec_enet_close(struct net_device *ndev)
        fec_enet_update_ethtool_stats(ndev);
 
        fec_enet_clk_enable(ndev, false);
+       if (fep->quirks & FEC_QUIRK_HAS_PMQOS)
+               cpu_latency_qos_remove_request(&fep->pm_qos_req);
+
        pinctrl_pm_select_sleep_state(&fep->pdev->dev);
        pm_runtime_mark_last_busy(&fep->pdev->dev);
        pm_runtime_put_autosuspend(&fep->pdev->dev);
@@ -3873,7 +3915,7 @@ fec_probe(struct platform_device *pdev)
        }
 
        fep->ptp_clk_on = false;
-       mutex_init(&fep->ptp_clk_mutex);
+       spin_lock_init(&fep->tmreg_lock);
 
        /* clk_ref is optional, depends on board */
        fep->clk_ref = devm_clk_get_optional(&pdev->dev, "enet_clk_ref");
index 7d49c28..8dd5a26 100644 (file)
@@ -135,11 +135,7 @@ static int fec_ptp_enable_pps(struct fec_enet_private *fep, uint enable)
                 * NSEC_PER_SEC - ts.tv_nsec. Add the remaining nanoseconds
                 * to current timer would be next second.
                 */
-               tempval = readl(fep->hwp + FEC_ATIME_CTRL);
-               tempval |= FEC_T_CTRL_CAPTURE;
-               writel(tempval, fep->hwp + FEC_ATIME_CTRL);
-
-               tempval = readl(fep->hwp + FEC_ATIME);
+               tempval = fep->cc.read(&fep->cc);
                /* Convert the ptp local counter to 1588 timestamp */
                ns = timecounter_cyc2time(&fep->tc, tempval);
                ts = ns_to_timespec64(ns);
@@ -369,21 +365,19 @@ static int fec_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
  */
 static int fec_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
 {
-       struct fec_enet_private *adapter =
+       struct fec_enet_private *fep =
            container_of(ptp, struct fec_enet_private, ptp_caps);
        u64 ns;
        unsigned long flags;
 
-       mutex_lock(&adapter->ptp_clk_mutex);
+       spin_lock_irqsave(&fep->tmreg_lock, flags);
        /* Check the ptp clock */
-       if (!adapter->ptp_clk_on) {
-               mutex_unlock(&adapter->ptp_clk_mutex);
+       if (!fep->ptp_clk_on) {
+               spin_unlock_irqrestore(&fep->tmreg_lock, flags);
                return -EINVAL;
        }
-       spin_lock_irqsave(&adapter->tmreg_lock, flags);
-       ns = timecounter_read(&adapter->tc);
-       spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
-       mutex_unlock(&adapter->ptp_clk_mutex);
+       ns = timecounter_read(&fep->tc);
+       spin_unlock_irqrestore(&fep->tmreg_lock, flags);
 
        *ts = ns_to_timespec64(ns);
 
@@ -408,10 +402,10 @@ static int fec_ptp_settime(struct ptp_clock_info *ptp,
        unsigned long flags;
        u32 counter;
 
-       mutex_lock(&fep->ptp_clk_mutex);
+       spin_lock_irqsave(&fep->tmreg_lock, flags);
        /* Check the ptp clock */
        if (!fep->ptp_clk_on) {
-               mutex_unlock(&fep->ptp_clk_mutex);
+               spin_unlock_irqrestore(&fep->tmreg_lock, flags);
                return -EINVAL;
        }
 
@@ -421,11 +415,9 @@ static int fec_ptp_settime(struct ptp_clock_info *ptp,
         */
        counter = ns & fep->cc.mask;
 
-       spin_lock_irqsave(&fep->tmreg_lock, flags);
        writel(counter, fep->hwp + FEC_ATIME);
        timecounter_init(&fep->tc, &fep->cc, ns);
        spin_unlock_irqrestore(&fep->tmreg_lock, flags);
-       mutex_unlock(&fep->ptp_clk_mutex);
        return 0;
 }
 
@@ -522,13 +514,11 @@ static void fec_time_keep(struct work_struct *work)
        struct fec_enet_private *fep = container_of(dwork, struct fec_enet_private, time_keep);
        unsigned long flags;
 
-       mutex_lock(&fep->ptp_clk_mutex);
+       spin_lock_irqsave(&fep->tmreg_lock, flags);
        if (fep->ptp_clk_on) {
-               spin_lock_irqsave(&fep->tmreg_lock, flags);
                timecounter_read(&fep->tc);
-               spin_unlock_irqrestore(&fep->tmreg_lock, flags);
        }
-       mutex_unlock(&fep->ptp_clk_mutex);
+       spin_unlock_irqrestore(&fep->tmreg_lock, flags);
 
        schedule_delayed_work(&fep->time_keep, HZ);
 }
@@ -603,8 +593,6 @@ void fec_ptp_init(struct platform_device *pdev, int irq_idx)
        }
        fep->ptp_inc = NSEC_PER_SEC / fep->cycle_speed;
 
-       spin_lock_init(&fep->tmreg_lock);
-
        fec_ptp_start_cyclecounter(ndev);
 
        INIT_DELAYED_WORK(&fep->time_keep, fec_time_keep);
@@ -637,7 +625,36 @@ void fec_ptp_stop(struct platform_device *pdev)
        struct net_device *ndev = platform_get_drvdata(pdev);
        struct fec_enet_private *fep = netdev_priv(ndev);
 
+       if (fep->pps_enable)
+               fec_ptp_enable_pps(fep, 0);
+
        cancel_delayed_work_sync(&fep->time_keep);
        if (fep->ptp_clock)
                ptp_clock_unregister(fep->ptp_clock);
 }
+
+void fec_ptp_save_state(struct fec_enet_private *fep)
+{
+       u32 atime_inc_corr;
+
+       fec_ptp_gettime(&fep->ptp_caps, &fep->ptp_saved_state.ts_phc);
+       fep->ptp_saved_state.ns_sys = ktime_get_ns();
+
+       fep->ptp_saved_state.at_corr = readl(fep->hwp + FEC_ATIME_CORR);
+       atime_inc_corr = readl(fep->hwp + FEC_ATIME_INC) & FEC_T_INC_CORR_MASK;
+       fep->ptp_saved_state.at_inc_corr = (u8)(atime_inc_corr >> FEC_T_INC_CORR_OFFSET);
+}
+
+int fec_ptp_restore_state(struct fec_enet_private *fep)
+{
+       u32 atime_inc = readl(fep->hwp + FEC_ATIME_INC) & FEC_T_INC_MASK;
+       u64 ns_sys;
+
+       writel(fep->ptp_saved_state.at_corr, fep->hwp + FEC_ATIME_CORR);
+       atime_inc |= ((u32)fep->ptp_saved_state.at_inc_corr) << FEC_T_INC_CORR_OFFSET;
+       writel(atime_inc, fep->hwp + FEC_ATIME_INC);
+
+       ns_sys = ktime_get_ns() - fep->ptp_saved_state.ns_sys;
+       timespec64_add_ns(&fep->ptp_saved_state.ts_phc, ns_sys);
+       return fec_ptp_settime(&fep->ptp_caps, &fep->ptp_saved_state.ts_phc);
+}
index 53b7e95..671f511 100644 (file)
@@ -206,9 +206,9 @@ struct funeth_rxq {
 
 #define FUN_QSTAT_READ(q, seq, stats_copy) \
        do { \
-               seq = u64_stats_fetch_begin(&(q)->syncp); \
+               seq = u64_stats_fetch_begin_irq(&(q)->syncp); \
                stats_copy = (q)->stats; \
-       } while (u64_stats_fetch_retry(&(q)->syncp, (seq)))
+       } while (u64_stats_fetch_retry_irq(&(q)->syncp, (seq)))
 
 #define FUN_INT_NAME_LEN (IFNAMSIZ + 16)
 
index 50b3849..7b9a2d9 100644 (file)
@@ -177,14 +177,14 @@ gve_get_ethtool_stats(struct net_device *netdev,
                                struct gve_rx_ring *rx = &priv->rx[ring];
 
                                start =
-                                 u64_stats_fetch_begin(&priv->rx[ring].statss);
+                                 u64_stats_fetch_begin_irq(&priv->rx[ring].statss);
                                tmp_rx_pkts = rx->rpackets;
                                tmp_rx_bytes = rx->rbytes;
                                tmp_rx_skb_alloc_fail = rx->rx_skb_alloc_fail;
                                tmp_rx_buf_alloc_fail = rx->rx_buf_alloc_fail;
                                tmp_rx_desc_err_dropped_pkt =
                                        rx->rx_desc_err_dropped_pkt;
-                       } while (u64_stats_fetch_retry(&priv->rx[ring].statss,
+                       } while (u64_stats_fetch_retry_irq(&priv->rx[ring].statss,
                                                       start));
                        rx_pkts += tmp_rx_pkts;
                        rx_bytes += tmp_rx_bytes;
@@ -198,10 +198,10 @@ gve_get_ethtool_stats(struct net_device *netdev,
                if (priv->tx) {
                        do {
                                start =
-                                 u64_stats_fetch_begin(&priv->tx[ring].statss);
+                                 u64_stats_fetch_begin_irq(&priv->tx[ring].statss);
                                tmp_tx_pkts = priv->tx[ring].pkt_done;
                                tmp_tx_bytes = priv->tx[ring].bytes_done;
-                       } while (u64_stats_fetch_retry(&priv->tx[ring].statss,
+                       } while (u64_stats_fetch_retry_irq(&priv->tx[ring].statss,
                                                       start));
                        tx_pkts += tmp_tx_pkts;
                        tx_bytes += tmp_tx_bytes;
@@ -259,13 +259,13 @@ gve_get_ethtool_stats(struct net_device *netdev,
                        data[i++] = rx->fill_cnt - rx->cnt;
                        do {
                                start =
-                                 u64_stats_fetch_begin(&priv->rx[ring].statss);
+                                 u64_stats_fetch_begin_irq(&priv->rx[ring].statss);
                                tmp_rx_bytes = rx->rbytes;
                                tmp_rx_skb_alloc_fail = rx->rx_skb_alloc_fail;
                                tmp_rx_buf_alloc_fail = rx->rx_buf_alloc_fail;
                                tmp_rx_desc_err_dropped_pkt =
                                        rx->rx_desc_err_dropped_pkt;
-                       } while (u64_stats_fetch_retry(&priv->rx[ring].statss,
+                       } while (u64_stats_fetch_retry_irq(&priv->rx[ring].statss,
                                                       start));
                        data[i++] = tmp_rx_bytes;
                        data[i++] = rx->rx_cont_packet_cnt;
@@ -331,9 +331,9 @@ gve_get_ethtool_stats(struct net_device *netdev,
                        }
                        do {
                                start =
-                                 u64_stats_fetch_begin(&priv->tx[ring].statss);
+                                 u64_stats_fetch_begin_irq(&priv->tx[ring].statss);
                                tmp_tx_bytes = tx->bytes_done;
-                       } while (u64_stats_fetch_retry(&priv->tx[ring].statss,
+                       } while (u64_stats_fetch_retry_irq(&priv->tx[ring].statss,
                                                       start));
                        data[i++] = tmp_tx_bytes;
                        data[i++] = tx->wake_queue;
index 6cafee5..044db3e 100644 (file)
@@ -51,10 +51,10 @@ static void gve_get_stats(struct net_device *dev, struct rtnl_link_stats64 *s)
                for (ring = 0; ring < priv->rx_cfg.num_queues; ring++) {
                        do {
                                start =
-                                 u64_stats_fetch_begin(&priv->rx[ring].statss);
+                                 u64_stats_fetch_begin_irq(&priv->rx[ring].statss);
                                packets = priv->rx[ring].rpackets;
                                bytes = priv->rx[ring].rbytes;
-                       } while (u64_stats_fetch_retry(&priv->rx[ring].statss,
+                       } while (u64_stats_fetch_retry_irq(&priv->rx[ring].statss,
                                                       start));
                        s->rx_packets += packets;
                        s->rx_bytes += bytes;
@@ -64,10 +64,10 @@ static void gve_get_stats(struct net_device *dev, struct rtnl_link_stats64 *s)
                for (ring = 0; ring < priv->tx_cfg.num_queues; ring++) {
                        do {
                                start =
-                                 u64_stats_fetch_begin(&priv->tx[ring].statss);
+                                 u64_stats_fetch_begin_irq(&priv->tx[ring].statss);
                                packets = priv->tx[ring].pkt_done;
                                bytes = priv->tx[ring].bytes_done;
-                       } while (u64_stats_fetch_retry(&priv->tx[ring].statss,
+                       } while (u64_stats_fetch_retry_irq(&priv->tx[ring].statss,
                                                       start));
                        s->tx_packets += packets;
                        s->tx_bytes += bytes;
@@ -1274,9 +1274,9 @@ void gve_handle_report_stats(struct gve_priv *priv)
                        }
 
                        do {
-                               start = u64_stats_fetch_begin(&priv->tx[idx].statss);
+                               start = u64_stats_fetch_begin_irq(&priv->tx[idx].statss);
                                tx_bytes = priv->tx[idx].bytes_done;
-                       } while (u64_stats_fetch_retry(&priv->tx[idx].statss, start));
+                       } while (u64_stats_fetch_retry_irq(&priv->tx[idx].statss, start));
                        stats[stats_idx++] = (struct stats) {
                                .stat_name = cpu_to_be32(TX_WAKE_CNT),
                                .value = cpu_to_be64(priv->tx[idx].wake_queue),
index a866bea..e5828a6 100644 (file)
@@ -74,14 +74,14 @@ void hinic_rxq_get_stats(struct hinic_rxq *rxq, struct hinic_rxq_stats *stats)
        unsigned int start;
 
        do {
-               start = u64_stats_fetch_begin(&rxq_stats->syncp);
+               start = u64_stats_fetch_begin_irq(&rxq_stats->syncp);
                stats->pkts = rxq_stats->pkts;
                stats->bytes = rxq_stats->bytes;
                stats->errors = rxq_stats->csum_errors +
                                rxq_stats->other_errors;
                stats->csum_errors = rxq_stats->csum_errors;
                stats->other_errors = rxq_stats->other_errors;
-       } while (u64_stats_fetch_retry(&rxq_stats->syncp, start));
+       } while (u64_stats_fetch_retry_irq(&rxq_stats->syncp, start));
 }
 
 /**
index 5051cdf..3b6c7b5 100644 (file)
@@ -99,14 +99,14 @@ void hinic_txq_get_stats(struct hinic_txq *txq, struct hinic_txq_stats *stats)
        unsigned int start;
 
        do {
-               start = u64_stats_fetch_begin(&txq_stats->syncp);
+               start = u64_stats_fetch_begin_irq(&txq_stats->syncp);
                stats->pkts    = txq_stats->pkts;
                stats->bytes   = txq_stats->bytes;
                stats->tx_busy = txq_stats->tx_busy;
                stats->tx_wake = txq_stats->tx_wake;
                stats->tx_dropped = txq_stats->tx_dropped;
                stats->big_frags_pkts = txq_stats->big_frags_pkts;
-       } while (u64_stats_fetch_retry(&txq_stats->syncp, start));
+       } while (u64_stats_fetch_retry_irq(&txq_stats->syncp, start));
 }
 
 /**
index ea2bb01..10d7a98 100644 (file)
@@ -177,6 +177,10 @@ void i40e_notify_client_of_netdev_close(struct i40e_vsi *vsi, bool reset)
                        "Cannot locate client instance close routine\n");
                return;
        }
+       if (!test_bit(__I40E_CLIENT_INSTANCE_OPENED, &cdev->state)) {
+               dev_dbg(&pf->pdev->dev, "Client is not open, abort close\n");
+               return;
+       }
        cdev->client->ops->close(&cdev->lan_info, cdev->client, reset);
        clear_bit(__I40E_CLIENT_INSTANCE_OPENED, &cdev->state);
        i40e_client_release_qvlist(&cdev->lan_info);
@@ -429,7 +433,6 @@ void i40e_client_subtask(struct i40e_pf *pf)
                                /* Remove failed client instance */
                                clear_bit(__I40E_CLIENT_INSTANCE_OPENED,
                                          &cdev->state);
-                               i40e_client_del_instance(pf);
                                return;
                        }
                }
index 156e92c..e9cd0fa 100644 (file)
@@ -4485,7 +4485,7 @@ static int i40e_check_fdir_input_set(struct i40e_vsi *vsi,
                                    (struct in6_addr *)&ipv6_full_mask))
                        new_mask |= I40E_L3_V6_DST_MASK;
                else if (ipv6_addr_any((struct in6_addr *)
-                                      &usr_ip6_spec->ip6src))
+                                      &usr_ip6_spec->ip6dst))
                        new_mask &= ~I40E_L3_V6_DST_MASK;
                else
                        return -EOPNOTSUPP;
index b36bf9c..10c1e1e 100644 (file)
@@ -384,7 +384,9 @@ static void i40e_tx_timeout(struct net_device *netdev, unsigned int txqueue)
                set_bit(__I40E_GLOBAL_RESET_REQUESTED, pf->state);
                break;
        default:
-               netdev_err(netdev, "tx_timeout recovery unsuccessful\n");
+               netdev_err(netdev, "tx_timeout recovery unsuccessful, device is in non-recoverable state.\n");
+               set_bit(__I40E_DOWN_REQUESTED, pf->state);
+               set_bit(__I40E_VSI_DOWN_REQUESTED, vsi->state);
                break;
        }
 
@@ -6657,6 +6659,9 @@ static int i40e_configure_queue_channels(struct i40e_vsi *vsi)
                        vsi->tc_seid_map[i] = ch->seid;
                }
        }
+
+       /* reset to reconfigure TX queue contexts */
+       i40e_do_reset(vsi->back, I40E_PF_RESET_FLAG, true);
        return ret;
 
 err_free:
index f6ba97a..69e67eb 100644 (file)
@@ -3203,11 +3203,13 @@ static int i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags,
 
        protocol = vlan_get_protocol(skb);
 
-       if (eth_p_mpls(protocol))
+       if (eth_p_mpls(protocol)) {
                ip.hdr = skb_inner_network_header(skb);
-       else
+               l4.hdr = skb_checksum_start(skb);
+       } else {
                ip.hdr = skb_network_header(skb);
-       l4.hdr = skb_checksum_start(skb);
+               l4.hdr = skb_transport_header(skb);
+       }
 
        /* set the tx_flags to indicate the IP protocol type. this is
         * required so that checksum header computation below is accurate.
@@ -3686,7 +3688,8 @@ u16 i40e_lan_select_queue(struct net_device *netdev,
        u8 prio;
 
        /* is DCB enabled at all? */
-       if (vsi->tc_config.numtc == 1)
+       if (vsi->tc_config.numtc == 1 ||
+           i40e_is_tc_mqprio_enabled(vsi->back))
                return netdev_pick_tx(netdev, skb, sb_dev);
 
        prio = skb->priority;
index cd4e6a2..9ffbd24 100644 (file)
@@ -324,6 +324,7 @@ static enum iavf_status iavf_config_arq_regs(struct iavf_hw *hw)
 static enum iavf_status iavf_init_asq(struct iavf_hw *hw)
 {
        enum iavf_status ret_code = 0;
+       int i;
 
        if (hw->aq.asq.count > 0) {
                /* queue already initialized */
@@ -354,12 +355,17 @@ static enum iavf_status iavf_init_asq(struct iavf_hw *hw)
        /* initialize base registers */
        ret_code = iavf_config_asq_regs(hw);
        if (ret_code)
-               goto init_adminq_free_rings;
+               goto init_free_asq_bufs;
 
        /* success! */
        hw->aq.asq.count = hw->aq.num_asq_entries;
        goto init_adminq_exit;
 
+init_free_asq_bufs:
+       for (i = 0; i < hw->aq.num_asq_entries; i++)
+               iavf_free_dma_mem(hw, &hw->aq.asq.r.asq_bi[i]);
+       iavf_free_virt_mem(hw, &hw->aq.asq.dma_head);
+
 init_adminq_free_rings:
        iavf_free_adminq_asq(hw);
 
@@ -383,6 +389,7 @@ init_adminq_exit:
 static enum iavf_status iavf_init_arq(struct iavf_hw *hw)
 {
        enum iavf_status ret_code = 0;
+       int i;
 
        if (hw->aq.arq.count > 0) {
                /* queue already initialized */
@@ -413,12 +420,16 @@ static enum iavf_status iavf_init_arq(struct iavf_hw *hw)
        /* initialize base registers */
        ret_code = iavf_config_arq_regs(hw);
        if (ret_code)
-               goto init_adminq_free_rings;
+               goto init_free_arq_bufs;
 
        /* success! */
        hw->aq.arq.count = hw->aq.num_arq_entries;
        goto init_adminq_exit;
 
+init_free_arq_bufs:
+       for (i = 0; i < hw->aq.num_arq_entries; i++)
+               iavf_free_dma_mem(hw, &hw->aq.arq.r.arq_bi[i]);
+       iavf_free_virt_mem(hw, &hw->aq.arq.dma_head);
 init_adminq_free_rings:
        iavf_free_adminq_arq(hw);
 
index 45d097a..10aa99d 100644 (file)
@@ -2367,7 +2367,7 @@ static void iavf_init_get_resources(struct iavf_adapter *adapter)
        err = iavf_get_vf_config(adapter);
        if (err == -EALREADY) {
                err = iavf_send_vf_config_msg(adapter);
-               goto err_alloc;
+               goto err;
        } else if (err == -EINVAL) {
                /* We only get -EINVAL if the device is in a very bad
                 * state or if we've been disabled for previous bad
@@ -2877,6 +2877,11 @@ static void iavf_reset_task(struct work_struct *work)
        int i = 0, err;
        bool running;
 
+       /* Detach interface to avoid subsequent NDO callbacks */
+       rtnl_lock();
+       netif_device_detach(netdev);
+       rtnl_unlock();
+
        /* When device is being removed it doesn't make sense to run the reset
         * task, just return in such a case.
         */
@@ -2884,7 +2889,7 @@ static void iavf_reset_task(struct work_struct *work)
                if (adapter->state != __IAVF_REMOVE)
                        queue_work(iavf_wq, &adapter->reset_task);
 
-               return;
+               goto reset_finish;
        }
 
        while (!mutex_trylock(&adapter->client_lock))
@@ -2954,7 +2959,6 @@ continue_reset:
 
        if (running) {
                netif_carrier_off(netdev);
-               netif_tx_stop_all_queues(netdev);
                adapter->link_up = false;
                iavf_napi_disable_all(adapter);
        }
@@ -3084,14 +3088,21 @@ continue_reset:
        mutex_unlock(&adapter->client_lock);
        mutex_unlock(&adapter->crit_lock);
 
-       return;
+       goto reset_finish;
 reset_err:
+       if (running) {
+               set_bit(__IAVF_VSI_DOWN, adapter->vsi.state);
+               iavf_free_traffic_irqs(adapter);
+       }
+       iavf_disable_vf(adapter);
+
        mutex_unlock(&adapter->client_lock);
        mutex_unlock(&adapter->crit_lock);
-       if (running)
-               iavf_change_state(adapter, __IAVF_RUNNING);
        dev_err(&adapter->pdev->dev, "failed to allocate resources during reinit\n");
-       iavf_close(netdev);
+reset_finish:
+       rtnl_lock();
+       netif_device_attach(netdev);
+       rtnl_unlock();
 }
 
 /**
@@ -4085,8 +4096,17 @@ static int iavf_open(struct net_device *netdev)
                return -EIO;
        }
 
-       while (!mutex_trylock(&adapter->crit_lock))
+       while (!mutex_trylock(&adapter->crit_lock)) {
+               /* If we are in __IAVF_INIT_CONFIG_ADAPTER state the crit_lock
+                * is already taken and iavf_open is called from an upper
+                * device's notifier reacting on NETDEV_REGISTER event.
+                * We have to leave here to avoid dead lock.
+                */
+               if (adapter->state == __IAVF_INIT_CONFIG_ADAPTER)
+                       return -EBUSY;
+
                usleep_range(500, 1000);
+       }
 
        if (adapter->state != __IAVF_DOWN) {
                err = -EBUSY;
index cc5b85a..841fa14 100644 (file)
@@ -684,8 +684,8 @@ static inline void ice_set_ring_xdp(struct ice_tx_ring *ring)
  * ice_xsk_pool - get XSK buffer pool bound to a ring
  * @ring: Rx ring to use
  *
- * Returns a pointer to xdp_umem structure if there is a buffer pool present,
- * NULL otherwise.
+ * Returns a pointer to xsk_buff_pool structure if there is a buffer pool
+ * present, NULL otherwise.
  */
 static inline struct xsk_buff_pool *ice_xsk_pool(struct ice_rx_ring *ring)
 {
@@ -699,23 +699,33 @@ static inline struct xsk_buff_pool *ice_xsk_pool(struct ice_rx_ring *ring)
 }
 
 /**
- * ice_tx_xsk_pool - get XSK buffer pool bound to a ring
- * @ring: Tx ring to use
+ * ice_tx_xsk_pool - assign XSK buff pool to XDP ring
+ * @vsi: pointer to VSI
+ * @qid: index of a queue to look at XSK buff pool presence
  *
- * Returns a pointer to xdp_umem structure if there is a buffer pool present,
- * NULL otherwise. Tx equivalent of ice_xsk_pool.
+ * Sets XSK buff pool pointer on XDP ring.
+ *
+ * XDP ring is picked from Rx ring, whereas Rx ring is picked based on provided
+ * queue id. Reason for doing so is that queue vectors might have assigned more
+ * than one XDP ring, e.g. when user reduced the queue count on netdev; Rx ring
+ * carries a pointer to one of these XDP rings for its own purposes, such as
+ * handling XDP_TX action, therefore we can piggyback here on the
+ * rx_ring->xdp_ring assignment that was done during XDP rings initialization.
  */
-static inline struct xsk_buff_pool *ice_tx_xsk_pool(struct ice_tx_ring *ring)
+static inline void ice_tx_xsk_pool(struct ice_vsi *vsi, u16 qid)
 {
-       struct ice_vsi *vsi = ring->vsi;
-       u16 qid;
+       struct ice_tx_ring *ring;
 
-       qid = ring->q_index - vsi->alloc_txq;
+       ring = vsi->rx_rings[qid]->xdp_ring;
+       if (!ring)
+               return;
 
-       if (!ice_is_xdp_ena_vsi(vsi) || !test_bit(qid, vsi->af_xdp_zc_qps))
-               return NULL;
+       if (!ice_is_xdp_ena_vsi(vsi) || !test_bit(qid, vsi->af_xdp_zc_qps)) {
+               ring->xsk_pool = NULL;
+               return;
+       }
 
-       return xsk_get_pool_from_qid(vsi->netdev, qid);
+       ring->xsk_pool = xsk_get_pool_from_qid(vsi->netdev, qid);
 }
 
 /**
index 136d791..1e32438 100644 (file)
@@ -7,18 +7,6 @@
 #include "ice_dcb_lib.h"
 #include "ice_sriov.h"
 
-static bool ice_alloc_rx_buf_zc(struct ice_rx_ring *rx_ring)
-{
-       rx_ring->xdp_buf = kcalloc(rx_ring->count, sizeof(*rx_ring->xdp_buf), GFP_KERNEL);
-       return !!rx_ring->xdp_buf;
-}
-
-static bool ice_alloc_rx_buf(struct ice_rx_ring *rx_ring)
-{
-       rx_ring->rx_buf = kcalloc(rx_ring->count, sizeof(*rx_ring->rx_buf), GFP_KERNEL);
-       return !!rx_ring->rx_buf;
-}
-
 /**
  * __ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI
  * @qs_cfg: gathered variables needed for PF->VSI queues assignment
@@ -519,11 +507,8 @@ int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
                        xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
                                         ring->q_index, ring->q_vector->napi.napi_id);
 
-               kfree(ring->rx_buf);
                ring->xsk_pool = ice_xsk_pool(ring);
                if (ring->xsk_pool) {
-                       if (!ice_alloc_rx_buf_zc(ring))
-                               return -ENOMEM;
                        xdp_rxq_info_unreg_mem_model(&ring->xdp_rxq);
 
                        ring->rx_buf_len =
@@ -538,8 +523,6 @@ int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
                        dev_info(dev, "Registered XDP mem model MEM_TYPE_XSK_BUFF_POOL on Rx ring %d\n",
                                 ring->q_index);
                } else {
-                       if (!ice_alloc_rx_buf(ring))
-                               return -ENOMEM;
                        if (!xdp_rxq_info_is_reg(&ring->xdp_rxq))
                                /* coverity[check_return] */
                                xdp_rxq_info_reg(&ring->xdp_rxq,
index 85a9448..40e678c 100644 (file)
@@ -62,7 +62,7 @@ ice_fltr_set_vlan_vsi_promisc(struct ice_hw *hw, struct ice_vsi *vsi,
        int result;
 
        result = ice_set_vlan_vsi_promisc(hw, vsi->idx, promisc_mask, false);
-       if (result)
+       if (result && result != -EEXIST)
                dev_err(ice_pf_to_dev(pf),
                        "Error setting promisc mode on VSI %i (rc=%d)\n",
                        vsi->vsi_num, result);
@@ -86,7 +86,7 @@ ice_fltr_clear_vlan_vsi_promisc(struct ice_hw *hw, struct ice_vsi *vsi,
        int result;
 
        result = ice_set_vlan_vsi_promisc(hw, vsi->idx, promisc_mask, true);
-       if (result)
+       if (result && result != -EEXIST)
                dev_err(ice_pf_to_dev(pf),
                        "Error clearing promisc mode on VSI %i (rc=%d)\n",
                        vsi->vsi_num, result);
@@ -109,7 +109,7 @@ ice_fltr_clear_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask,
        int result;
 
        result = ice_clear_vsi_promisc(hw, vsi_handle, promisc_mask, vid);
-       if (result)
+       if (result && result != -EEXIST)
                dev_err(ice_pf_to_dev(pf),
                        "Error clearing promisc mode on VSI %i for VID %u (rc=%d)\n",
                        ice_get_hw_vsi_num(hw, vsi_handle), vid, result);
@@ -132,7 +132,7 @@ ice_fltr_set_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask,
        int result;
 
        result = ice_set_vsi_promisc(hw, vsi_handle, promisc_mask, vid);
-       if (result)
+       if (result && result != -EEXIST)
                dev_err(ice_pf_to_dev(pf),
                        "Error setting promisc mode on VSI %i for VID %u (rc=%d)\n",
                        ice_get_hw_vsi_num(hw, vsi_handle), vid, result);
index a830f7f..0c4ec92 100644 (file)
@@ -1986,8 +1986,8 @@ int ice_vsi_cfg_xdp_txqs(struct ice_vsi *vsi)
        if (ret)
                return ret;
 
-       ice_for_each_xdp_txq(vsi, i)
-               vsi->xdp_rings[i]->xsk_pool = ice_tx_xsk_pool(vsi->xdp_rings[i]);
+       ice_for_each_rxq(vsi, i)
+               ice_tx_xsk_pool(vsi, i);
 
        return ret;
 }
@@ -3181,7 +3181,7 @@ int ice_vsi_rebuild(struct ice_vsi *vsi, bool init_vsi)
 
        pf = vsi->back;
        vtype = vsi->type;
-       if (WARN_ON(vtype == ICE_VSI_VF) && !vsi->vf)
+       if (WARN_ON(vtype == ICE_VSI_VF && !vsi->vf))
                return -EINVAL;
 
        ice_vsi_init_vlan_ops(vsi);
@@ -4062,7 +4062,11 @@ int ice_vsi_del_vlan_zero(struct ice_vsi *vsi)
        if (err && err != -EEXIST)
                return err;
 
-       return 0;
+       /* when deleting the last VLAN filter, make sure to disable the VLAN
+        * promisc mode so the filter isn't left by accident
+        */
+       return ice_clear_vsi_promisc(&vsi->back->hw, vsi->idx,
+                                   ICE_MCAST_VLAN_PROMISC_BITS, 0);
 }
 
 /**
index eb40526..8c30eea 100644 (file)
@@ -267,8 +267,10 @@ static int ice_set_promisc(struct ice_vsi *vsi, u8 promisc_m)
                status = ice_fltr_set_vsi_promisc(&vsi->back->hw, vsi->idx,
                                                  promisc_m, 0);
        }
+       if (status && status != -EEXIST)
+               return status;
 
-       return status;
+       return 0;
 }
 
 /**
@@ -2579,7 +2581,6 @@ static int ice_xdp_alloc_setup_rings(struct ice_vsi *vsi)
                if (ice_setup_tx_ring(xdp_ring))
                        goto free_xdp_rings;
                ice_set_ring_xdp(xdp_ring);
-               xdp_ring->xsk_pool = ice_tx_xsk_pool(xdp_ring);
                spin_lock_init(&xdp_ring->tx_lock);
                for (j = 0; j < xdp_ring->count; j++) {
                        tx_desc = ICE_TX_DESC(xdp_ring, j);
@@ -2587,13 +2588,6 @@ static int ice_xdp_alloc_setup_rings(struct ice_vsi *vsi)
                }
        }
 
-       ice_for_each_rxq(vsi, i) {
-               if (static_key_enabled(&ice_xdp_locking_key))
-                       vsi->rx_rings[i]->xdp_ring = vsi->xdp_rings[i % vsi->num_xdp_txq];
-               else
-                       vsi->rx_rings[i]->xdp_ring = vsi->xdp_rings[i];
-       }
-
        return 0;
 
 free_xdp_rings:
@@ -2683,6 +2677,23 @@ int ice_prepare_xdp_rings(struct ice_vsi *vsi, struct bpf_prog *prog)
                xdp_rings_rem -= xdp_rings_per_v;
        }
 
+       ice_for_each_rxq(vsi, i) {
+               if (static_key_enabled(&ice_xdp_locking_key)) {
+                       vsi->rx_rings[i]->xdp_ring = vsi->xdp_rings[i % vsi->num_xdp_txq];
+               } else {
+                       struct ice_q_vector *q_vector = vsi->rx_rings[i]->q_vector;
+                       struct ice_tx_ring *ring;
+
+                       ice_for_each_tx_ring(ring, q_vector->tx) {
+                               if (ice_ring_is_xdp(ring)) {
+                                       vsi->rx_rings[i]->xdp_ring = ring;
+                                       break;
+                               }
+                       }
+               }
+               ice_tx_xsk_pool(vsi, i);
+       }
+
        /* omit the scheduler update if in reset path; XDP queues will be
         * taken into account at the end of ice_vsi_rebuild, where
         * ice_cfg_vsi_lan is being called
@@ -2887,10 +2898,18 @@ ice_xdp_setup_prog(struct ice_vsi *vsi, struct bpf_prog *prog,
                        if (xdp_ring_err)
                                NL_SET_ERR_MSG_MOD(extack, "Setting up XDP Tx resources failed");
                }
+               /* reallocate Rx queues that are used for zero-copy */
+               xdp_ring_err = ice_realloc_zc_buf(vsi, true);
+               if (xdp_ring_err)
+                       NL_SET_ERR_MSG_MOD(extack, "Setting up XDP Rx resources failed");
        } else if (ice_is_xdp_ena_vsi(vsi) && !prog) {
                xdp_ring_err = ice_destroy_xdp_rings(vsi);
                if (xdp_ring_err)
                        NL_SET_ERR_MSG_MOD(extack, "Freeing XDP Tx resources failed");
+               /* reallocate Rx queues that were used for zero-copy */
+               xdp_ring_err = ice_realloc_zc_buf(vsi, false);
+               if (xdp_ring_err)
+                       NL_SET_ERR_MSG_MOD(extack, "Freeing XDP Rx resources failed");
        } else {
                /* safe to call even when prog == vsi->xdp_prog as
                 * dev_xdp_install in net/core/dev.c incremented prog's
@@ -3573,6 +3592,14 @@ ice_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid)
        while (test_and_set_bit(ICE_CFG_BUSY, vsi->state))
                usleep_range(1000, 2000);
 
+       ret = ice_clear_vsi_promisc(&vsi->back->hw, vsi->idx,
+                                   ICE_MCAST_VLAN_PROMISC_BITS, vid);
+       if (ret) {
+               netdev_err(netdev, "Error clearing multicast promiscuous mode on VSI %i\n",
+                          vsi->vsi_num);
+               vsi->current_netdev_flags |= IFF_ALLMULTI;
+       }
+
        vlan_ops = ice_get_compat_vsi_vlan_ops(vsi);
 
        /* Make sure VLAN delete is successful before updating VLAN
@@ -3886,7 +3913,7 @@ static int ice_init_pf(struct ice_pf *pf)
 
        pf->avail_rxqs = bitmap_zalloc(pf->max_pf_rxqs, GFP_KERNEL);
        if (!pf->avail_rxqs) {
-               devm_kfree(ice_pf_to_dev(pf), pf->avail_txqs);
+               bitmap_free(pf->avail_txqs);
                pf->avail_txqs = NULL;
                return -ENOMEM;
        }
index 262e553..3808034 100644 (file)
@@ -4445,6 +4445,13 @@ ice_set_vlan_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask,
                goto free_fltr_list;
 
        list_for_each_entry(list_itr, &vsi_list_head, list_entry) {
+               /* Avoid enabling or disabling VLAN zero twice when in double
+                * VLAN mode
+                */
+               if (ice_is_dvm_ena(hw) &&
+                   list_itr->fltr_info.l_data.vlan.tpid == 0)
+                       continue;
+
                vlan_id = list_itr->fltr_info.l_data.vlan.vlan_id;
                if (rm_vlan_promisc)
                        status = ice_clear_vsi_promisc(hw, vsi_handle,
@@ -4452,7 +4459,7 @@ ice_set_vlan_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask,
                else
                        status = ice_set_vsi_promisc(hw, vsi_handle,
                                                     promisc_mask, vlan_id);
-               if (status)
+               if (status && status != -EEXIST)
                        break;
        }
 
index 8fd7c3e..0abeed0 100644 (file)
@@ -571,8 +571,10 @@ int ice_reset_vf(struct ice_vf *vf, u32 flags)
 
        if (ice_is_vf_disabled(vf)) {
                vsi = ice_get_vf_vsi(vf);
-               if (WARN_ON(!vsi))
+               if (!vsi) {
+                       dev_dbg(dev, "VF is already removed\n");
                        return -EINVAL;
+               }
                ice_vsi_stop_lan_tx_rings(vsi, ICE_NO_RESET, vf->vf_id);
                ice_vsi_stop_all_rx_rings(vsi);
                dev_dbg(dev, "VF is already disabled, there is no need for resetting it, telling VM, all is fine %d\n",
@@ -762,13 +764,16 @@ static int ice_cfg_mac_antispoof(struct ice_vsi *vsi, bool enable)
 static int ice_vsi_ena_spoofchk(struct ice_vsi *vsi)
 {
        struct ice_vsi_vlan_ops *vlan_ops;
-       int err;
+       int err = 0;
 
        vlan_ops = ice_get_compat_vsi_vlan_ops(vsi);
 
-       err = vlan_ops->ena_tx_filtering(vsi);
-       if (err)
-               return err;
+       /* Allow VF with VLAN 0 only to send all tagged traffic */
+       if (vsi->type != ICE_VSI_VF || ice_vsi_has_non_zero_vlans(vsi)) {
+               err = vlan_ops->ena_tx_filtering(vsi);
+               if (err)
+                       return err;
+       }
 
        return ice_cfg_mac_antispoof(vsi, true);
 }
index 094e3c9..2b4c791 100644 (file)
@@ -2288,6 +2288,15 @@ static int ice_vc_process_vlan_msg(struct ice_vf *vf, u8 *msg, bool add_v)
 
                        /* Enable VLAN filtering on first non-zero VLAN */
                        if (!vlan_promisc && vid && !ice_is_dvm_ena(&pf->hw)) {
+                               if (vf->spoofchk) {
+                                       status = vsi->inner_vlan_ops.ena_tx_filtering(vsi);
+                                       if (status) {
+                                               v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+                                               dev_err(dev, "Enable VLAN anti-spoofing on VLAN ID: %d failed error-%d\n",
+                                                       vid, status);
+                                               goto error_param;
+                                       }
+                               }
                                if (vsi->inner_vlan_ops.ena_rx_filtering(vsi)) {
                                        v_ret = VIRTCHNL_STATUS_ERR_PARAM;
                                        dev_err(dev, "Enable VLAN pruning on VLAN ID: %d failed error-%d\n",
@@ -2333,8 +2342,10 @@ static int ice_vc_process_vlan_msg(struct ice_vf *vf, u8 *msg, bool add_v)
                        }
 
                        /* Disable VLAN filtering when only VLAN 0 is left */
-                       if (!ice_vsi_has_non_zero_vlans(vsi))
+                       if (!ice_vsi_has_non_zero_vlans(vsi)) {
+                               vsi->inner_vlan_ops.dis_tx_filtering(vsi);
                                vsi->inner_vlan_ops.dis_rx_filtering(vsi);
+                       }
 
                        if (vlan_promisc)
                                ice_vf_dis_vlan_promisc(vsi, &vlan);
@@ -2838,6 +2849,13 @@ ice_vc_del_vlans(struct ice_vf *vf, struct ice_vsi *vsi,
 
                        if (vlan_promisc)
                                ice_vf_dis_vlan_promisc(vsi, &vlan);
+
+                       /* Disable VLAN filtering when only VLAN 0 is left */
+                       if (!ice_vsi_has_non_zero_vlans(vsi) && ice_is_dvm_ena(&vsi->back->hw)) {
+                               err = vsi->outer_vlan_ops.dis_tx_filtering(vsi);
+                               if (err)
+                                       return err;
+                       }
                }
 
                vc_vlan = &vlan_fltr->inner;
@@ -2853,8 +2871,17 @@ ice_vc_del_vlans(struct ice_vf *vf, struct ice_vsi *vsi,
                        /* no support for VLAN promiscuous on inner VLAN unless
                         * we are in Single VLAN Mode (SVM)
                         */
-                       if (!ice_is_dvm_ena(&vsi->back->hw) && vlan_promisc)
-                               ice_vf_dis_vlan_promisc(vsi, &vlan);
+                       if (!ice_is_dvm_ena(&vsi->back->hw)) {
+                               if (vlan_promisc)
+                                       ice_vf_dis_vlan_promisc(vsi, &vlan);
+
+                               /* Disable VLAN filtering when only VLAN 0 is left */
+                               if (!ice_vsi_has_non_zero_vlans(vsi)) {
+                                       err = vsi->inner_vlan_ops.dis_tx_filtering(vsi);
+                                       if (err)
+                                               return err;
+                               }
+                       }
                }
        }
 
@@ -2931,6 +2958,13 @@ ice_vc_add_vlans(struct ice_vf *vf, struct ice_vsi *vsi,
                                if (err)
                                        return err;
                        }
+
+                       /* Enable VLAN filtering on first non-zero VLAN */
+                       if (vf->spoofchk && vlan.vid && ice_is_dvm_ena(&vsi->back->hw)) {
+                               err = vsi->outer_vlan_ops.ena_tx_filtering(vsi);
+                               if (err)
+                                       return err;
+                       }
                }
 
                vc_vlan = &vlan_fltr->inner;
@@ -2946,10 +2980,19 @@ ice_vc_add_vlans(struct ice_vf *vf, struct ice_vsi *vsi,
                        /* no support for VLAN promiscuous on inner VLAN unless
                         * we are in Single VLAN Mode (SVM)
                         */
-                       if (!ice_is_dvm_ena(&vsi->back->hw) && vlan_promisc) {
-                               err = ice_vf_ena_vlan_promisc(vsi, &vlan);
-                               if (err)
-                                       return err;
+                       if (!ice_is_dvm_ena(&vsi->back->hw)) {
+                               if (vlan_promisc) {
+                                       err = ice_vf_ena_vlan_promisc(vsi, &vlan);
+                                       if (err)
+                                               return err;
+                               }
+
+                               /* Enable VLAN filtering on first non-zero VLAN */
+                               if (vf->spoofchk && vlan.vid) {
+                                       err = vsi->inner_vlan_ops.ena_tx_filtering(vsi);
+                                       if (err)
+                                               return err;
+                               }
                        }
                }
        }
index 49ba8bf..03ce85f 100644 (file)
@@ -192,6 +192,7 @@ static int ice_qp_dis(struct ice_vsi *vsi, u16 q_idx)
        err = ice_vsi_ctrl_one_rx_ring(vsi, false, q_idx, true);
        if (err)
                return err;
+       ice_clean_rx_ring(rx_ring);
 
        ice_qvec_toggle_napi(vsi, q_vector, false);
        ice_qp_clean_rings(vsi, q_idx);
@@ -243,7 +244,7 @@ static int ice_qp_ena(struct ice_vsi *vsi, u16 q_idx)
                if (err)
                        goto free_buf;
                ice_set_ring_xdp(xdp_ring);
-               xdp_ring->xsk_pool = ice_tx_xsk_pool(xdp_ring);
+               ice_tx_xsk_pool(vsi, q_idx);
        }
 
        err = ice_vsi_cfg_rxq(rx_ring);
@@ -317,6 +318,62 @@ ice_xsk_pool_enable(struct ice_vsi *vsi, struct xsk_buff_pool *pool, u16 qid)
 }
 
 /**
+ * ice_realloc_rx_xdp_bufs - reallocate for either XSK or normal buffer
+ * @rx_ring: Rx ring
+ * @pool_present: is pool for XSK present
+ *
+ * Try allocating memory and return ENOMEM, if failed to allocate.
+ * If allocation was successful, substitute buffer with allocated one.
+ * Returns 0 on success, negative on failure
+ */
+static int
+ice_realloc_rx_xdp_bufs(struct ice_rx_ring *rx_ring, bool pool_present)
+{
+       size_t elem_size = pool_present ? sizeof(*rx_ring->xdp_buf) :
+                                         sizeof(*rx_ring->rx_buf);
+       void *sw_ring = kcalloc(rx_ring->count, elem_size, GFP_KERNEL);
+
+       if (!sw_ring)
+               return -ENOMEM;
+
+       if (pool_present) {
+               kfree(rx_ring->rx_buf);
+               rx_ring->rx_buf = NULL;
+               rx_ring->xdp_buf = sw_ring;
+       } else {
+               kfree(rx_ring->xdp_buf);
+               rx_ring->xdp_buf = NULL;
+               rx_ring->rx_buf = sw_ring;
+       }
+
+       return 0;
+}
+
+/**
+ * ice_realloc_zc_buf - reallocate XDP ZC queue pairs
+ * @vsi: Current VSI
+ * @zc: is zero copy set
+ *
+ * Reallocate buffer for rx_rings that might be used by XSK.
+ * XDP requires more memory, than rx_buf provides.
+ * Returns 0 on success, negative on failure
+ */
+int ice_realloc_zc_buf(struct ice_vsi *vsi, bool zc)
+{
+       struct ice_rx_ring *rx_ring;
+       unsigned long q;
+
+       for_each_set_bit(q, vsi->af_xdp_zc_qps,
+                        max_t(int, vsi->alloc_txq, vsi->alloc_rxq)) {
+               rx_ring = vsi->rx_rings[q];
+               if (ice_realloc_rx_xdp_bufs(rx_ring, zc))
+                       return -ENOMEM;
+       }
+
+       return 0;
+}
+
+/**
  * ice_xsk_pool_setup - enable/disable a buffer pool region depending on its state
  * @vsi: Current VSI
  * @pool: buffer pool to enable/associate to a ring, NULL to disable
@@ -329,6 +386,12 @@ int ice_xsk_pool_setup(struct ice_vsi *vsi, struct xsk_buff_pool *pool, u16 qid)
        bool if_running, pool_present = !!pool;
        int ret = 0, pool_failure = 0;
 
+       if (qid >= vsi->num_rxq || qid >= vsi->num_txq) {
+               netdev_err(vsi->netdev, "Please use queue id in scope of combined queues count\n");
+               pool_failure = -EINVAL;
+               goto failure;
+       }
+
        if (!is_power_of_2(vsi->rx_rings[qid]->count) ||
            !is_power_of_2(vsi->tx_rings[qid]->count)) {
                netdev_err(vsi->netdev, "Please align ring sizes to power of 2\n");
@@ -339,11 +402,17 @@ int ice_xsk_pool_setup(struct ice_vsi *vsi, struct xsk_buff_pool *pool, u16 qid)
        if_running = netif_running(vsi->netdev) && ice_is_xdp_ena_vsi(vsi);
 
        if (if_running) {
+               struct ice_rx_ring *rx_ring = vsi->rx_rings[qid];
+
                ret = ice_qp_dis(vsi, qid);
                if (ret) {
                        netdev_err(vsi->netdev, "ice_qp_dis error = %d\n", ret);
                        goto xsk_pool_if_up;
                }
+
+               ret = ice_realloc_rx_xdp_bufs(rx_ring, pool_present);
+               if (ret)
+                       goto xsk_pool_if_up;
        }
 
        pool_failure = pool_present ? ice_xsk_pool_enable(vsi, pool, qid) :
@@ -353,7 +422,7 @@ xsk_pool_if_up:
        if (if_running) {
                ret = ice_qp_ena(vsi, qid);
                if (!ret && pool_present)
-                       napi_schedule(&vsi->xdp_rings[qid]->q_vector->napi);
+                       napi_schedule(&vsi->rx_rings[qid]->xdp_ring->q_vector->napi);
                else if (ret)
                        netdev_err(vsi->netdev, "ice_qp_ena error = %d\n", ret);
        }
@@ -944,13 +1013,13 @@ ice_xsk_wakeup(struct net_device *netdev, u32 queue_id,
        if (!ice_is_xdp_ena_vsi(vsi))
                return -EINVAL;
 
-       if (queue_id >= vsi->num_txq)
+       if (queue_id >= vsi->num_txq || queue_id >= vsi->num_rxq)
                return -EINVAL;
 
-       if (!vsi->xdp_rings[queue_id]->xsk_pool)
-               return -EINVAL;
+       ring = vsi->rx_rings[queue_id]->xdp_ring;
 
-       ring = vsi->xdp_rings[queue_id];
+       if (!ring->xsk_pool)
+               return -EINVAL;
 
        /* The idea here is that if NAPI is running, mark a miss, so
         * it will run again. If not, trigger an interrupt and
index 21faec8..4edbe81 100644 (file)
@@ -27,6 +27,7 @@ bool ice_xsk_any_rx_ring_ena(struct ice_vsi *vsi);
 void ice_xsk_clean_rx_ring(struct ice_rx_ring *rx_ring);
 void ice_xsk_clean_xdp_ring(struct ice_tx_ring *xdp_ring);
 bool ice_xmit_zc(struct ice_tx_ring *xdp_ring, u32 budget, int napi_budget);
+int ice_realloc_zc_buf(struct ice_vsi *vsi, bool zc);
 #else
 static inline bool
 ice_xmit_zc(struct ice_tx_ring __always_unused *xdp_ring,
@@ -72,5 +73,12 @@ ice_xsk_wakeup(struct net_device __always_unused *netdev,
 
 static inline void ice_xsk_clean_rx_ring(struct ice_rx_ring *rx_ring) { }
 static inline void ice_xsk_clean_xdp_ring(struct ice_tx_ring *xdp_ring) { }
+
+static inline int
+ice_realloc_zc_buf(struct ice_vsi __always_unused *vsi,
+                  bool __always_unused zc)
+{
+       return 0;
+}
 #endif /* CONFIG_XDP_SOCKETS */
 #endif /* !_ICE_XSK_H_ */
index 2d3daf0..015b781 100644 (file)
@@ -664,6 +664,8 @@ struct igb_adapter {
        struct igb_mac_addr *mac_table;
        struct vf_mac_filter vf_macs;
        struct vf_mac_filter *vf_mac_list;
+       /* lock for VF resources */
+       spinlock_t vfs_lock;
 };
 
 /* flags controlling PTP/1588 function */
index d8b836a..2796e81 100644 (file)
@@ -3637,6 +3637,7 @@ static int igb_disable_sriov(struct pci_dev *pdev)
        struct net_device *netdev = pci_get_drvdata(pdev);
        struct igb_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
+       unsigned long flags;
 
        /* reclaim resources allocated to VFs */
        if (adapter->vf_data) {
@@ -3649,12 +3650,13 @@ static int igb_disable_sriov(struct pci_dev *pdev)
                        pci_disable_sriov(pdev);
                        msleep(500);
                }
-
+               spin_lock_irqsave(&adapter->vfs_lock, flags);
                kfree(adapter->vf_mac_list);
                adapter->vf_mac_list = NULL;
                kfree(adapter->vf_data);
                adapter->vf_data = NULL;
                adapter->vfs_allocated_count = 0;
+               spin_unlock_irqrestore(&adapter->vfs_lock, flags);
                wr32(E1000_IOVCTL, E1000_IOVCTL_REUSE_VFQ);
                wrfl();
                msleep(100);
@@ -3814,7 +3816,9 @@ static void igb_remove(struct pci_dev *pdev)
        igb_release_hw_control(adapter);
 
 #ifdef CONFIG_PCI_IOV
+       rtnl_lock();
        igb_disable_sriov(pdev);
+       rtnl_unlock();
 #endif
 
        unregister_netdev(netdev);
@@ -3974,6 +3978,9 @@ static int igb_sw_init(struct igb_adapter *adapter)
 
        spin_lock_init(&adapter->nfc_lock);
        spin_lock_init(&adapter->stats64_lock);
+
+       /* init spinlock to avoid concurrency of VF resources */
+       spin_lock_init(&adapter->vfs_lock);
 #ifdef CONFIG_PCI_IOV
        switch (hw->mac.type) {
        case e1000_82576:
@@ -7958,8 +7965,10 @@ unlock:
 static void igb_msg_task(struct igb_adapter *adapter)
 {
        struct e1000_hw *hw = &adapter->hw;
+       unsigned long flags;
        u32 vf;
 
+       spin_lock_irqsave(&adapter->vfs_lock, flags);
        for (vf = 0; vf < adapter->vfs_allocated_count; vf++) {
                /* process any reset requests */
                if (!igb_check_for_rst(hw, vf))
@@ -7973,6 +7982,7 @@ static void igb_msg_task(struct igb_adapter *adapter)
                if (!igb_check_for_ack(hw, vf))
                        igb_rcv_ack_from_vf(adapter, vf);
        }
+       spin_unlock_irqrestore(&adapter->vfs_lock, flags);
 }
 
 /**
index 9f06896..f8605f5 100644 (file)
@@ -1214,7 +1214,6 @@ void ixgbe_ptp_start_cyclecounter(struct ixgbe_adapter *adapter)
        struct cyclecounter cc;
        unsigned long flags;
        u32 incval = 0;
-       u32 tsauxc = 0;
        u32 fuse0 = 0;
 
        /* For some of the boards below this mask is technically incorrect.
@@ -1249,18 +1248,6 @@ void ixgbe_ptp_start_cyclecounter(struct ixgbe_adapter *adapter)
        case ixgbe_mac_x550em_a:
        case ixgbe_mac_X550:
                cc.read = ixgbe_ptp_read_X550;
-
-               /* enable SYSTIME counter */
-               IXGBE_WRITE_REG(hw, IXGBE_SYSTIMR, 0);
-               IXGBE_WRITE_REG(hw, IXGBE_SYSTIML, 0);
-               IXGBE_WRITE_REG(hw, IXGBE_SYSTIMH, 0);
-               tsauxc = IXGBE_READ_REG(hw, IXGBE_TSAUXC);
-               IXGBE_WRITE_REG(hw, IXGBE_TSAUXC,
-                               tsauxc & ~IXGBE_TSAUXC_DISABLE_SYSTIME);
-               IXGBE_WRITE_REG(hw, IXGBE_TSIM, IXGBE_TSIM_TXTS);
-               IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_TIMESYNC);
-
-               IXGBE_WRITE_FLUSH(hw);
                break;
        case ixgbe_mac_X540:
                cc.read = ixgbe_ptp_read_82599;
@@ -1293,6 +1280,50 @@ void ixgbe_ptp_start_cyclecounter(struct ixgbe_adapter *adapter)
 }
 
 /**
+ * ixgbe_ptp_init_systime - Initialize SYSTIME registers
+ * @adapter: the ixgbe private board structure
+ *
+ * Initialize and start the SYSTIME registers.
+ */
+static void ixgbe_ptp_init_systime(struct ixgbe_adapter *adapter)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       u32 tsauxc;
+
+       switch (hw->mac.type) {
+       case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
+       case ixgbe_mac_X550:
+               tsauxc = IXGBE_READ_REG(hw, IXGBE_TSAUXC);
+
+               /* Reset SYSTIME registers to 0 */
+               IXGBE_WRITE_REG(hw, IXGBE_SYSTIMR, 0);
+               IXGBE_WRITE_REG(hw, IXGBE_SYSTIML, 0);
+               IXGBE_WRITE_REG(hw, IXGBE_SYSTIMH, 0);
+
+               /* Reset interrupt settings */
+               IXGBE_WRITE_REG(hw, IXGBE_TSIM, IXGBE_TSIM_TXTS);
+               IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_TIMESYNC);
+
+               /* Activate the SYSTIME counter */
+               IXGBE_WRITE_REG(hw, IXGBE_TSAUXC,
+                               tsauxc & ~IXGBE_TSAUXC_DISABLE_SYSTIME);
+               break;
+       case ixgbe_mac_X540:
+       case ixgbe_mac_82599EB:
+               /* Reset SYSTIME registers to 0 */
+               IXGBE_WRITE_REG(hw, IXGBE_SYSTIML, 0);
+               IXGBE_WRITE_REG(hw, IXGBE_SYSTIMH, 0);
+               break;
+       default:
+               /* Other devices aren't supported */
+               return;
+       };
+
+       IXGBE_WRITE_FLUSH(hw);
+}
+
+/**
  * ixgbe_ptp_reset
  * @adapter: the ixgbe private board structure
  *
@@ -1318,6 +1349,8 @@ void ixgbe_ptp_reset(struct ixgbe_adapter *adapter)
 
        ixgbe_ptp_start_cyclecounter(adapter);
 
+       ixgbe_ptp_init_systime(adapter);
+
        spin_lock_irqsave(&adapter->tmreg_lock, flags);
        timecounter_init(&adapter->hw_tc, &adapter->hw_cc,
                         ktime_to_ns(ktime_get_real()));
index 5edb68a..57f27cc 100644 (file)
@@ -193,6 +193,7 @@ static int xrx200_alloc_buf(struct xrx200_chan *ch, void *(*alloc)(unsigned int
 
        ch->rx_buff[ch->dma.desc] = alloc(priv->rx_skb_size);
        if (!ch->rx_buff[ch->dma.desc]) {
+               ch->rx_buff[ch->dma.desc] = buf;
                ret = -ENOMEM;
                goto skip;
        }
@@ -239,6 +240,12 @@ static int xrx200_hw_receive(struct xrx200_chan *ch)
        }
 
        skb = build_skb(buf, priv->rx_skb_size);
+       if (!skb) {
+               skb_free_frag(buf);
+               net_dev->stats.rx_dropped++;
+               return -ENOMEM;
+       }
+
        skb_reserve(skb, NET_SKB_PAD);
        skb_put(skb, len);
 
@@ -288,7 +295,7 @@ static int xrx200_poll_rx(struct napi_struct *napi, int budget)
                        if (ret == XRX200_DMA_PACKET_IN_PROGRESS)
                                continue;
                        if (ret != XRX200_DMA_PACKET_COMPLETE)
-                               return ret;
+                               break;
                        rx++;
                } else {
                        break;
index 4a3baa7..0eec05d 100644 (file)
@@ -700,10 +700,10 @@ void mvpp2_dbgfs_cleanup(struct mvpp2 *priv)
 
 void mvpp2_dbgfs_init(struct mvpp2 *priv, const char *name)
 {
-       struct dentry *mvpp2_dir, *mvpp2_root;
+       static struct dentry *mvpp2_root;
+       struct dentry *mvpp2_dir;
        int ret, i;
 
-       mvpp2_root = debugfs_lookup(MVPP2_DRIVER_NAME, NULL);
        if (!mvpp2_root)
                mvpp2_root = debugfs_create_dir(MVPP2_DRIVER_NAME, NULL);
 
index d9426b0..5ace460 100644 (file)
@@ -1732,7 +1732,7 @@ static u32 mtk_xdp_run(struct mtk_eth *eth, struct mtk_rx_ring *ring,
        case XDP_TX: {
                struct xdp_frame *xdpf = xdp_convert_buff_to_frame(xdp);
 
-               if (mtk_xdp_submit_frame(eth, xdpf, dev, false)) {
+               if (!xdpf || mtk_xdp_submit_frame(eth, xdpf, dev, false)) {
                        count = &hw_stats->xdp_stats.rx_xdp_tx_errors;
                        act = XDP_DROP;
                        break;
@@ -1891,10 +1891,19 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
                skb->dev = netdev;
                bytes += skb->len;
 
-               if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
+               if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
+                       hash = trxd.rxd5 & MTK_RXD5_FOE_ENTRY;
+                       if (hash != MTK_RXD5_FOE_ENTRY)
+                               skb_set_hash(skb, jhash_1word(hash, 0),
+                                            PKT_HASH_TYPE_L4);
                        rxdcsum = &trxd.rxd3;
-               else
+               } else {
+                       hash = trxd.rxd4 & MTK_RXD4_FOE_ENTRY;
+                       if (hash != MTK_RXD4_FOE_ENTRY)
+                               skb_set_hash(skb, jhash_1word(hash, 0),
+                                            PKT_HASH_TYPE_L4);
                        rxdcsum = &trxd.rxd4;
+               }
 
                if (*rxdcsum & eth->soc->txrx.rx_dma_l4_valid)
                        skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -1902,16 +1911,9 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
                        skb_checksum_none_assert(skb);
                skb->protocol = eth_type_trans(skb, netdev);
 
-               hash = trxd.rxd4 & MTK_RXD4_FOE_ENTRY;
-               if (hash != MTK_RXD4_FOE_ENTRY) {
-                       hash = jhash_1word(hash, 0);
-                       skb_set_hash(skb, hash, PKT_HASH_TYPE_L4);
-               }
-
                reason = FIELD_GET(MTK_RXD4_PPE_CPU_REASON, trxd.rxd4);
                if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED)
-                       mtk_ppe_check_skb(eth->ppe, skb,
-                                         trxd.rxd4 & MTK_RXD4_FOE_ENTRY);
+                       mtk_ppe_check_skb(eth->ppe, skb, hash);
 
                if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) {
                        if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
index 7405c97..ecf85e9 100644 (file)
 #define RX_DMA_L4_VALID_PDMA   BIT(30)         /* when PDMA is used */
 #define RX_DMA_SPECIAL_TAG     BIT(22)
 
+/* PDMA descriptor rxd5 */
+#define MTK_RXD5_FOE_ENTRY     GENMASK(14, 0)
+#define MTK_RXD5_PPE_CPU_REASON        GENMASK(22, 18)
+#define MTK_RXD5_SRC_PORT      GENMASK(29, 26)
+
 #define RX_DMA_GET_SPORT(x)    (((x) >> 19) & 0xf)
 #define RX_DMA_GET_SPORT_V2(x) (((x) >> 26) & 0x7)
 
index dab8f3f..cfe804b 100644 (file)
@@ -412,7 +412,7 @@ __mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
        if (entry->hash != 0xffff) {
                ppe->foe_table[entry->hash].ib1 &= ~MTK_FOE_IB1_STATE;
                ppe->foe_table[entry->hash].ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE,
-                                                             MTK_FOE_STATE_BIND);
+                                                             MTK_FOE_STATE_UNBIND);
                dma_wmb();
        }
        entry->hash = 0xffff;
index 1f5cf1c..69ffce0 100644 (file)
@@ -293,6 +293,9 @@ mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash)
        if (!ppe)
                return;
 
+       if (hash > MTK_PPE_HASH_MASK)
+               return;
+
        now = (u16)jiffies;
        diff = now - ppe->foe_check_time[hash];
        if (diff < HZ / 10)
index 3752235..c8e5ca6 100644 (file)
@@ -79,6 +79,10 @@ tc_act_police_offload(struct mlx5e_priv *priv,
        struct mlx5e_flow_meter_handle *meter;
        int err = 0;
 
+       err = mlx5e_policer_validate(&fl_act->action, act, fl_act->extack);
+       if (err)
+               return err;
+
        err = fill_meter_params_from_act(act, &params);
        if (err)
                return err;
index 0aef695..3a1f76e 100644 (file)
@@ -246,7 +246,7 @@ static void mlx5e_tls_priv_tx_cleanup(struct mlx5e_ktls_offload_context_tx *priv
 static void mlx5e_tls_priv_tx_list_cleanup(struct mlx5_core_dev *mdev,
                                           struct list_head *list, int size)
 {
-       struct mlx5e_ktls_offload_context_tx *obj;
+       struct mlx5e_ktls_offload_context_tx *obj, *n;
        struct mlx5e_async_ctx *bulk_async;
        int i;
 
@@ -255,7 +255,7 @@ static void mlx5e_tls_priv_tx_list_cleanup(struct mlx5_core_dev *mdev,
                return;
 
        i = 0;
-       list_for_each_entry(obj, list, list_node) {
+       list_for_each_entry_safe(obj, n, list, list_node) {
                mlx5e_tls_priv_tx_cleanup(obj, &bulk_async[i]);
                i++;
        }
index e2a9b9b..e0ce5a2 100644 (file)
@@ -1395,10 +1395,11 @@ struct mlx5e_flow_steering *mlx5e_fs_init(const struct mlx5e_profile *profile,
        }
 
        return fs;
-err_free_fs:
-       kvfree(fs);
+
 err_free_vlan:
        mlx5e_fs_vlan_free(fs);
+err_free_fs:
+       kvfree(fs);
 err:
        return NULL;
 }
index d858667..02eb2f0 100644 (file)
@@ -3682,7 +3682,9 @@ static int set_feature_hw_tc(struct net_device *netdev, bool enable)
        int err = 0;
 
 #if IS_ENABLED(CONFIG_MLX5_CLS_ACT)
-       if (!enable && mlx5e_tc_num_filters(priv, MLX5_TC_FLAG(NIC_OFFLOAD))) {
+       int tc_flag = mlx5e_is_uplink_rep(priv) ? MLX5_TC_FLAG(ESW_OFFLOAD) :
+                                                 MLX5_TC_FLAG(NIC_OFFLOAD);
+       if (!enable && mlx5e_tc_num_filters(priv, tc_flag)) {
                netdev_err(netdev,
                           "Active offloaded tc filters, can't turn hw_tc_offload off\n");
                return -EINVAL;
@@ -4769,14 +4771,6 @@ void mlx5e_build_nic_params(struct mlx5e_priv *priv, struct mlx5e_xsk *xsk, u16
        /* RQ */
        mlx5e_build_rq_params(mdev, params);
 
-       /* HW LRO */
-       if (MLX5_CAP_ETH(mdev, lro_cap) &&
-           params->rq_wq_type == MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ) {
-               /* No XSK params: checking the availability of striding RQ in general. */
-               if (!mlx5e_rx_mpwqe_is_linear_skb(mdev, params, NULL))
-                       params->packet_merge.type = slow_pci_heuristic(mdev) ?
-                               MLX5E_PACKET_MERGE_NONE : MLX5E_PACKET_MERGE_LRO;
-       }
        params->packet_merge.timeout = mlx5e_choose_lro_timeout(mdev, MLX5E_DEFAULT_LRO_TIMEOUT);
 
        /* CQ moderation params */
index 4c1599d..759f7d3 100644 (file)
@@ -662,6 +662,8 @@ static void mlx5e_build_rep_params(struct net_device *netdev)
 
        params->mqprio.num_tc       = 1;
        params->tunneled_offload_en = false;
+       if (rep->vport != MLX5_VPORT_UPLINK)
+               params->vlan_strip_disable = true;
 
        mlx5_query_min_inline(mdev, &params->tx_min_inline_mode);
 }
@@ -696,6 +698,13 @@ static int mlx5e_init_rep(struct mlx5_core_dev *mdev,
 {
        struct mlx5e_priv *priv = netdev_priv(netdev);
 
+       priv->fs = mlx5e_fs_init(priv->profile, mdev,
+                                !test_bit(MLX5E_STATE_DESTROYING, &priv->state));
+       if (!priv->fs) {
+               netdev_err(priv->netdev, "FS allocation failed\n");
+               return -ENOMEM;
+       }
+
        mlx5e_build_rep_params(netdev);
        mlx5e_timestamp_init(priv);
 
@@ -708,12 +717,21 @@ static int mlx5e_init_ul_rep(struct mlx5_core_dev *mdev,
        struct mlx5e_priv *priv = netdev_priv(netdev);
        int err;
 
+       priv->fs = mlx5e_fs_init(priv->profile, mdev,
+                                !test_bit(MLX5E_STATE_DESTROYING, &priv->state));
+       if (!priv->fs) {
+               netdev_err(priv->netdev, "FS allocation failed\n");
+               return -ENOMEM;
+       }
+
        err = mlx5e_ipsec_init(priv);
        if (err)
                mlx5_core_err(mdev, "Uplink rep IPsec initialization failed, %d\n", err);
 
        mlx5e_vxlan_set_netdev_info(priv);
-       return mlx5e_init_rep(mdev, netdev);
+       mlx5e_build_rep_params(netdev);
+       mlx5e_timestamp_init(priv);
+       return 0;
 }
 
 static void mlx5e_cleanup_rep(struct mlx5e_priv *priv)
@@ -836,13 +854,6 @@ static int mlx5e_init_rep_rx(struct mlx5e_priv *priv)
        struct mlx5_core_dev *mdev = priv->mdev;
        int err;
 
-       priv->fs = mlx5e_fs_init(priv->profile, mdev,
-                                !test_bit(MLX5E_STATE_DESTROYING, &priv->state));
-       if (!priv->fs) {
-               netdev_err(priv->netdev, "FS allocation failed\n");
-               return -ENOMEM;
-       }
-
        priv->rx_res = mlx5e_rx_res_alloc();
        if (!priv->rx_res) {
                err = -ENOMEM;
index ed73132..a9f4c65 100644 (file)
@@ -427,7 +427,8 @@ esw_setup_vport_dest(struct mlx5_flow_destination *dest, struct mlx5_flow_act *f
                dest[dest_idx].vport.vhca_id =
                        MLX5_CAP_GEN(esw_attr->dests[attr_idx].mdev, vhca_id);
                dest[dest_idx].vport.flags |= MLX5_FLOW_DEST_VPORT_VHCA_ID;
-               if (mlx5_lag_mpesw_is_activated(esw->dev))
+               if (dest[dest_idx].vport.num == MLX5_VPORT_UPLINK &&
+                   mlx5_lag_mpesw_is_activated(esw->dev))
                        dest[dest_idx].type = MLX5_FLOW_DESTINATION_TYPE_UPLINK;
        }
        if (esw_attr->dests[attr_idx].flags & MLX5_ESW_DEST_ENCAP) {
@@ -3115,8 +3116,10 @@ esw_vfs_changed_event_handler(struct mlx5_eswitch *esw, const u32 *out)
 
                err = mlx5_eswitch_load_vf_vports(esw, new_num_vfs,
                                                  MLX5_VPORT_UC_ADDR_CHANGE);
-               if (err)
+               if (err) {
+                       devl_unlock(devlink);
                        return;
+               }
        }
        esw->esw_funcs.num_vfs = new_num_vfs;
        devl_unlock(devlink);
index 0f34e3c..0651022 100644 (file)
@@ -1067,30 +1067,32 @@ static void mlx5_ldev_add_netdev(struct mlx5_lag *ldev,
                                 struct net_device *netdev)
 {
        unsigned int fn = mlx5_get_dev_index(dev);
+       unsigned long flags;
 
        if (fn >= ldev->ports)
                return;
 
-       spin_lock(&lag_lock);
+       spin_lock_irqsave(&lag_lock, flags);
        ldev->pf[fn].netdev = netdev;
        ldev->tracker.netdev_state[fn].link_up = 0;
        ldev->tracker.netdev_state[fn].tx_enabled = 0;
-       spin_unlock(&lag_lock);
+       spin_unlock_irqrestore(&lag_lock, flags);
 }
 
 static void mlx5_ldev_remove_netdev(struct mlx5_lag *ldev,
                                    struct net_device *netdev)
 {
+       unsigned long flags;
        int i;
 
-       spin_lock(&lag_lock);
+       spin_lock_irqsave(&lag_lock, flags);
        for (i = 0; i < ldev->ports; i++) {
                if (ldev->pf[i].netdev == netdev) {
                        ldev->pf[i].netdev = NULL;
                        break;
                }
        }
-       spin_unlock(&lag_lock);
+       spin_unlock_irqrestore(&lag_lock, flags);
 }
 
 static void mlx5_ldev_add_mdev(struct mlx5_lag *ldev,
@@ -1234,7 +1236,7 @@ void mlx5_lag_add_netdev(struct mlx5_core_dev *dev,
        mlx5_ldev_add_netdev(ldev, dev, netdev);
 
        for (i = 0; i < ldev->ports; i++)
-               if (!ldev->pf[i].dev)
+               if (!ldev->pf[i].netdev)
                        break;
 
        if (i >= ldev->ports)
@@ -1246,12 +1248,13 @@ void mlx5_lag_add_netdev(struct mlx5_core_dev *dev,
 bool mlx5_lag_is_roce(struct mlx5_core_dev *dev)
 {
        struct mlx5_lag *ldev;
+       unsigned long flags;
        bool res;
 
-       spin_lock(&lag_lock);
+       spin_lock_irqsave(&lag_lock, flags);
        ldev = mlx5_lag_dev(dev);
        res  = ldev && __mlx5_lag_is_roce(ldev);
-       spin_unlock(&lag_lock);
+       spin_unlock_irqrestore(&lag_lock, flags);
 
        return res;
 }
@@ -1260,12 +1263,13 @@ EXPORT_SYMBOL(mlx5_lag_is_roce);
 bool mlx5_lag_is_active(struct mlx5_core_dev *dev)
 {
        struct mlx5_lag *ldev;
+       unsigned long flags;
        bool res;
 
-       spin_lock(&lag_lock);
+       spin_lock_irqsave(&lag_lock, flags);
        ldev = mlx5_lag_dev(dev);
        res  = ldev && __mlx5_lag_is_active(ldev);
-       spin_unlock(&lag_lock);
+       spin_unlock_irqrestore(&lag_lock, flags);
 
        return res;
 }
@@ -1274,13 +1278,14 @@ EXPORT_SYMBOL(mlx5_lag_is_active);
 bool mlx5_lag_is_master(struct mlx5_core_dev *dev)
 {
        struct mlx5_lag *ldev;
+       unsigned long flags;
        bool res;
 
-       spin_lock(&lag_lock);
+       spin_lock_irqsave(&lag_lock, flags);
        ldev = mlx5_lag_dev(dev);
        res = ldev && __mlx5_lag_is_active(ldev) &&
                dev == ldev->pf[MLX5_LAG_P1].dev;
-       spin_unlock(&lag_lock);
+       spin_unlock_irqrestore(&lag_lock, flags);
 
        return res;
 }
@@ -1289,12 +1294,13 @@ EXPORT_SYMBOL(mlx5_lag_is_master);
 bool mlx5_lag_is_sriov(struct mlx5_core_dev *dev)
 {
        struct mlx5_lag *ldev;
+       unsigned long flags;
        bool res;
 
-       spin_lock(&lag_lock);
+       spin_lock_irqsave(&lag_lock, flags);
        ldev = mlx5_lag_dev(dev);
        res  = ldev && __mlx5_lag_is_sriov(ldev);
-       spin_unlock(&lag_lock);
+       spin_unlock_irqrestore(&lag_lock, flags);
 
        return res;
 }
@@ -1303,13 +1309,14 @@ EXPORT_SYMBOL(mlx5_lag_is_sriov);
 bool mlx5_lag_is_shared_fdb(struct mlx5_core_dev *dev)
 {
        struct mlx5_lag *ldev;
+       unsigned long flags;
        bool res;
 
-       spin_lock(&lag_lock);
+       spin_lock_irqsave(&lag_lock, flags);
        ldev = mlx5_lag_dev(dev);
        res = ldev && __mlx5_lag_is_sriov(ldev) &&
              test_bit(MLX5_LAG_MODE_FLAG_SHARED_FDB, &ldev->mode_flags);
-       spin_unlock(&lag_lock);
+       spin_unlock_irqrestore(&lag_lock, flags);
 
        return res;
 }
@@ -1352,9 +1359,10 @@ struct net_device *mlx5_lag_get_roce_netdev(struct mlx5_core_dev *dev)
 {
        struct net_device *ndev = NULL;
        struct mlx5_lag *ldev;
+       unsigned long flags;
        int i;
 
-       spin_lock(&lag_lock);
+       spin_lock_irqsave(&lag_lock, flags);
        ldev = mlx5_lag_dev(dev);
 
        if (!(ldev && __mlx5_lag_is_roce(ldev)))
@@ -1373,7 +1381,7 @@ struct net_device *mlx5_lag_get_roce_netdev(struct mlx5_core_dev *dev)
                dev_hold(ndev);
 
 unlock:
-       spin_unlock(&lag_lock);
+       spin_unlock_irqrestore(&lag_lock, flags);
 
        return ndev;
 }
@@ -1383,10 +1391,11 @@ u8 mlx5_lag_get_slave_port(struct mlx5_core_dev *dev,
                           struct net_device *slave)
 {
        struct mlx5_lag *ldev;
+       unsigned long flags;
        u8 port = 0;
        int i;
 
-       spin_lock(&lag_lock);
+       spin_lock_irqsave(&lag_lock, flags);
        ldev = mlx5_lag_dev(dev);
        if (!(ldev && __mlx5_lag_is_roce(ldev)))
                goto unlock;
@@ -1401,7 +1410,7 @@ u8 mlx5_lag_get_slave_port(struct mlx5_core_dev *dev,
        port = ldev->v2p_map[port * ldev->buckets];
 
 unlock:
-       spin_unlock(&lag_lock);
+       spin_unlock_irqrestore(&lag_lock, flags);
        return port;
 }
 EXPORT_SYMBOL(mlx5_lag_get_slave_port);
@@ -1422,8 +1431,9 @@ struct mlx5_core_dev *mlx5_lag_get_peer_mdev(struct mlx5_core_dev *dev)
 {
        struct mlx5_core_dev *peer_dev = NULL;
        struct mlx5_lag *ldev;
+       unsigned long flags;
 
-       spin_lock(&lag_lock);
+       spin_lock_irqsave(&lag_lock, flags);
        ldev = mlx5_lag_dev(dev);
        if (!ldev)
                goto unlock;
@@ -1433,7 +1443,7 @@ struct mlx5_core_dev *mlx5_lag_get_peer_mdev(struct mlx5_core_dev *dev)
                           ldev->pf[MLX5_LAG_P1].dev;
 
 unlock:
-       spin_unlock(&lag_lock);
+       spin_unlock_irqrestore(&lag_lock, flags);
        return peer_dev;
 }
 EXPORT_SYMBOL(mlx5_lag_get_peer_mdev);
@@ -1446,6 +1456,7 @@ int mlx5_lag_query_cong_counters(struct mlx5_core_dev *dev,
        int outlen = MLX5_ST_SZ_BYTES(query_cong_statistics_out);
        struct mlx5_core_dev **mdev;
        struct mlx5_lag *ldev;
+       unsigned long flags;
        int num_ports;
        int ret, i, j;
        void *out;
@@ -1462,7 +1473,7 @@ int mlx5_lag_query_cong_counters(struct mlx5_core_dev *dev,
 
        memset(values, 0, sizeof(*values) * num_counters);
 
-       spin_lock(&lag_lock);
+       spin_lock_irqsave(&lag_lock, flags);
        ldev = mlx5_lag_dev(dev);
        if (ldev && __mlx5_lag_is_active(ldev)) {
                num_ports = ldev->ports;
@@ -1472,7 +1483,7 @@ int mlx5_lag_query_cong_counters(struct mlx5_core_dev *dev,
                num_ports = 1;
                mdev[MLX5_LAG_P1] = dev;
        }
-       spin_unlock(&lag_lock);
+       spin_unlock_irqrestore(&lag_lock, flags);
 
        for (i = 0; i < num_ports; ++i) {
                u32 in[MLX5_ST_SZ_DW(query_cong_statistics_in)] = {};
index bec8d6d..89b2d9c 100644 (file)
@@ -494,6 +494,24 @@ static int max_uc_list_get_devlink_param(struct mlx5_core_dev *dev)
        return err;
 }
 
+bool mlx5_is_roce_on(struct mlx5_core_dev *dev)
+{
+       struct devlink *devlink = priv_to_devlink(dev);
+       union devlink_param_value val;
+       int err;
+
+       err = devlink_param_driverinit_value_get(devlink,
+                                                DEVLINK_PARAM_GENERIC_ID_ENABLE_ROCE,
+                                                &val);
+
+       if (!err)
+               return val.vbool;
+
+       mlx5_core_dbg(dev, "Failed to get param. err = %d\n", err);
+       return MLX5_CAP_GEN(dev, roce);
+}
+EXPORT_SYMBOL(mlx5_is_roce_on);
+
 static int handle_hca_cap_2(struct mlx5_core_dev *dev, void *set_ctx)
 {
        void *set_hca_cap;
@@ -597,7 +615,8 @@ static int handle_hca_cap(struct mlx5_core_dev *dev, void *set_ctx)
                         MLX5_CAP_GEN_MAX(dev, num_total_dynamic_vf_msix));
 
        if (MLX5_CAP_GEN(dev, roce_rw_supported))
-               MLX5_SET(cmd_hca_cap, set_hca_cap, roce, mlx5_is_roce_init_enabled(dev));
+               MLX5_SET(cmd_hca_cap, set_hca_cap, roce,
+                        mlx5_is_roce_on(dev));
 
        max_uc_list = max_uc_list_get_devlink_param(dev);
        if (max_uc_list > 0)
@@ -623,7 +642,7 @@ static int handle_hca_cap(struct mlx5_core_dev *dev, void *set_ctx)
  */
 static bool is_roce_fw_disabled(struct mlx5_core_dev *dev)
 {
-       return (MLX5_CAP_GEN(dev, roce_rw_supported) && !mlx5_is_roce_init_enabled(dev)) ||
+       return (MLX5_CAP_GEN(dev, roce_rw_supported) && !mlx5_is_roce_on(dev)) ||
                (!MLX5_CAP_GEN(dev, roce_rw_supported) && !MLX5_CAP_GEN(dev, roce));
 }
 
@@ -1530,7 +1549,9 @@ int mlx5_mdev_init(struct mlx5_core_dev *dev, int profile_idx)
        memcpy(&dev->profile, &profile[profile_idx], sizeof(dev->profile));
        INIT_LIST_HEAD(&priv->ctx_list);
        spin_lock_init(&priv->ctx_lock);
+       lockdep_register_key(&dev->lock_key);
        mutex_init(&dev->intf_state_mutex);
+       lockdep_set_class(&dev->intf_state_mutex, &dev->lock_key);
 
        mutex_init(&priv->bfregs.reg_head.lock);
        mutex_init(&priv->bfregs.wc_head.lock);
@@ -1597,6 +1618,7 @@ err_timeout_init:
        mutex_destroy(&priv->bfregs.wc_head.lock);
        mutex_destroy(&priv->bfregs.reg_head.lock);
        mutex_destroy(&dev->intf_state_mutex);
+       lockdep_unregister_key(&dev->lock_key);
        return err;
 }
 
@@ -1618,6 +1640,7 @@ void mlx5_mdev_uninit(struct mlx5_core_dev *dev)
        mutex_destroy(&priv->bfregs.wc_head.lock);
        mutex_destroy(&priv->bfregs.reg_head.lock);
        mutex_destroy(&dev->intf_state_mutex);
+       lockdep_unregister_key(&dev->lock_key);
 }
 
 static int probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
index ec76a8b..6059635 100644 (file)
@@ -376,8 +376,8 @@ retry:
                        goto out_dropped;
                }
        }
+       err = mlx5_cmd_check(dev, err, in, out);
        if (err) {
-               err = mlx5_cmd_check(dev, err, in, out);
                mlx5_core_warn(dev, "func_id 0x%x, npages %d, err %d\n",
                               func_id, npages, err);
                goto out_dropped;
@@ -524,10 +524,13 @@ static int reclaim_pages(struct mlx5_core_dev *dev, u16 func_id, int npages,
                dev->priv.reclaim_pages_discard += npages;
        }
        /* if triggered by FW event and failed by FW then ignore */
-       if (event && err == -EREMOTEIO)
+       if (event && err == -EREMOTEIO) {
                err = 0;
+               goto out_free;
+       }
+
+       err = mlx5_cmd_check(dev, err, in, out);
        if (err) {
-               err = mlx5_cmd_check(dev, err, in, out);
                mlx5_core_err(dev, "failed reclaiming pages: err %d\n", err);
                goto out_free;
        }
index ee2e1b7..c0e6c48 100644 (file)
@@ -159,11 +159,11 @@ static int mlx5_sriov_enable(struct pci_dev *pdev, int num_vfs)
 
        devl_lock(devlink);
        err = mlx5_device_enable_sriov(dev, num_vfs);
+       devl_unlock(devlink);
        if (err) {
                mlx5_core_warn(dev, "mlx5_device_enable_sriov failed : %d\n", err);
                return err;
        }
-       devl_unlock(devlink);
 
        err = pci_enable_sriov(pdev, num_vfs);
        if (err) {
index 5fdf9b7..5a1027b 100644 (file)
@@ -75,6 +75,7 @@ struct mlxbf_gige {
        struct net_device *netdev;
        struct platform_device *pdev;
        void __iomem *mdio_io;
+       void __iomem *clk_io;
        struct mii_bus *mdiobus;
        spinlock_t lock;      /* for packet processing indices */
        u16 rx_q_entries;
@@ -137,7 +138,8 @@ enum mlxbf_gige_res {
        MLXBF_GIGE_RES_MDIO9,
        MLXBF_GIGE_RES_GPIO0,
        MLXBF_GIGE_RES_LLU,
-       MLXBF_GIGE_RES_PLU
+       MLXBF_GIGE_RES_PLU,
+       MLXBF_GIGE_RES_CLK
 };
 
 /* Version of register data returned by mlxbf_gige_get_regs() */
index 2e6c1b7..85155cd 100644 (file)
 #include <linux/property.h>
 
 #include "mlxbf_gige.h"
+#include "mlxbf_gige_regs.h"
 
 #define MLXBF_GIGE_MDIO_GW_OFFSET      0x0
 #define MLXBF_GIGE_MDIO_CFG_OFFSET     0x4
 
+#define MLXBF_GIGE_MDIO_FREQ_REFERENCE 156250000ULL
+#define MLXBF_GIGE_MDIO_COREPLL_CONST  16384ULL
+#define MLXBF_GIGE_MDC_CLK_NS          400
+#define MLXBF_GIGE_MDIO_PLL_I1CLK_REG1 0x4
+#define MLXBF_GIGE_MDIO_PLL_I1CLK_REG2 0x8
+#define MLXBF_GIGE_MDIO_CORE_F_SHIFT   0
+#define MLXBF_GIGE_MDIO_CORE_F_MASK    GENMASK(25, 0)
+#define MLXBF_GIGE_MDIO_CORE_R_SHIFT   26
+#define MLXBF_GIGE_MDIO_CORE_R_MASK    GENMASK(31, 26)
+#define MLXBF_GIGE_MDIO_CORE_OD_SHIFT  0
+#define MLXBF_GIGE_MDIO_CORE_OD_MASK   GENMASK(3, 0)
+
 /* Support clause 22 */
 #define MLXBF_GIGE_MDIO_CL22_ST1       0x1
 #define MLXBF_GIGE_MDIO_CL22_WRITE     0x1
 #define MLXBF_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK          GENMASK(23, 16)
 #define MLXBF_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK         GENMASK(31, 24)
 
+#define MLXBF_GIGE_MDIO_CFG_VAL (FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_MODE_MASK, 1) | \
+                                FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO3_3_MASK, 1) | \
+                                FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_FULL_DRIVE_MASK, 1) | \
+                                FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK, 6) | \
+                                FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK, 13))
+
+#define MLXBF_GIGE_BF2_COREPLL_ADDR 0x02800c30
+#define MLXBF_GIGE_BF2_COREPLL_SIZE 0x0000000c
+
+static struct resource corepll_params[] = {
+       [MLXBF_GIGE_VERSION_BF2] = {
+               .start = MLXBF_GIGE_BF2_COREPLL_ADDR,
+               .end = MLXBF_GIGE_BF2_COREPLL_ADDR + MLXBF_GIGE_BF2_COREPLL_SIZE - 1,
+               .name = "COREPLL_RES"
+       },
+};
+
+/* Returns core clock i1clk in Hz */
+static u64 calculate_i1clk(struct mlxbf_gige *priv)
+{
+       u8 core_od, core_r;
+       u64 freq_output;
+       u32 reg1, reg2;
+       u32 core_f;
+
+       reg1 = readl(priv->clk_io + MLXBF_GIGE_MDIO_PLL_I1CLK_REG1);
+       reg2 = readl(priv->clk_io + MLXBF_GIGE_MDIO_PLL_I1CLK_REG2);
+
+       core_f = (reg1 & MLXBF_GIGE_MDIO_CORE_F_MASK) >>
+               MLXBF_GIGE_MDIO_CORE_F_SHIFT;
+       core_r = (reg1 & MLXBF_GIGE_MDIO_CORE_R_MASK) >>
+               MLXBF_GIGE_MDIO_CORE_R_SHIFT;
+       core_od = (reg2 & MLXBF_GIGE_MDIO_CORE_OD_MASK) >>
+               MLXBF_GIGE_MDIO_CORE_OD_SHIFT;
+
+       /* Compute PLL output frequency as follow:
+        *
+        *                                     CORE_F / 16384
+        * freq_output = freq_reference * ----------------------------
+        *                              (CORE_R + 1) * (CORE_OD + 1)
+        */
+       freq_output = div_u64((MLXBF_GIGE_MDIO_FREQ_REFERENCE * core_f),
+                             MLXBF_GIGE_MDIO_COREPLL_CONST);
+       freq_output = div_u64(freq_output, (core_r + 1) * (core_od + 1));
+
+       return freq_output;
+}
+
 /* Formula for encoding the MDIO period. The encoded value is
  * passed to the MDIO config register.
  *
- * mdc_clk = 2*(val + 1)*i1clk
+ * mdc_clk = 2*(val + 1)*(core clock in sec)
  *
- * 400 ns = 2*(val + 1)*(((1/430)*1000) ns)
+ * i1clk is in Hz:
+ * 400 ns = 2*(val + 1)*(1/i1clk)
  *
- * val = (((400 * 430 / 1000) / 2) - 1)
+ * val = (((400/10^9) / (1/i1clk) / 2) - 1)
+ * val = (400/2 * i1clk)/10^9 - 1
  */
-#define MLXBF_GIGE_I1CLK_MHZ           430
-#define MLXBF_GIGE_MDC_CLK_NS          400
+static u8 mdio_period_map(struct mlxbf_gige *priv)
+{
+       u8 mdio_period;
+       u64 i1clk;
 
-#define MLXBF_GIGE_MDIO_PERIOD (((MLXBF_GIGE_MDC_CLK_NS * MLXBF_GIGE_I1CLK_MHZ / 1000) / 2) - 1)
+       i1clk = calculate_i1clk(priv);
 
-#define MLXBF_GIGE_MDIO_CFG_VAL (FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_MODE_MASK, 1) | \
-                                FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO3_3_MASK, 1) | \
-                                FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_FULL_DRIVE_MASK, 1) | \
-                                FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDC_PERIOD_MASK, \
-                                           MLXBF_GIGE_MDIO_PERIOD) | \
-                                FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK, 6) | \
-                                FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK, 13))
+       mdio_period = div_u64((MLXBF_GIGE_MDC_CLK_NS >> 1) * i1clk, 1000000000) - 1;
+
+       return mdio_period;
+}
 
 static u32 mlxbf_gige_mdio_create_cmd(u16 data, int phy_add,
                                      int phy_reg, u32 opcode)
@@ -124,9 +186,9 @@ static int mlxbf_gige_mdio_write(struct mii_bus *bus, int phy_add,
                                 int phy_reg, u16 val)
 {
        struct mlxbf_gige *priv = bus->priv;
+       u32 temp;
        u32 cmd;
        int ret;
-       u32 temp;
 
        if (phy_reg & MII_ADDR_C45)
                return -EOPNOTSUPP;
@@ -144,18 +206,44 @@ static int mlxbf_gige_mdio_write(struct mii_bus *bus, int phy_add,
        return ret;
 }
 
+static void mlxbf_gige_mdio_cfg(struct mlxbf_gige *priv)
+{
+       u8 mdio_period;
+       u32 val;
+
+       mdio_period = mdio_period_map(priv);
+
+       val = MLXBF_GIGE_MDIO_CFG_VAL;
+       val |= FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDC_PERIOD_MASK, mdio_period);
+       writel(val, priv->mdio_io + MLXBF_GIGE_MDIO_CFG_OFFSET);
+}
+
 int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv)
 {
        struct device *dev = &pdev->dev;
+       struct resource *res;
        int ret;
 
        priv->mdio_io = devm_platform_ioremap_resource(pdev, MLXBF_GIGE_RES_MDIO9);
        if (IS_ERR(priv->mdio_io))
                return PTR_ERR(priv->mdio_io);
 
-       /* Configure mdio parameters */
-       writel(MLXBF_GIGE_MDIO_CFG_VAL,
-              priv->mdio_io + MLXBF_GIGE_MDIO_CFG_OFFSET);
+       /* clk resource shared with other drivers so cannot use
+        * devm_platform_ioremap_resource
+        */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_CLK);
+       if (!res) {
+               /* For backward compatibility with older ACPI tables, also keep
+                * CLK resource internal to the driver.
+                */
+               res = &corepll_params[MLXBF_GIGE_VERSION_BF2];
+       }
+
+       priv->clk_io = devm_ioremap(dev, res->start, resource_size(res));
+       if (IS_ERR(priv->clk_io))
+               return PTR_ERR(priv->clk_io);
+
+       mlxbf_gige_mdio_cfg(priv);
 
        priv->mdiobus = devm_mdiobus_alloc(dev);
        if (!priv->mdiobus) {
index 5fb33c9..7be3a79 100644 (file)
@@ -8,6 +8,8 @@
 #ifndef __MLXBF_GIGE_REGS_H__
 #define __MLXBF_GIGE_REGS_H__
 
+#define MLXBF_GIGE_VERSION                            0x0000
+#define MLXBF_GIGE_VERSION_BF2                        0x0
 #define MLXBF_GIGE_STATUS                             0x0010
 #define MLXBF_GIGE_STATUS_READY                       BIT(0)
 #define MLXBF_GIGE_INT_STATUS                         0x0028
index 1e240cd..30c7b0e 100644 (file)
@@ -1897,9 +1897,9 @@ static void mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u16 local_port)
 
        cancel_delayed_work_sync(&mlxsw_sp_port->periodic_hw_stats.update_dw);
        cancel_delayed_work_sync(&mlxsw_sp_port->ptp.shaper_dw);
-       mlxsw_sp_port_ptp_clear(mlxsw_sp_port);
        mlxsw_core_port_clear(mlxsw_sp->core, local_port, mlxsw_sp);
        unregister_netdev(mlxsw_sp_port->dev); /* This calls ndo_stop */
+       mlxsw_sp_port_ptp_clear(mlxsw_sp_port);
        mlxsw_sp_port_vlan_classification_set(mlxsw_sp_port, true, true);
        mlxsw_sp->ports[local_port] = NULL;
        mlxsw_sp_port_vlan_flush(mlxsw_sp_port, true);
index 2e0b704..7b01b9c 100644 (file)
@@ -46,6 +46,7 @@ struct mlxsw_sp2_ptp_state {
                                          * enabled.
                                          */
        struct hwtstamp_config config;
+       struct mutex lock; /* Protects 'config' and HW configuration. */
 };
 
 struct mlxsw_sp1_ptp_key {
@@ -1374,6 +1375,7 @@ struct mlxsw_sp_ptp_state *mlxsw_sp2_ptp_init(struct mlxsw_sp *mlxsw_sp)
                goto err_ptp_traps_set;
 
        refcount_set(&ptp_state->ptp_port_enabled_ref, 0);
+       mutex_init(&ptp_state->lock);
        return &ptp_state->common;
 
 err_ptp_traps_set:
@@ -1388,6 +1390,7 @@ void mlxsw_sp2_ptp_fini(struct mlxsw_sp_ptp_state *ptp_state_common)
 
        ptp_state = mlxsw_sp2_ptp_state(mlxsw_sp);
 
+       mutex_destroy(&ptp_state->lock);
        mlxsw_sp_ptp_traps_unset(mlxsw_sp);
        kfree(ptp_state);
 }
@@ -1461,7 +1464,10 @@ int mlxsw_sp2_ptp_hwtstamp_get(struct mlxsw_sp_port *mlxsw_sp_port,
 
        ptp_state = mlxsw_sp2_ptp_state(mlxsw_sp_port->mlxsw_sp);
 
+       mutex_lock(&ptp_state->lock);
        *config = ptp_state->config;
+       mutex_unlock(&ptp_state->lock);
+
        return 0;
 }
 
@@ -1523,6 +1529,9 @@ mlxsw_sp2_ptp_get_message_types(const struct hwtstamp_config *config,
                return -EINVAL;
        }
 
+       if ((ing_types && !egr_types) || (!ing_types && egr_types))
+               return -EINVAL;
+
        *p_ing_types = ing_types;
        *p_egr_types = egr_types;
        return 0;
@@ -1574,8 +1583,6 @@ static int mlxsw_sp2_ptp_configure_port(struct mlxsw_sp_port *mlxsw_sp_port,
        struct mlxsw_sp2_ptp_state *ptp_state;
        int err;
 
-       ASSERT_RTNL();
-
        ptp_state = mlxsw_sp2_ptp_state(mlxsw_sp_port->mlxsw_sp);
 
        if (refcount_inc_not_zero(&ptp_state->ptp_port_enabled_ref))
@@ -1597,8 +1604,6 @@ static int mlxsw_sp2_ptp_deconfigure_port(struct mlxsw_sp_port *mlxsw_sp_port,
        struct mlxsw_sp2_ptp_state *ptp_state;
        int err;
 
-       ASSERT_RTNL();
-
        ptp_state = mlxsw_sp2_ptp_state(mlxsw_sp_port->mlxsw_sp);
 
        if (!refcount_dec_and_test(&ptp_state->ptp_port_enabled_ref))
@@ -1618,16 +1623,20 @@ err_ptp_disable:
 int mlxsw_sp2_ptp_hwtstamp_set(struct mlxsw_sp_port *mlxsw_sp_port,
                               struct hwtstamp_config *config)
 {
+       struct mlxsw_sp2_ptp_state *ptp_state;
        enum hwtstamp_rx_filters rx_filter;
        struct hwtstamp_config new_config;
        u16 new_ing_types, new_egr_types;
        bool ptp_enabled;
        int err;
 
+       ptp_state = mlxsw_sp2_ptp_state(mlxsw_sp_port->mlxsw_sp);
+       mutex_lock(&ptp_state->lock);
+
        err = mlxsw_sp2_ptp_get_message_types(config, &new_ing_types,
                                              &new_egr_types, &rx_filter);
        if (err)
-               return err;
+               goto err_get_message_types;
 
        new_config.flags = config->flags;
        new_config.tx_type = config->tx_type;
@@ -1640,11 +1649,11 @@ int mlxsw_sp2_ptp_hwtstamp_set(struct mlxsw_sp_port *mlxsw_sp_port,
                err = mlxsw_sp2_ptp_configure_port(mlxsw_sp_port, new_ing_types,
                                                   new_egr_types, new_config);
                if (err)
-                       return err;
+                       goto err_configure_port;
        } else if (!new_ing_types && !new_egr_types && ptp_enabled) {
                err = mlxsw_sp2_ptp_deconfigure_port(mlxsw_sp_port, new_config);
                if (err)
-                       return err;
+                       goto err_deconfigure_port;
        }
 
        mlxsw_sp_port->ptp.ing_types = new_ing_types;
@@ -1652,8 +1661,15 @@ int mlxsw_sp2_ptp_hwtstamp_set(struct mlxsw_sp_port *mlxsw_sp_port,
 
        /* Notify the ioctl caller what we are actually timestamping. */
        config->rx_filter = rx_filter;
+       mutex_unlock(&ptp_state->lock);
 
        return 0;
+
+err_deconfigure_port:
+err_configure_port:
+err_get_message_types:
+       mutex_unlock(&ptp_state->lock);
+       return err;
 }
 
 int mlxsw_sp2_ptp_get_ts_info(struct mlxsw_sp *mlxsw_sp,
index 2d1628f..a8b8823 100644 (file)
@@ -171,10 +171,11 @@ static inline void mlxsw_sp1_get_stats(struct mlxsw_sp_port *mlxsw_sp_port,
 {
 }
 
-int mlxsw_sp_ptp_txhdr_construct(struct mlxsw_core *mlxsw_core,
-                                struct mlxsw_sp_port *mlxsw_sp_port,
-                                struct sk_buff *skb,
-                                const struct mlxsw_tx_info *tx_info)
+static inline int
+mlxsw_sp_ptp_txhdr_construct(struct mlxsw_core *mlxsw_core,
+                            struct mlxsw_sp_port *mlxsw_sp_port,
+                            struct sk_buff *skb,
+                            const struct mlxsw_tx_info *tx_info)
 {
        return -EOPNOTSUPP;
 }
@@ -231,10 +232,11 @@ static inline int mlxsw_sp2_ptp_get_ts_info(struct mlxsw_sp *mlxsw_sp,
        return mlxsw_sp_ptp_get_ts_info_noptp(info);
 }
 
-int mlxsw_sp2_ptp_txhdr_construct(struct mlxsw_core *mlxsw_core,
-                                 struct mlxsw_sp_port *mlxsw_sp_port,
-                                 struct sk_buff *skb,
-                                 const struct mlxsw_tx_info *tx_info)
+static inline int
+mlxsw_sp2_ptp_txhdr_construct(struct mlxsw_core *mlxsw_core,
+                             struct mlxsw_sp_port *mlxsw_sp_port,
+                             struct sk_buff *skb,
+                             const struct mlxsw_tx_info *tx_info)
 {
        return -EOPNOTSUPP;
 }
index 39904da..b3472fb 100644 (file)
@@ -423,7 +423,8 @@ mlxsw_sp_span_gretap4_route(const struct net_device *to_dev,
 
        parms = mlxsw_sp_ipip_netdev_parms4(to_dev);
        ip_tunnel_init_flow(&fl4, parms.iph.protocol, *daddrp, *saddrp,
-                           0, 0, dev_net(to_dev), parms.link, tun->fwmark, 0);
+                           0, 0, dev_net(to_dev), parms.link, tun->fwmark, 0,
+                           0);
 
        rt = ip_route_output_key(tun->net, &fl4);
        if (IS_ERR(rt))
index 6dea7f8..51f8a08 100644 (file)
@@ -425,7 +425,8 @@ static struct sk_buff *lan966x_fdma_rx_get_frame(struct lan966x_rx *rx)
        lan966x_ifh_get_src_port(skb->data, &src_port);
        lan966x_ifh_get_timestamp(skb->data, &timestamp);
 
-       WARN_ON(src_port >= lan966x->num_phys_ports);
+       if (WARN_ON(src_port >= lan966x->num_phys_ports))
+               goto free_skb;
 
        skb->dev = lan966x->ports[src_port]->dev;
        skb_pull(skb, IFH_LEN * sizeof(u32));
@@ -449,6 +450,8 @@ static struct sk_buff *lan966x_fdma_rx_get_frame(struct lan966x_rx *rx)
 
        return skb;
 
+free_skb:
+       kfree_skb(skb);
 unmap_page:
        dma_unmap_page(lan966x->dev, (dma_addr_t)db->dataptr,
                       FDMA_DCB_STATUS_BLOCKL(db->status),
index 1d6e3b6..d928b75 100644 (file)
@@ -710,7 +710,7 @@ static void lan966x_cleanup_ports(struct lan966x *lan966x)
        disable_irq(lan966x->xtr_irq);
        lan966x->xtr_irq = -ENXIO;
 
-       if (lan966x->ana_irq) {
+       if (lan966x->ana_irq > 0) {
                disable_irq(lan966x->ana_irq);
                lan966x->ana_irq = -ENXIO;
        }
@@ -718,10 +718,10 @@ static void lan966x_cleanup_ports(struct lan966x *lan966x)
        if (lan966x->fdma)
                devm_free_irq(lan966x->dev, lan966x->fdma_irq, lan966x);
 
-       if (lan966x->ptp_irq)
+       if (lan966x->ptp_irq > 0)
                devm_free_irq(lan966x->dev, lan966x->ptp_irq, lan966x);
 
-       if (lan966x->ptp_ext_irq)
+       if (lan966x->ptp_ext_irq > 0)
                devm_free_irq(lan966x->dev, lan966x->ptp_ext_irq, lan966x);
 }
 
@@ -1049,7 +1049,7 @@ static int lan966x_probe(struct platform_device *pdev)
        }
 
        lan966x->ana_irq = platform_get_irq_byname(pdev, "ana");
-       if (lan966x->ana_irq) {
+       if (lan966x->ana_irq > 0) {
                err = devm_request_threaded_irq(&pdev->dev, lan966x->ana_irq, NULL,
                                                lan966x_ana_irq_handler, IRQF_ONESHOT,
                                                "ana irq", lan966x);
index 304f84a..21844be 100644 (file)
@@ -113,6 +113,8 @@ static void sparx5_xtr_grp(struct sparx5 *sparx5, u8 grp, bool byte_swap)
                        /* This assumes STATUS_WORD_POS == 1, Status
                         * just after last data
                         */
+                       if (!byte_swap)
+                               val = ntohl((__force __be32)val);
                        byte_cnt -= (4 - XTR_VALID_BYTES(val));
                        eof_flag = true;
                        break;
index 5f92401..00d8198 100644 (file)
@@ -1465,10 +1465,6 @@ static void mana_gd_shutdown(struct pci_dev *pdev)
        pci_disable_device(pdev);
 }
 
-#ifndef PCI_VENDOR_ID_MICROSOFT
-#define PCI_VENDOR_ID_MICROSOFT 0x1414
-#endif
-
 static const struct pci_device_id mana_id_table[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_MICROSOFT, MANA_PF_DEVICE_ID) },
        { PCI_DEVICE(PCI_VENDOR_ID_MICROSOFT, MANA_VF_DEVICE_ID) },
index a3214a7..9e57d23 100644 (file)
@@ -62,9 +62,6 @@ static int moxart_set_mac_address(struct net_device *ndev, void *addr)
 {
        struct sockaddr *address = addr;
 
-       if (!is_valid_ether_addr(address->sa_data))
-               return -EADDRNOTAVAIL;
-
        eth_hw_addr_set(ndev, address->sa_data);
        moxart_update_mac_address(ndev);
 
@@ -74,11 +71,6 @@ static int moxart_set_mac_address(struct net_device *ndev, void *addr)
 static void moxart_mac_free_memory(struct net_device *ndev)
 {
        struct moxart_mac_priv_t *priv = netdev_priv(ndev);
-       int i;
-
-       for (i = 0; i < RX_DESC_NUM; i++)
-               dma_unmap_single(&ndev->dev, priv->rx_mapping[i],
-                                priv->rx_buf_size, DMA_FROM_DEVICE);
 
        if (priv->tx_desc_base)
                dma_free_coherent(&priv->pdev->dev,
@@ -147,11 +139,11 @@ static void moxart_mac_setup_desc_ring(struct net_device *ndev)
                       desc + RX_REG_OFFSET_DESC1);
 
                priv->rx_buf[i] = priv->rx_buf_base + priv->rx_buf_size * i;
-               priv->rx_mapping[i] = dma_map_single(&ndev->dev,
+               priv->rx_mapping[i] = dma_map_single(&priv->pdev->dev,
                                                     priv->rx_buf[i],
                                                     priv->rx_buf_size,
                                                     DMA_FROM_DEVICE);
-               if (dma_mapping_error(&ndev->dev, priv->rx_mapping[i]))
+               if (dma_mapping_error(&priv->pdev->dev, priv->rx_mapping[i]))
                        netdev_err(ndev, "DMA mapping error\n");
 
                moxart_desc_write(priv->rx_mapping[i],
@@ -172,9 +164,6 @@ static int moxart_mac_open(struct net_device *ndev)
 {
        struct moxart_mac_priv_t *priv = netdev_priv(ndev);
 
-       if (!is_valid_ether_addr(ndev->dev_addr))
-               return -EADDRNOTAVAIL;
-
        napi_enable(&priv->napi);
 
        moxart_mac_reset(ndev);
@@ -193,6 +182,7 @@ static int moxart_mac_open(struct net_device *ndev)
 static int moxart_mac_stop(struct net_device *ndev)
 {
        struct moxart_mac_priv_t *priv = netdev_priv(ndev);
+       int i;
 
        napi_disable(&priv->napi);
 
@@ -204,6 +194,11 @@ static int moxart_mac_stop(struct net_device *ndev)
        /* disable all functions */
        writel(0, priv->base + REG_MAC_CTRL);
 
+       /* unmap areas mapped in moxart_mac_setup_desc_ring() */
+       for (i = 0; i < RX_DESC_NUM; i++)
+               dma_unmap_single(&priv->pdev->dev, priv->rx_mapping[i],
+                                priv->rx_buf_size, DMA_FROM_DEVICE);
+
        return 0;
 }
 
@@ -240,7 +235,7 @@ static int moxart_rx_poll(struct napi_struct *napi, int budget)
                if (len > RX_BUF_SIZE)
                        len = RX_BUF_SIZE;
 
-               dma_sync_single_for_cpu(&ndev->dev,
+               dma_sync_single_for_cpu(&priv->pdev->dev,
                                        priv->rx_mapping[rx_head],
                                        priv->rx_buf_size, DMA_FROM_DEVICE);
                skb = netdev_alloc_skb_ip_align(ndev, len);
@@ -294,7 +289,7 @@ static void moxart_tx_finished(struct net_device *ndev)
        unsigned int tx_tail = priv->tx_tail;
 
        while (tx_tail != tx_head) {
-               dma_unmap_single(&ndev->dev, priv->tx_mapping[tx_tail],
+               dma_unmap_single(&priv->pdev->dev, priv->tx_mapping[tx_tail],
                                 priv->tx_len[tx_tail], DMA_TO_DEVICE);
 
                ndev->stats.tx_packets++;
@@ -358,9 +353,9 @@ static netdev_tx_t moxart_mac_start_xmit(struct sk_buff *skb,
 
        len = skb->len > TX_BUF_SIZE ? TX_BUF_SIZE : skb->len;
 
-       priv->tx_mapping[tx_head] = dma_map_single(&ndev->dev, skb->data,
+       priv->tx_mapping[tx_head] = dma_map_single(&priv->pdev->dev, skb->data,
                                                   len, DMA_TO_DEVICE);
-       if (dma_mapping_error(&ndev->dev, priv->tx_mapping[tx_head])) {
+       if (dma_mapping_error(&priv->pdev->dev, priv->tx_mapping[tx_head])) {
                netdev_err(ndev, "DMA mapping error\n");
                goto out_unlock;
        }
@@ -379,7 +374,7 @@ static netdev_tx_t moxart_mac_start_xmit(struct sk_buff *skb,
                len = ETH_ZLEN;
        }
 
-       dma_sync_single_for_device(&ndev->dev, priv->tx_mapping[tx_head],
+       dma_sync_single_for_device(&priv->pdev->dev, priv->tx_mapping[tx_head],
                                   priv->tx_buf_size, DMA_TO_DEVICE);
 
        txdes1 = TX_DESC1_LTS | TX_DESC1_FTS | (len & TX_DESC1_BUF_SIZE_MASK);
@@ -488,12 +483,19 @@ static int moxart_mac_probe(struct platform_device *pdev)
        }
        ndev->base_addr = res->start;
 
+       ret = platform_get_ethdev_address(p_dev, ndev);
+       if (ret == -EPROBE_DEFER)
+               goto init_fail;
+       if (ret)
+               eth_hw_addr_random(ndev);
+       moxart_update_mac_address(ndev);
+
        spin_lock_init(&priv->txlock);
 
        priv->tx_buf_size = TX_BUF_SIZE;
        priv->rx_buf_size = RX_BUF_SIZE;
 
-       priv->tx_desc_base = dma_alloc_coherent(&pdev->dev, TX_REG_DESC_SIZE *
+       priv->tx_desc_base = dma_alloc_coherent(p_dev, TX_REG_DESC_SIZE *
                                                TX_DESC_NUM, &priv->tx_base,
                                                GFP_DMA | GFP_KERNEL);
        if (!priv->tx_desc_base) {
@@ -501,7 +503,7 @@ static int moxart_mac_probe(struct platform_device *pdev)
                goto init_fail;
        }
 
-       priv->rx_desc_base = dma_alloc_coherent(&pdev->dev, RX_REG_DESC_SIZE *
+       priv->rx_desc_base = dma_alloc_coherent(p_dev, RX_REG_DESC_SIZE *
                                                RX_DESC_NUM, &priv->rx_base,
                                                GFP_DMA | GFP_KERNEL);
        if (!priv->rx_desc_base) {
index d4649e4..306026e 100644 (file)
@@ -1860,16 +1860,20 @@ void ocelot_get_strings(struct ocelot *ocelot, int port, u32 sset, u8 *data)
        if (sset != ETH_SS_STATS)
                return;
 
-       for (i = 0; i < ocelot->num_stats; i++)
+       for (i = 0; i < OCELOT_NUM_STATS; i++) {
+               if (ocelot->stats_layout[i].name[0] == '\0')
+                       continue;
+
                memcpy(data + i * ETH_GSTRING_LEN, ocelot->stats_layout[i].name,
                       ETH_GSTRING_LEN);
+       }
 }
 EXPORT_SYMBOL(ocelot_get_strings);
 
 /* Caller must hold &ocelot->stats_lock */
 static int ocelot_port_update_stats(struct ocelot *ocelot, int port)
 {
-       unsigned int idx = port * ocelot->num_stats;
+       unsigned int idx = port * OCELOT_NUM_STATS;
        struct ocelot_stats_region *region;
        int err, j;
 
@@ -1877,9 +1881,8 @@ static int ocelot_port_update_stats(struct ocelot *ocelot, int port)
        ocelot_write(ocelot, SYS_STAT_CFG_STAT_VIEW(port), SYS_STAT_CFG);
 
        list_for_each_entry(region, &ocelot->stats_regions, node) {
-               err = ocelot_bulk_read_rix(ocelot, SYS_COUNT_RX_OCTETS,
-                                          region->offset, region->buf,
-                                          region->count);
+               err = ocelot_bulk_read(ocelot, region->base, region->buf,
+                                      region->count);
                if (err)
                        return err;
 
@@ -1906,13 +1909,13 @@ static void ocelot_check_stats_work(struct work_struct *work)
                                             stats_work);
        int i, err;
 
-       mutex_lock(&ocelot->stats_lock);
+       spin_lock(&ocelot->stats_lock);
        for (i = 0; i < ocelot->num_phys_ports; i++) {
                err = ocelot_port_update_stats(ocelot, i);
                if (err)
                        break;
        }
-       mutex_unlock(&ocelot->stats_lock);
+       spin_unlock(&ocelot->stats_lock);
 
        if (err)
                dev_err(ocelot->dev, "Error %d updating ethtool stats\n",  err);
@@ -1925,16 +1928,22 @@ void ocelot_get_ethtool_stats(struct ocelot *ocelot, int port, u64 *data)
 {
        int i, err;
 
-       mutex_lock(&ocelot->stats_lock);
+       spin_lock(&ocelot->stats_lock);
 
        /* check and update now */
        err = ocelot_port_update_stats(ocelot, port);
 
-       /* Copy all counters */
-       for (i = 0; i < ocelot->num_stats; i++)
-               *data++ = ocelot->stats[port * ocelot->num_stats + i];
+       /* Copy all supported counters */
+       for (i = 0; i < OCELOT_NUM_STATS; i++) {
+               int index = port * OCELOT_NUM_STATS + i;
+
+               if (ocelot->stats_layout[i].name[0] == '\0')
+                       continue;
+
+               *data++ = ocelot->stats[index];
+       }
 
-       mutex_unlock(&ocelot->stats_lock);
+       spin_unlock(&ocelot->stats_lock);
 
        if (err)
                dev_err(ocelot->dev, "Error %d updating ethtool stats\n", err);
@@ -1943,10 +1952,16 @@ EXPORT_SYMBOL(ocelot_get_ethtool_stats);
 
 int ocelot_get_sset_count(struct ocelot *ocelot, int port, int sset)
 {
+       int i, num_stats = 0;
+
        if (sset != ETH_SS_STATS)
                return -EOPNOTSUPP;
 
-       return ocelot->num_stats;
+       for (i = 0; i < OCELOT_NUM_STATS; i++)
+               if (ocelot->stats_layout[i].name[0] != '\0')
+                       num_stats++;
+
+       return num_stats;
 }
 EXPORT_SYMBOL(ocelot_get_sset_count);
 
@@ -1958,8 +1973,11 @@ static int ocelot_prepare_stats_regions(struct ocelot *ocelot)
 
        INIT_LIST_HEAD(&ocelot->stats_regions);
 
-       for (i = 0; i < ocelot->num_stats; i++) {
-               if (region && ocelot->stats_layout[i].offset == last + 1) {
+       for (i = 0; i < OCELOT_NUM_STATS; i++) {
+               if (ocelot->stats_layout[i].name[0] == '\0')
+                       continue;
+
+               if (region && ocelot->stats_layout[i].reg == last + 4) {
                        region->count++;
                } else {
                        region = devm_kzalloc(ocelot->dev, sizeof(*region),
@@ -1967,12 +1985,12 @@ static int ocelot_prepare_stats_regions(struct ocelot *ocelot)
                        if (!region)
                                return -ENOMEM;
 
-                       region->offset = ocelot->stats_layout[i].offset;
+                       region->base = ocelot->stats_layout[i].reg;
                        region->count = 1;
                        list_add_tail(&region->node, &ocelot->stats_regions);
                }
 
-               last = ocelot->stats_layout[i].offset;
+               last = ocelot->stats_layout[i].reg;
        }
 
        list_for_each_entry(region, &ocelot->stats_regions, node) {
@@ -3340,7 +3358,6 @@ static void ocelot_detect_features(struct ocelot *ocelot)
 
 int ocelot_init(struct ocelot *ocelot)
 {
-       const struct ocelot_stat_layout *stat;
        char queue_name[32];
        int i, ret;
        u32 port;
@@ -3353,17 +3370,13 @@ int ocelot_init(struct ocelot *ocelot)
                }
        }
 
-       ocelot->num_stats = 0;
-       for_each_stat(ocelot, stat)
-               ocelot->num_stats++;
-
        ocelot->stats = devm_kcalloc(ocelot->dev,
-                                    ocelot->num_phys_ports * ocelot->num_stats,
+                                    ocelot->num_phys_ports * OCELOT_NUM_STATS,
                                     sizeof(u64), GFP_KERNEL);
        if (!ocelot->stats)
                return -ENOMEM;
 
-       mutex_init(&ocelot->stats_lock);
+       spin_lock_init(&ocelot->stats_lock);
        mutex_init(&ocelot->ptp_lock);
        mutex_init(&ocelot->mact_lock);
        mutex_init(&ocelot->fwd_domain_lock);
@@ -3511,7 +3524,6 @@ void ocelot_deinit(struct ocelot *ocelot)
        cancel_delayed_work(&ocelot->stats_work);
        destroy_workqueue(ocelot->stats_queue);
        destroy_workqueue(ocelot->owq);
-       mutex_destroy(&ocelot->stats_lock);
 }
 EXPORT_SYMBOL(ocelot_deinit);
 
index 5e6136e..330d308 100644 (file)
@@ -725,37 +725,42 @@ static void ocelot_get_stats64(struct net_device *dev,
        struct ocelot_port_private *priv = netdev_priv(dev);
        struct ocelot *ocelot = priv->port.ocelot;
        int port = priv->port.index;
+       u64 *s;
 
-       /* Configure the port to read the stats from */
-       ocelot_write(ocelot, SYS_STAT_CFG_STAT_VIEW(port),
-                    SYS_STAT_CFG);
+       spin_lock(&ocelot->stats_lock);
+
+       s = &ocelot->stats[port * OCELOT_NUM_STATS];
 
        /* Get Rx stats */
-       stats->rx_bytes = ocelot_read(ocelot, SYS_COUNT_RX_OCTETS);
-       stats->rx_packets = ocelot_read(ocelot, SYS_COUNT_RX_SHORTS) +
-                           ocelot_read(ocelot, SYS_COUNT_RX_FRAGMENTS) +
-                           ocelot_read(ocelot, SYS_COUNT_RX_JABBERS) +
-                           ocelot_read(ocelot, SYS_COUNT_RX_LONGS) +
-                           ocelot_read(ocelot, SYS_COUNT_RX_64) +
-                           ocelot_read(ocelot, SYS_COUNT_RX_65_127) +
-                           ocelot_read(ocelot, SYS_COUNT_RX_128_255) +
-                           ocelot_read(ocelot, SYS_COUNT_RX_256_1023) +
-                           ocelot_read(ocelot, SYS_COUNT_RX_1024_1526) +
-                           ocelot_read(ocelot, SYS_COUNT_RX_1527_MAX);
-       stats->multicast = ocelot_read(ocelot, SYS_COUNT_RX_MULTICAST);
+       stats->rx_bytes = s[OCELOT_STAT_RX_OCTETS];
+       stats->rx_packets = s[OCELOT_STAT_RX_SHORTS] +
+                           s[OCELOT_STAT_RX_FRAGMENTS] +
+                           s[OCELOT_STAT_RX_JABBERS] +
+                           s[OCELOT_STAT_RX_LONGS] +
+                           s[OCELOT_STAT_RX_64] +
+                           s[OCELOT_STAT_RX_65_127] +
+                           s[OCELOT_STAT_RX_128_255] +
+                           s[OCELOT_STAT_RX_256_511] +
+                           s[OCELOT_STAT_RX_512_1023] +
+                           s[OCELOT_STAT_RX_1024_1526] +
+                           s[OCELOT_STAT_RX_1527_MAX];
+       stats->multicast = s[OCELOT_STAT_RX_MULTICAST];
        stats->rx_dropped = dev->stats.rx_dropped;
 
        /* Get Tx stats */
-       stats->tx_bytes = ocelot_read(ocelot, SYS_COUNT_TX_OCTETS);
-       stats->tx_packets = ocelot_read(ocelot, SYS_COUNT_TX_64) +
-                           ocelot_read(ocelot, SYS_COUNT_TX_65_127) +
-                           ocelot_read(ocelot, SYS_COUNT_TX_128_511) +
-                           ocelot_read(ocelot, SYS_COUNT_TX_512_1023) +
-                           ocelot_read(ocelot, SYS_COUNT_TX_1024_1526) +
-                           ocelot_read(ocelot, SYS_COUNT_TX_1527_MAX);
-       stats->tx_dropped = ocelot_read(ocelot, SYS_COUNT_TX_DROPS) +
-                           ocelot_read(ocelot, SYS_COUNT_TX_AGING);
-       stats->collisions = ocelot_read(ocelot, SYS_COUNT_TX_COLLISION);
+       stats->tx_bytes = s[OCELOT_STAT_TX_OCTETS];
+       stats->tx_packets = s[OCELOT_STAT_TX_64] +
+                           s[OCELOT_STAT_TX_65_127] +
+                           s[OCELOT_STAT_TX_128_255] +
+                           s[OCELOT_STAT_TX_256_511] +
+                           s[OCELOT_STAT_TX_512_1023] +
+                           s[OCELOT_STAT_TX_1024_1526] +
+                           s[OCELOT_STAT_TX_1527_MAX];
+       stats->tx_dropped = s[OCELOT_STAT_TX_DROPS] +
+                           s[OCELOT_STAT_TX_AGED];
+       stats->collisions = s[OCELOT_STAT_TX_COLLISION];
+
+       spin_unlock(&ocelot->stats_lock);
 }
 
 static int ocelot_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
index 961f803..9c48895 100644 (file)
@@ -96,101 +96,379 @@ static const struct reg_field ocelot_regfields[REGFIELD_MAX] = {
        [SYS_PAUSE_CFG_PAUSE_ENA] = REG_FIELD_ID(SYS_PAUSE_CFG, 0, 1, 12, 4),
 };
 
-static const struct ocelot_stat_layout ocelot_stats_layout[] = {
-       { .name = "rx_octets", .offset = 0x00, },
-       { .name = "rx_unicast", .offset = 0x01, },
-       { .name = "rx_multicast", .offset = 0x02, },
-       { .name = "rx_broadcast", .offset = 0x03, },
-       { .name = "rx_shorts", .offset = 0x04, },
-       { .name = "rx_fragments", .offset = 0x05, },
-       { .name = "rx_jabbers", .offset = 0x06, },
-       { .name = "rx_crc_align_errs", .offset = 0x07, },
-       { .name = "rx_sym_errs", .offset = 0x08, },
-       { .name = "rx_frames_below_65_octets", .offset = 0x09, },
-       { .name = "rx_frames_65_to_127_octets", .offset = 0x0A, },
-       { .name = "rx_frames_128_to_255_octets", .offset = 0x0B, },
-       { .name = "rx_frames_256_to_511_octets", .offset = 0x0C, },
-       { .name = "rx_frames_512_to_1023_octets", .offset = 0x0D, },
-       { .name = "rx_frames_1024_to_1526_octets", .offset = 0x0E, },
-       { .name = "rx_frames_over_1526_octets", .offset = 0x0F, },
-       { .name = "rx_pause", .offset = 0x10, },
-       { .name = "rx_control", .offset = 0x11, },
-       { .name = "rx_longs", .offset = 0x12, },
-       { .name = "rx_classified_drops", .offset = 0x13, },
-       { .name = "rx_red_prio_0", .offset = 0x14, },
-       { .name = "rx_red_prio_1", .offset = 0x15, },
-       { .name = "rx_red_prio_2", .offset = 0x16, },
-       { .name = "rx_red_prio_3", .offset = 0x17, },
-       { .name = "rx_red_prio_4", .offset = 0x18, },
-       { .name = "rx_red_prio_5", .offset = 0x19, },
-       { .name = "rx_red_prio_6", .offset = 0x1A, },
-       { .name = "rx_red_prio_7", .offset = 0x1B, },
-       { .name = "rx_yellow_prio_0", .offset = 0x1C, },
-       { .name = "rx_yellow_prio_1", .offset = 0x1D, },
-       { .name = "rx_yellow_prio_2", .offset = 0x1E, },
-       { .name = "rx_yellow_prio_3", .offset = 0x1F, },
-       { .name = "rx_yellow_prio_4", .offset = 0x20, },
-       { .name = "rx_yellow_prio_5", .offset = 0x21, },
-       { .name = "rx_yellow_prio_6", .offset = 0x22, },
-       { .name = "rx_yellow_prio_7", .offset = 0x23, },
-       { .name = "rx_green_prio_0", .offset = 0x24, },
-       { .name = "rx_green_prio_1", .offset = 0x25, },
-       { .name = "rx_green_prio_2", .offset = 0x26, },
-       { .name = "rx_green_prio_3", .offset = 0x27, },
-       { .name = "rx_green_prio_4", .offset = 0x28, },
-       { .name = "rx_green_prio_5", .offset = 0x29, },
-       { .name = "rx_green_prio_6", .offset = 0x2A, },
-       { .name = "rx_green_prio_7", .offset = 0x2B, },
-       { .name = "tx_octets", .offset = 0x40, },
-       { .name = "tx_unicast", .offset = 0x41, },
-       { .name = "tx_multicast", .offset = 0x42, },
-       { .name = "tx_broadcast", .offset = 0x43, },
-       { .name = "tx_collision", .offset = 0x44, },
-       { .name = "tx_drops", .offset = 0x45, },
-       { .name = "tx_pause", .offset = 0x46, },
-       { .name = "tx_frames_below_65_octets", .offset = 0x47, },
-       { .name = "tx_frames_65_to_127_octets", .offset = 0x48, },
-       { .name = "tx_frames_128_255_octets", .offset = 0x49, },
-       { .name = "tx_frames_256_511_octets", .offset = 0x4A, },
-       { .name = "tx_frames_512_1023_octets", .offset = 0x4B, },
-       { .name = "tx_frames_1024_1526_octets", .offset = 0x4C, },
-       { .name = "tx_frames_over_1526_octets", .offset = 0x4D, },
-       { .name = "tx_yellow_prio_0", .offset = 0x4E, },
-       { .name = "tx_yellow_prio_1", .offset = 0x4F, },
-       { .name = "tx_yellow_prio_2", .offset = 0x50, },
-       { .name = "tx_yellow_prio_3", .offset = 0x51, },
-       { .name = "tx_yellow_prio_4", .offset = 0x52, },
-       { .name = "tx_yellow_prio_5", .offset = 0x53, },
-       { .name = "tx_yellow_prio_6", .offset = 0x54, },
-       { .name = "tx_yellow_prio_7", .offset = 0x55, },
-       { .name = "tx_green_prio_0", .offset = 0x56, },
-       { .name = "tx_green_prio_1", .offset = 0x57, },
-       { .name = "tx_green_prio_2", .offset = 0x58, },
-       { .name = "tx_green_prio_3", .offset = 0x59, },
-       { .name = "tx_green_prio_4", .offset = 0x5A, },
-       { .name = "tx_green_prio_5", .offset = 0x5B, },
-       { .name = "tx_green_prio_6", .offset = 0x5C, },
-       { .name = "tx_green_prio_7", .offset = 0x5D, },
-       { .name = "tx_aged", .offset = 0x5E, },
-       { .name = "drop_local", .offset = 0x80, },
-       { .name = "drop_tail", .offset = 0x81, },
-       { .name = "drop_yellow_prio_0", .offset = 0x82, },
-       { .name = "drop_yellow_prio_1", .offset = 0x83, },
-       { .name = "drop_yellow_prio_2", .offset = 0x84, },
-       { .name = "drop_yellow_prio_3", .offset = 0x85, },
-       { .name = "drop_yellow_prio_4", .offset = 0x86, },
-       { .name = "drop_yellow_prio_5", .offset = 0x87, },
-       { .name = "drop_yellow_prio_6", .offset = 0x88, },
-       { .name = "drop_yellow_prio_7", .offset = 0x89, },
-       { .name = "drop_green_prio_0", .offset = 0x8A, },
-       { .name = "drop_green_prio_1", .offset = 0x8B, },
-       { .name = "drop_green_prio_2", .offset = 0x8C, },
-       { .name = "drop_green_prio_3", .offset = 0x8D, },
-       { .name = "drop_green_prio_4", .offset = 0x8E, },
-       { .name = "drop_green_prio_5", .offset = 0x8F, },
-       { .name = "drop_green_prio_6", .offset = 0x90, },
-       { .name = "drop_green_prio_7", .offset = 0x91, },
-       OCELOT_STAT_END
+static const struct ocelot_stat_layout ocelot_stats_layout[OCELOT_NUM_STATS] = {
+       [OCELOT_STAT_RX_OCTETS] = {
+               .name = "rx_octets",
+               .reg = SYS_COUNT_RX_OCTETS,
+       },
+       [OCELOT_STAT_RX_UNICAST] = {
+               .name = "rx_unicast",
+               .reg = SYS_COUNT_RX_UNICAST,
+       },
+       [OCELOT_STAT_RX_MULTICAST] = {
+               .name = "rx_multicast",
+               .reg = SYS_COUNT_RX_MULTICAST,
+       },
+       [OCELOT_STAT_RX_BROADCAST] = {
+               .name = "rx_broadcast",
+               .reg = SYS_COUNT_RX_BROADCAST,
+       },
+       [OCELOT_STAT_RX_SHORTS] = {
+               .name = "rx_shorts",
+               .reg = SYS_COUNT_RX_SHORTS,
+       },
+       [OCELOT_STAT_RX_FRAGMENTS] = {
+               .name = "rx_fragments",
+               .reg = SYS_COUNT_RX_FRAGMENTS,
+       },
+       [OCELOT_STAT_RX_JABBERS] = {
+               .name = "rx_jabbers",
+               .reg = SYS_COUNT_RX_JABBERS,
+       },
+       [OCELOT_STAT_RX_CRC_ALIGN_ERRS] = {
+               .name = "rx_crc_align_errs",
+               .reg = SYS_COUNT_RX_CRC_ALIGN_ERRS,
+       },
+       [OCELOT_STAT_RX_SYM_ERRS] = {
+               .name = "rx_sym_errs",
+               .reg = SYS_COUNT_RX_SYM_ERRS,
+       },
+       [OCELOT_STAT_RX_64] = {
+               .name = "rx_frames_below_65_octets",
+               .reg = SYS_COUNT_RX_64,
+       },
+       [OCELOT_STAT_RX_65_127] = {
+               .name = "rx_frames_65_to_127_octets",
+               .reg = SYS_COUNT_RX_65_127,
+       },
+       [OCELOT_STAT_RX_128_255] = {
+               .name = "rx_frames_128_to_255_octets",
+               .reg = SYS_COUNT_RX_128_255,
+       },
+       [OCELOT_STAT_RX_256_511] = {
+               .name = "rx_frames_256_to_511_octets",
+               .reg = SYS_COUNT_RX_256_511,
+       },
+       [OCELOT_STAT_RX_512_1023] = {
+               .name = "rx_frames_512_to_1023_octets",
+               .reg = SYS_COUNT_RX_512_1023,
+       },
+       [OCELOT_STAT_RX_1024_1526] = {
+               .name = "rx_frames_1024_to_1526_octets",
+               .reg = SYS_COUNT_RX_1024_1526,
+       },
+       [OCELOT_STAT_RX_1527_MAX] = {
+               .name = "rx_frames_over_1526_octets",
+               .reg = SYS_COUNT_RX_1527_MAX,
+       },
+       [OCELOT_STAT_RX_PAUSE] = {
+               .name = "rx_pause",
+               .reg = SYS_COUNT_RX_PAUSE,
+       },
+       [OCELOT_STAT_RX_CONTROL] = {
+               .name = "rx_control",
+               .reg = SYS_COUNT_RX_CONTROL,
+       },
+       [OCELOT_STAT_RX_LONGS] = {
+               .name = "rx_longs",
+               .reg = SYS_COUNT_RX_LONGS,
+       },
+       [OCELOT_STAT_RX_CLASSIFIED_DROPS] = {
+               .name = "rx_classified_drops",
+               .reg = SYS_COUNT_RX_CLASSIFIED_DROPS,
+       },
+       [OCELOT_STAT_RX_RED_PRIO_0] = {
+               .name = "rx_red_prio_0",
+               .reg = SYS_COUNT_RX_RED_PRIO_0,
+       },
+       [OCELOT_STAT_RX_RED_PRIO_1] = {
+               .name = "rx_red_prio_1",
+               .reg = SYS_COUNT_RX_RED_PRIO_1,
+       },
+       [OCELOT_STAT_RX_RED_PRIO_2] = {
+               .name = "rx_red_prio_2",
+               .reg = SYS_COUNT_RX_RED_PRIO_2,
+       },
+       [OCELOT_STAT_RX_RED_PRIO_3] = {
+               .name = "rx_red_prio_3",
+               .reg = SYS_COUNT_RX_RED_PRIO_3,
+       },
+       [OCELOT_STAT_RX_RED_PRIO_4] = {
+               .name = "rx_red_prio_4",
+               .reg = SYS_COUNT_RX_RED_PRIO_4,
+       },
+       [OCELOT_STAT_RX_RED_PRIO_5] = {
+               .name = "rx_red_prio_5",
+               .reg = SYS_COUNT_RX_RED_PRIO_5,
+       },
+       [OCELOT_STAT_RX_RED_PRIO_6] = {
+               .name = "rx_red_prio_6",
+               .reg = SYS_COUNT_RX_RED_PRIO_6,
+       },
+       [OCELOT_STAT_RX_RED_PRIO_7] = {
+               .name = "rx_red_prio_7",
+               .reg = SYS_COUNT_RX_RED_PRIO_7,
+       },
+       [OCELOT_STAT_RX_YELLOW_PRIO_0] = {
+               .name = "rx_yellow_prio_0",
+               .reg = SYS_COUNT_RX_YELLOW_PRIO_0,
+       },
+       [OCELOT_STAT_RX_YELLOW_PRIO_1] = {
+               .name = "rx_yellow_prio_1",
+               .reg = SYS_COUNT_RX_YELLOW_PRIO_1,
+       },
+       [OCELOT_STAT_RX_YELLOW_PRIO_2] = {
+               .name = "rx_yellow_prio_2",
+               .reg = SYS_COUNT_RX_YELLOW_PRIO_2,
+       },
+       [OCELOT_STAT_RX_YELLOW_PRIO_3] = {
+               .name = "rx_yellow_prio_3",
+               .reg = SYS_COUNT_RX_YELLOW_PRIO_3,
+       },
+       [OCELOT_STAT_RX_YELLOW_PRIO_4] = {
+               .name = "rx_yellow_prio_4",
+               .reg = SYS_COUNT_RX_YELLOW_PRIO_4,
+       },
+       [OCELOT_STAT_RX_YELLOW_PRIO_5] = {
+               .name = "rx_yellow_prio_5",
+               .reg = SYS_COUNT_RX_YELLOW_PRIO_5,
+       },
+       [OCELOT_STAT_RX_YELLOW_PRIO_6] = {
+               .name = "rx_yellow_prio_6",
+               .reg = SYS_COUNT_RX_YELLOW_PRIO_6,
+       },
+       [OCELOT_STAT_RX_YELLOW_PRIO_7] = {
+               .name = "rx_yellow_prio_7",
+               .reg = SYS_COUNT_RX_YELLOW_PRIO_7,
+       },
+       [OCELOT_STAT_RX_GREEN_PRIO_0] = {
+               .name = "rx_green_prio_0",
+               .reg = SYS_COUNT_RX_GREEN_PRIO_0,
+       },
+       [OCELOT_STAT_RX_GREEN_PRIO_1] = {
+               .name = "rx_green_prio_1",
+               .reg = SYS_COUNT_RX_GREEN_PRIO_1,
+       },
+       [OCELOT_STAT_RX_GREEN_PRIO_2] = {
+               .name = "rx_green_prio_2",
+               .reg = SYS_COUNT_RX_GREEN_PRIO_2,
+       },
+       [OCELOT_STAT_RX_GREEN_PRIO_3] = {
+               .name = "rx_green_prio_3",
+               .reg = SYS_COUNT_RX_GREEN_PRIO_3,
+       },
+       [OCELOT_STAT_RX_GREEN_PRIO_4] = {
+               .name = "rx_green_prio_4",
+               .reg = SYS_COUNT_RX_GREEN_PRIO_4,
+       },
+       [OCELOT_STAT_RX_GREEN_PRIO_5] = {
+               .name = "rx_green_prio_5",
+               .reg = SYS_COUNT_RX_GREEN_PRIO_5,
+       },
+       [OCELOT_STAT_RX_GREEN_PRIO_6] = {
+               .name = "rx_green_prio_6",
+               .reg = SYS_COUNT_RX_GREEN_PRIO_6,
+       },
+       [OCELOT_STAT_RX_GREEN_PRIO_7] = {
+               .name = "rx_green_prio_7",
+               .reg = SYS_COUNT_RX_GREEN_PRIO_7,
+       },
+       [OCELOT_STAT_TX_OCTETS] = {
+               .name = "tx_octets",
+               .reg = SYS_COUNT_TX_OCTETS,
+       },
+       [OCELOT_STAT_TX_UNICAST] = {
+               .name = "tx_unicast",
+               .reg = SYS_COUNT_TX_UNICAST,
+       },
+       [OCELOT_STAT_TX_MULTICAST] = {
+               .name = "tx_multicast",
+               .reg = SYS_COUNT_TX_MULTICAST,
+       },
+       [OCELOT_STAT_TX_BROADCAST] = {
+               .name = "tx_broadcast",
+               .reg = SYS_COUNT_TX_BROADCAST,
+       },
+       [OCELOT_STAT_TX_COLLISION] = {
+               .name = "tx_collision",
+               .reg = SYS_COUNT_TX_COLLISION,
+       },
+       [OCELOT_STAT_TX_DROPS] = {
+               .name = "tx_drops",
+               .reg = SYS_COUNT_TX_DROPS,
+       },
+       [OCELOT_STAT_TX_PAUSE] = {
+               .name = "tx_pause",
+               .reg = SYS_COUNT_TX_PAUSE,
+       },
+       [OCELOT_STAT_TX_64] = {
+               .name = "tx_frames_below_65_octets",
+               .reg = SYS_COUNT_TX_64,
+       },
+       [OCELOT_STAT_TX_65_127] = {
+               .name = "tx_frames_65_to_127_octets",
+               .reg = SYS_COUNT_TX_65_127,
+       },
+       [OCELOT_STAT_TX_128_255] = {
+               .name = "tx_frames_128_255_octets",
+               .reg = SYS_COUNT_TX_128_255,
+       },
+       [OCELOT_STAT_TX_256_511] = {
+               .name = "tx_frames_256_511_octets",
+               .reg = SYS_COUNT_TX_256_511,
+       },
+       [OCELOT_STAT_TX_512_1023] = {
+               .name = "tx_frames_512_1023_octets",
+               .reg = SYS_COUNT_TX_512_1023,
+       },
+       [OCELOT_STAT_TX_1024_1526] = {
+               .name = "tx_frames_1024_1526_octets",
+               .reg = SYS_COUNT_TX_1024_1526,
+       },
+       [OCELOT_STAT_TX_1527_MAX] = {
+               .name = "tx_frames_over_1526_octets",
+               .reg = SYS_COUNT_TX_1527_MAX,
+       },
+       [OCELOT_STAT_TX_YELLOW_PRIO_0] = {
+               .name = "tx_yellow_prio_0",
+               .reg = SYS_COUNT_TX_YELLOW_PRIO_0,
+       },
+       [OCELOT_STAT_TX_YELLOW_PRIO_1] = {
+               .name = "tx_yellow_prio_1",
+               .reg = SYS_COUNT_TX_YELLOW_PRIO_1,
+       },
+       [OCELOT_STAT_TX_YELLOW_PRIO_2] = {
+               .name = "tx_yellow_prio_2",
+               .reg = SYS_COUNT_TX_YELLOW_PRIO_2,
+       },
+       [OCELOT_STAT_TX_YELLOW_PRIO_3] = {
+               .name = "tx_yellow_prio_3",
+               .reg = SYS_COUNT_TX_YELLOW_PRIO_3,
+       },
+       [OCELOT_STAT_TX_YELLOW_PRIO_4] = {
+               .name = "tx_yellow_prio_4",
+               .reg = SYS_COUNT_TX_YELLOW_PRIO_4,
+       },
+       [OCELOT_STAT_TX_YELLOW_PRIO_5] = {
+               .name = "tx_yellow_prio_5",
+               .reg = SYS_COUNT_TX_YELLOW_PRIO_5,
+       },
+       [OCELOT_STAT_TX_YELLOW_PRIO_6] = {
+               .name = "tx_yellow_prio_6",
+               .reg = SYS_COUNT_TX_YELLOW_PRIO_6,
+       },
+       [OCELOT_STAT_TX_YELLOW_PRIO_7] = {
+               .name = "tx_yellow_prio_7",
+               .reg = SYS_COUNT_TX_YELLOW_PRIO_7,
+       },
+       [OCELOT_STAT_TX_GREEN_PRIO_0] = {
+               .name = "tx_green_prio_0",
+               .reg = SYS_COUNT_TX_GREEN_PRIO_0,
+       },
+       [OCELOT_STAT_TX_GREEN_PRIO_1] = {
+               .name = "tx_green_prio_1",
+               .reg = SYS_COUNT_TX_GREEN_PRIO_1,
+       },
+       [OCELOT_STAT_TX_GREEN_PRIO_2] = {
+               .name = "tx_green_prio_2",
+               .reg = SYS_COUNT_TX_GREEN_PRIO_2,
+       },
+       [OCELOT_STAT_TX_GREEN_PRIO_3] = {
+               .name = "tx_green_prio_3",
+               .reg = SYS_COUNT_TX_GREEN_PRIO_3,
+       },
+       [OCELOT_STAT_TX_GREEN_PRIO_4] = {
+               .name = "tx_green_prio_4",
+               .reg = SYS_COUNT_TX_GREEN_PRIO_4,
+       },
+       [OCELOT_STAT_TX_GREEN_PRIO_5] = {
+               .name = "tx_green_prio_5",
+               .reg = SYS_COUNT_TX_GREEN_PRIO_5,
+       },
+       [OCELOT_STAT_TX_GREEN_PRIO_6] = {
+               .name = "tx_green_prio_6",
+               .reg = SYS_COUNT_TX_GREEN_PRIO_6,
+       },
+       [OCELOT_STAT_TX_GREEN_PRIO_7] = {
+               .name = "tx_green_prio_7",
+               .reg = SYS_COUNT_TX_GREEN_PRIO_7,
+       },
+       [OCELOT_STAT_TX_AGED] = {
+               .name = "tx_aged",
+               .reg = SYS_COUNT_TX_AGING,
+       },
+       [OCELOT_STAT_DROP_LOCAL] = {
+               .name = "drop_local",
+               .reg = SYS_COUNT_DROP_LOCAL,
+       },
+       [OCELOT_STAT_DROP_TAIL] = {
+               .name = "drop_tail",
+               .reg = SYS_COUNT_DROP_TAIL,
+       },
+       [OCELOT_STAT_DROP_YELLOW_PRIO_0] = {
+               .name = "drop_yellow_prio_0",
+               .reg = SYS_COUNT_DROP_YELLOW_PRIO_0,
+       },
+       [OCELOT_STAT_DROP_YELLOW_PRIO_1] = {
+               .name = "drop_yellow_prio_1",
+               .reg = SYS_COUNT_DROP_YELLOW_PRIO_1,
+       },
+       [OCELOT_STAT_DROP_YELLOW_PRIO_2] = {
+               .name = "drop_yellow_prio_2",
+               .reg = SYS_COUNT_DROP_YELLOW_PRIO_2,
+       },
+       [OCELOT_STAT_DROP_YELLOW_PRIO_3] = {
+               .name = "drop_yellow_prio_3",
+               .reg = SYS_COUNT_DROP_YELLOW_PRIO_3,
+       },
+       [OCELOT_STAT_DROP_YELLOW_PRIO_4] = {
+               .name = "drop_yellow_prio_4",
+               .reg = SYS_COUNT_DROP_YELLOW_PRIO_4,
+       },
+       [OCELOT_STAT_DROP_YELLOW_PRIO_5] = {
+               .name = "drop_yellow_prio_5",
+               .reg = SYS_COUNT_DROP_YELLOW_PRIO_5,
+       },
+       [OCELOT_STAT_DROP_YELLOW_PRIO_6] = {
+               .name = "drop_yellow_prio_6",
+               .reg = SYS_COUNT_DROP_YELLOW_PRIO_6,
+       },
+       [OCELOT_STAT_DROP_YELLOW_PRIO_7] = {
+               .name = "drop_yellow_prio_7",
+               .reg = SYS_COUNT_DROP_YELLOW_PRIO_7,
+       },
+       [OCELOT_STAT_DROP_GREEN_PRIO_0] = {
+               .name = "drop_green_prio_0",
+               .reg = SYS_COUNT_DROP_GREEN_PRIO_0,
+       },
+       [OCELOT_STAT_DROP_GREEN_PRIO_1] = {
+               .name = "drop_green_prio_1",
+               .reg = SYS_COUNT_DROP_GREEN_PRIO_1,
+       },
+       [OCELOT_STAT_DROP_GREEN_PRIO_2] = {
+               .name = "drop_green_prio_2",
+               .reg = SYS_COUNT_DROP_GREEN_PRIO_2,
+       },
+       [OCELOT_STAT_DROP_GREEN_PRIO_3] = {
+               .name = "drop_green_prio_3",
+               .reg = SYS_COUNT_DROP_GREEN_PRIO_3,
+       },
+       [OCELOT_STAT_DROP_GREEN_PRIO_4] = {
+               .name = "drop_green_prio_4",
+               .reg = SYS_COUNT_DROP_GREEN_PRIO_4,
+       },
+       [OCELOT_STAT_DROP_GREEN_PRIO_5] = {
+               .name = "drop_green_prio_5",
+               .reg = SYS_COUNT_DROP_GREEN_PRIO_5,
+       },
+       [OCELOT_STAT_DROP_GREEN_PRIO_6] = {
+               .name = "drop_green_prio_6",
+               .reg = SYS_COUNT_DROP_GREEN_PRIO_6,
+       },
+       [OCELOT_STAT_DROP_GREEN_PRIO_7] = {
+               .name = "drop_green_prio_7",
+               .reg = SYS_COUNT_DROP_GREEN_PRIO_7,
+       },
 };
 
 static void ocelot_pll5_init(struct ocelot *ocelot)
index c2af4eb..9cf82ec 100644 (file)
@@ -180,13 +180,38 @@ const u32 vsc7514_sys_regmap[] = {
        REG(SYS_COUNT_RX_64,                            0x000024),
        REG(SYS_COUNT_RX_65_127,                        0x000028),
        REG(SYS_COUNT_RX_128_255,                       0x00002c),
-       REG(SYS_COUNT_RX_256_1023,                      0x000030),
-       REG(SYS_COUNT_RX_1024_1526,                     0x000034),
-       REG(SYS_COUNT_RX_1527_MAX,                      0x000038),
-       REG(SYS_COUNT_RX_PAUSE,                         0x00003c),
-       REG(SYS_COUNT_RX_CONTROL,                       0x000040),
-       REG(SYS_COUNT_RX_LONGS,                         0x000044),
-       REG(SYS_COUNT_RX_CLASSIFIED_DROPS,              0x000048),
+       REG(SYS_COUNT_RX_256_511,                       0x000030),
+       REG(SYS_COUNT_RX_512_1023,                      0x000034),
+       REG(SYS_COUNT_RX_1024_1526,                     0x000038),
+       REG(SYS_COUNT_RX_1527_MAX,                      0x00003c),
+       REG(SYS_COUNT_RX_PAUSE,                         0x000040),
+       REG(SYS_COUNT_RX_CONTROL,                       0x000044),
+       REG(SYS_COUNT_RX_LONGS,                         0x000048),
+       REG(SYS_COUNT_RX_CLASSIFIED_DROPS,              0x00004c),
+       REG(SYS_COUNT_RX_RED_PRIO_0,                    0x000050),
+       REG(SYS_COUNT_RX_RED_PRIO_1,                    0x000054),
+       REG(SYS_COUNT_RX_RED_PRIO_2,                    0x000058),
+       REG(SYS_COUNT_RX_RED_PRIO_3,                    0x00005c),
+       REG(SYS_COUNT_RX_RED_PRIO_4,                    0x000060),
+       REG(SYS_COUNT_RX_RED_PRIO_5,                    0x000064),
+       REG(SYS_COUNT_RX_RED_PRIO_6,                    0x000068),
+       REG(SYS_COUNT_RX_RED_PRIO_7,                    0x00006c),
+       REG(SYS_COUNT_RX_YELLOW_PRIO_0,                 0x000070),
+       REG(SYS_COUNT_RX_YELLOW_PRIO_1,                 0x000074),
+       REG(SYS_COUNT_RX_YELLOW_PRIO_2,                 0x000078),
+       REG(SYS_COUNT_RX_YELLOW_PRIO_3,                 0x00007c),
+       REG(SYS_COUNT_RX_YELLOW_PRIO_4,                 0x000080),
+       REG(SYS_COUNT_RX_YELLOW_PRIO_5,                 0x000084),
+       REG(SYS_COUNT_RX_YELLOW_PRIO_6,                 0x000088),
+       REG(SYS_COUNT_RX_YELLOW_PRIO_7,                 0x00008c),
+       REG(SYS_COUNT_RX_GREEN_PRIO_0,                  0x000090),
+       REG(SYS_COUNT_RX_GREEN_PRIO_1,                  0x000094),
+       REG(SYS_COUNT_RX_GREEN_PRIO_2,                  0x000098),
+       REG(SYS_COUNT_RX_GREEN_PRIO_3,                  0x00009c),
+       REG(SYS_COUNT_RX_GREEN_PRIO_4,                  0x0000a0),
+       REG(SYS_COUNT_RX_GREEN_PRIO_5,                  0x0000a4),
+       REG(SYS_COUNT_RX_GREEN_PRIO_6,                  0x0000a8),
+       REG(SYS_COUNT_RX_GREEN_PRIO_7,                  0x0000ac),
        REG(SYS_COUNT_TX_OCTETS,                        0x000100),
        REG(SYS_COUNT_TX_UNICAST,                       0x000104),
        REG(SYS_COUNT_TX_MULTICAST,                     0x000108),
@@ -196,11 +221,46 @@ const u32 vsc7514_sys_regmap[] = {
        REG(SYS_COUNT_TX_PAUSE,                         0x000118),
        REG(SYS_COUNT_TX_64,                            0x00011c),
        REG(SYS_COUNT_TX_65_127,                        0x000120),
-       REG(SYS_COUNT_TX_128_511,                       0x000124),
-       REG(SYS_COUNT_TX_512_1023,                      0x000128),
-       REG(SYS_COUNT_TX_1024_1526,                     0x00012c),
-       REG(SYS_COUNT_TX_1527_MAX,                      0x000130),
-       REG(SYS_COUNT_TX_AGING,                         0x000170),
+       REG(SYS_COUNT_TX_128_255,                       0x000124),
+       REG(SYS_COUNT_TX_256_511,                       0x000128),
+       REG(SYS_COUNT_TX_512_1023,                      0x00012c),
+       REG(SYS_COUNT_TX_1024_1526,                     0x000130),
+       REG(SYS_COUNT_TX_1527_MAX,                      0x000134),
+       REG(SYS_COUNT_TX_YELLOW_PRIO_0,                 0x000138),
+       REG(SYS_COUNT_TX_YELLOW_PRIO_1,                 0x00013c),
+       REG(SYS_COUNT_TX_YELLOW_PRIO_2,                 0x000140),
+       REG(SYS_COUNT_TX_YELLOW_PRIO_3,                 0x000144),
+       REG(SYS_COUNT_TX_YELLOW_PRIO_4,                 0x000148),
+       REG(SYS_COUNT_TX_YELLOW_PRIO_5,                 0x00014c),
+       REG(SYS_COUNT_TX_YELLOW_PRIO_6,                 0x000150),
+       REG(SYS_COUNT_TX_YELLOW_PRIO_7,                 0x000154),
+       REG(SYS_COUNT_TX_GREEN_PRIO_0,                  0x000158),
+       REG(SYS_COUNT_TX_GREEN_PRIO_1,                  0x00015c),
+       REG(SYS_COUNT_TX_GREEN_PRIO_2,                  0x000160),
+       REG(SYS_COUNT_TX_GREEN_PRIO_3,                  0x000164),
+       REG(SYS_COUNT_TX_GREEN_PRIO_4,                  0x000168),
+       REG(SYS_COUNT_TX_GREEN_PRIO_5,                  0x00016c),
+       REG(SYS_COUNT_TX_GREEN_PRIO_6,                  0x000170),
+       REG(SYS_COUNT_TX_GREEN_PRIO_7,                  0x000174),
+       REG(SYS_COUNT_TX_AGING,                         0x000178),
+       REG(SYS_COUNT_DROP_LOCAL,                       0x000200),
+       REG(SYS_COUNT_DROP_TAIL,                        0x000204),
+       REG(SYS_COUNT_DROP_YELLOW_PRIO_0,               0x000208),
+       REG(SYS_COUNT_DROP_YELLOW_PRIO_1,               0x00020c),
+       REG(SYS_COUNT_DROP_YELLOW_PRIO_2,               0x000210),
+       REG(SYS_COUNT_DROP_YELLOW_PRIO_3,               0x000214),
+       REG(SYS_COUNT_DROP_YELLOW_PRIO_4,               0x000218),
+       REG(SYS_COUNT_DROP_YELLOW_PRIO_5,               0x00021c),
+       REG(SYS_COUNT_DROP_YELLOW_PRIO_6,               0x000220),
+       REG(SYS_COUNT_DROP_YELLOW_PRIO_7,               0x000214),
+       REG(SYS_COUNT_DROP_GREEN_PRIO_0,                0x000218),
+       REG(SYS_COUNT_DROP_GREEN_PRIO_1,                0x00021c),
+       REG(SYS_COUNT_DROP_GREEN_PRIO_2,                0x000220),
+       REG(SYS_COUNT_DROP_GREEN_PRIO_3,                0x000224),
+       REG(SYS_COUNT_DROP_GREEN_PRIO_4,                0x000228),
+       REG(SYS_COUNT_DROP_GREEN_PRIO_5,                0x00022c),
+       REG(SYS_COUNT_DROP_GREEN_PRIO_6,                0x000230),
+       REG(SYS_COUNT_DROP_GREEN_PRIO_7,                0x000234),
        REG(SYS_RESET_CFG,                              0x000508),
        REG(SYS_CMID,                                   0x00050c),
        REG(SYS_VLAN_ETYPE_CFG,                         0x000510),
index 4e5df9f..7b92026 100644 (file)
@@ -127,10 +127,11 @@ static int nfp_policer_validate(const struct flow_action *action,
                return -EOPNOTSUPP;
        }
 
-       if (act->police.notexceed.act_id != FLOW_ACTION_PIPE &&
+       if (act->police.notexceed.act_id != FLOW_ACTION_CONTINUE &&
+           act->police.notexceed.act_id != FLOW_ACTION_PIPE &&
            act->police.notexceed.act_id != FLOW_ACTION_ACCEPT) {
                NL_SET_ERR_MSG_MOD(extack,
-                                  "Offload not supported when conform action is not pipe or ok");
+                                  "Offload not supported when conform action is not continue, pipe or ok");
                return -EOPNOTSUPP;
        }
 
index cf4d6f1..349a2b1 100644 (file)
@@ -1630,21 +1630,21 @@ static void nfp_net_stat64(struct net_device *netdev,
                unsigned int start;
 
                do {
-                       start = u64_stats_fetch_begin(&r_vec->rx_sync);
+                       start = u64_stats_fetch_begin_irq(&r_vec->rx_sync);
                        data[0] = r_vec->rx_pkts;
                        data[1] = r_vec->rx_bytes;
                        data[2] = r_vec->rx_drops;
-               } while (u64_stats_fetch_retry(&r_vec->rx_sync, start));
+               } while (u64_stats_fetch_retry_irq(&r_vec->rx_sync, start));
                stats->rx_packets += data[0];
                stats->rx_bytes += data[1];
                stats->rx_dropped += data[2];
 
                do {
-                       start = u64_stats_fetch_begin(&r_vec->tx_sync);
+                       start = u64_stats_fetch_begin_irq(&r_vec->tx_sync);
                        data[0] = r_vec->tx_pkts;
                        data[1] = r_vec->tx_bytes;
                        data[2] = r_vec->tx_errors;
-               } while (u64_stats_fetch_retry(&r_vec->tx_sync, start));
+               } while (u64_stats_fetch_retry_irq(&r_vec->tx_sync, start));
                stats->tx_packets += data[0];
                stats->tx_bytes += data[1];
                stats->tx_errors += data[2];
index eeb1455..b1b1b64 100644 (file)
@@ -649,7 +649,7 @@ static u64 *nfp_vnic_get_sw_stats(struct net_device *netdev, u64 *data)
                unsigned int start;
 
                do {
-                       start = u64_stats_fetch_begin(&nn->r_vecs[i].rx_sync);
+                       start = u64_stats_fetch_begin_irq(&nn->r_vecs[i].rx_sync);
                        data[0] = nn->r_vecs[i].rx_pkts;
                        tmp[0] = nn->r_vecs[i].hw_csum_rx_ok;
                        tmp[1] = nn->r_vecs[i].hw_csum_rx_inner_ok;
@@ -657,10 +657,10 @@ static u64 *nfp_vnic_get_sw_stats(struct net_device *netdev, u64 *data)
                        tmp[3] = nn->r_vecs[i].hw_csum_rx_error;
                        tmp[4] = nn->r_vecs[i].rx_replace_buf_alloc_fail;
                        tmp[5] = nn->r_vecs[i].hw_tls_rx;
-               } while (u64_stats_fetch_retry(&nn->r_vecs[i].rx_sync, start));
+               } while (u64_stats_fetch_retry_irq(&nn->r_vecs[i].rx_sync, start));
 
                do {
-                       start = u64_stats_fetch_begin(&nn->r_vecs[i].tx_sync);
+                       start = u64_stats_fetch_begin_irq(&nn->r_vecs[i].tx_sync);
                        data[1] = nn->r_vecs[i].tx_pkts;
                        data[2] = nn->r_vecs[i].tx_busy;
                        tmp[6] = nn->r_vecs[i].hw_csum_tx;
@@ -670,7 +670,7 @@ static u64 *nfp_vnic_get_sw_stats(struct net_device *netdev, u64 *data)
                        tmp[10] = nn->r_vecs[i].hw_tls_tx;
                        tmp[11] = nn->r_vecs[i].tls_tx_fallback;
                        tmp[12] = nn->r_vecs[i].tls_tx_no_fallback;
-               } while (u64_stats_fetch_retry(&nn->r_vecs[i].tx_sync, start));
+               } while (u64_stats_fetch_retry_irq(&nn->r_vecs[i].tx_sync, start));
 
                data += NN_RVEC_PER_Q_STATS;
 
index edd3000..4cc3879 100644 (file)
@@ -507,6 +507,7 @@ int nfp_eth_set_idmode(struct nfp_cpp *cpp, unsigned int idx, bool state)
        if (nfp_nsp_get_abi_ver_minor(nsp) < 32) {
                nfp_err(nfp_nsp_cpp(nsp),
                        "set id mode operation not supported, please update flash\n");
+               nfp_eth_config_cleanup_end(nsp);
                return -EOPNOTSUPP;
        }
 
index 1443f78..0be79c5 100644 (file)
@@ -1564,8 +1564,67 @@ static int ionic_set_features(struct net_device *netdev,
        return err;
 }
 
+static int ionic_set_attr_mac(struct ionic_lif *lif, u8 *mac)
+{
+       struct ionic_admin_ctx ctx = {
+               .work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
+               .cmd.lif_setattr = {
+                       .opcode = IONIC_CMD_LIF_SETATTR,
+                       .index = cpu_to_le16(lif->index),
+                       .attr = IONIC_LIF_ATTR_MAC,
+               },
+       };
+
+       ether_addr_copy(ctx.cmd.lif_setattr.mac, mac);
+       return ionic_adminq_post_wait(lif, &ctx);
+}
+
+static int ionic_get_attr_mac(struct ionic_lif *lif, u8 *mac_addr)
+{
+       struct ionic_admin_ctx ctx = {
+               .work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
+               .cmd.lif_getattr = {
+                       .opcode = IONIC_CMD_LIF_GETATTR,
+                       .index = cpu_to_le16(lif->index),
+                       .attr = IONIC_LIF_ATTR_MAC,
+               },
+       };
+       int err;
+
+       err = ionic_adminq_post_wait(lif, &ctx);
+       if (err)
+               return err;
+
+       ether_addr_copy(mac_addr, ctx.comp.lif_getattr.mac);
+       return 0;
+}
+
+static int ionic_program_mac(struct ionic_lif *lif, u8 *mac)
+{
+       u8  get_mac[ETH_ALEN];
+       int err;
+
+       err = ionic_set_attr_mac(lif, mac);
+       if (err)
+               return err;
+
+       err = ionic_get_attr_mac(lif, get_mac);
+       if (err)
+               return err;
+
+       /* To deal with older firmware that silently ignores the set attr mac:
+        * doesn't actually change the mac and doesn't return an error, so we
+        * do the get attr to verify whether or not the set actually happened
+        */
+       if (!ether_addr_equal(get_mac, mac))
+               return 1;
+
+       return 0;
+}
+
 static int ionic_set_mac_address(struct net_device *netdev, void *sa)
 {
+       struct ionic_lif *lif = netdev_priv(netdev);
        struct sockaddr *addr = sa;
        u8 *mac;
        int err;
@@ -1574,6 +1633,14 @@ static int ionic_set_mac_address(struct net_device *netdev, void *sa)
        if (ether_addr_equal(netdev->dev_addr, mac))
                return 0;
 
+       err = ionic_program_mac(lif, mac);
+       if (err < 0)
+               return err;
+
+       if (err > 0)
+               netdev_dbg(netdev, "%s: SET and GET ATTR Mac are not equal-due to old FW running\n",
+                          __func__);
+
        err = eth_prepare_mac_addr_change(netdev, addr);
        if (err)
                return err;
@@ -2963,6 +3030,9 @@ static void ionic_lif_handle_fw_up(struct ionic_lif *lif)
 
        mutex_lock(&lif->queue_lock);
 
+       if (test_and_clear_bit(IONIC_LIF_F_BROKEN, lif->state))
+               dev_info(ionic->dev, "FW Up: clearing broken state\n");
+
        err = ionic_qcqs_alloc(lif);
        if (err)
                goto err_unlock;
@@ -3169,6 +3239,7 @@ static int ionic_station_set(struct ionic_lif *lif)
                        .attr = IONIC_LIF_ATTR_MAC,
                },
        };
+       u8 mac_address[ETH_ALEN];
        struct sockaddr addr;
        int err;
 
@@ -3177,8 +3248,23 @@ static int ionic_station_set(struct ionic_lif *lif)
                return err;
        netdev_dbg(lif->netdev, "found initial MAC addr %pM\n",
                   ctx.comp.lif_getattr.mac);
-       if (is_zero_ether_addr(ctx.comp.lif_getattr.mac))
-               return 0;
+       ether_addr_copy(mac_address, ctx.comp.lif_getattr.mac);
+
+       if (is_zero_ether_addr(mac_address)) {
+               eth_hw_addr_random(netdev);
+               netdev_dbg(netdev, "Random Mac generated: %pM\n", netdev->dev_addr);
+               ether_addr_copy(mac_address, netdev->dev_addr);
+
+               err = ionic_program_mac(lif, mac_address);
+               if (err < 0)
+                       return err;
+
+               if (err > 0) {
+                       netdev_dbg(netdev, "%s:SET/GET ATTR Mac are not same-due to old FW running\n",
+                                  __func__);
+                       return 0;
+               }
+       }
 
        if (!is_zero_ether_addr(netdev->dev_addr)) {
                /* If the netdev mac is non-zero and doesn't match the default
@@ -3186,12 +3272,11 @@ static int ionic_station_set(struct ionic_lif *lif)
                 * likely here again after a fw-upgrade reset.  We need to be
                 * sure the netdev mac is in our filter list.
                 */
-               if (!ether_addr_equal(ctx.comp.lif_getattr.mac,
-                                     netdev->dev_addr))
+               if (!ether_addr_equal(mac_address, netdev->dev_addr))
                        ionic_lif_addr_add(lif, netdev->dev_addr);
        } else {
                /* Update the netdev mac with the device's mac */
-               memcpy(addr.sa_data, ctx.comp.lif_getattr.mac, netdev->addr_len);
+               ether_addr_copy(addr.sa_data, mac_address);
                addr.sa_family = AF_INET;
                err = eth_prepare_mac_addr_change(netdev, &addr);
                if (err) {
index 4029b4e..56f93b0 100644 (file)
@@ -474,8 +474,8 @@ try_again:
                                ionic_opcode_to_str(opcode), opcode,
                                ionic_error_to_str(err), err);
 
-                       msleep(1000);
                        iowrite32(0, &idev->dev_cmd_regs->done);
+                       msleep(1000);
                        iowrite32(1, &idev->dev_cmd_regs->doorbell);
                        goto try_again;
                }
@@ -488,6 +488,8 @@ try_again:
                return ionic_error_to_errno(err);
        }
 
+       ionic_dev_cmd_clean(ionic);
+
        return 0;
 }
 
index bc70c6a..58cf7cc 100644 (file)
@@ -1273,7 +1273,7 @@ static int ofdpa_port_ipv4_neigh(struct ofdpa_port *ofdpa_port,
        bool removing;
        int err = 0;
 
-       entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+       entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
        if (!entry)
                return -ENOMEM;
 
index 3bf2021..3829c28 100644 (file)
@@ -1037,6 +1037,8 @@ static int smsc911x_mii_probe(struct net_device *dev)
                return ret;
        }
 
+       /* Indicate that the MAC is responsible for managing PHY PM */
+       phydev->mac_managed_pm = true;
        phy_attached_info(phydev);
 
        phy_set_max_speed(phydev, SPEED_100);
@@ -2587,6 +2589,8 @@ static int smsc911x_suspend(struct device *dev)
        if (netif_running(ndev)) {
                netif_stop_queue(ndev);
                netif_device_detach(ndev);
+               if (!device_may_wakeup(dev))
+                       phy_stop(ndev->phydev);
        }
 
        /* enable wake on LAN, energy detection and the external PME
@@ -2628,6 +2632,8 @@ static int smsc911x_resume(struct device *dev)
        if (netif_running(ndev)) {
                netif_device_attach(ndev);
                netif_start_queue(ndev);
+               if (!device_may_wakeup(dev))
+                       phy_start(ndev->phydev);
        }
 
        return 0;
index 52f9ed8..9af25be 100644 (file)
@@ -1134,9 +1134,8 @@ static void intel_eth_pci_remove(struct pci_dev *pdev)
 
        stmmac_dvr_remove(&pdev->dev);
 
+       clk_disable_unprepare(priv->plat->stmmac_clk);
        clk_unregister_fixed_rate(priv->plat->stmmac_clk);
-
-       pcim_iounmap_regions(pdev, BIT(0));
 }
 
 static int __maybe_unused intel_eth_pci_suspend(struct device *dev)
index caa4bfc..9b6138b 100644 (file)
@@ -258,14 +258,18 @@ EXPORT_SYMBOL_GPL(stmmac_set_mac_addr);
 /* Enable disable MAC RX/TX */
 void stmmac_set_mac(void __iomem *ioaddr, bool enable)
 {
-       u32 value = readl(ioaddr + MAC_CTRL_REG);
+       u32 old_val, value;
+
+       old_val = readl(ioaddr + MAC_CTRL_REG);
+       value = old_val;
 
        if (enable)
                value |= MAC_ENABLE_RX | MAC_ENABLE_TX;
        else
                value &= ~(MAC_ENABLE_TX | MAC_ENABLE_RX);
 
-       writel(value, ioaddr + MAC_CTRL_REG);
+       if (value != old_val)
+               writel(value, ioaddr + MAC_CTRL_REG);
 }
 
 void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr,
index 070b5ef..592d29a 100644 (file)
@@ -986,10 +986,10 @@ static void stmmac_mac_link_up(struct phylink_config *config,
                               bool tx_pause, bool rx_pause)
 {
        struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev));
-       u32 ctrl;
+       u32 old_ctrl, ctrl;
 
-       ctrl = readl(priv->ioaddr + MAC_CTRL_REG);
-       ctrl &= ~priv->hw->link.speed_mask;
+       old_ctrl = readl(priv->ioaddr + MAC_CTRL_REG);
+       ctrl = old_ctrl & ~priv->hw->link.speed_mask;
 
        if (interface == PHY_INTERFACE_MODE_USXGMII) {
                switch (speed) {
@@ -1064,7 +1064,8 @@ static void stmmac_mac_link_up(struct phylink_config *config,
        if (tx_pause && rx_pause)
                stmmac_mac_flow_ctrl(priv, duplex);
 
-       writel(ctrl, priv->ioaddr + MAC_CTRL_REG);
+       if (ctrl != old_ctrl)
+               writel(ctrl, priv->ioaddr + MAC_CTRL_REG);
 
        stmmac_mac_set(priv, priv->ioaddr, true);
        if (phy && priv->dma_cap.eee) {
index 76c4a70..e97db82 100644 (file)
@@ -348,7 +348,7 @@ do {                                                                        \
  *             This macro is invoked by the OS-specific before it left the
  *             function mac_drv_rx_complete. This macro calls mac_drv_fill_rxd
  *             if the number of used RxDs is equal or lower than the
- *             the given low water mark.
+ *             given low water mark.
  *
  * para        low_water       low water mark of used RxD's
  *
index 6afdf16..5cf218c 100644 (file)
@@ -1310,10 +1310,11 @@ static void adf7242_remove(struct spi_device *spi)
 
        debugfs_remove_recursive(lp->debugfs_root);
 
+       ieee802154_unregister_hw(lp->hw);
+
        cancel_delayed_work_sync(&lp->work);
        destroy_workqueue(lp->wqueue);
 
-       ieee802154_unregister_hw(lp->hw);
        mutex_destroy(&lp->bmux);
        ieee802154_free_hw(lp->hw);
 }
index 42c0b45..450b16a 100644 (file)
@@ -2293,7 +2293,7 @@ static int ca8210_set_csma_params(
  * @retries:  Number of retries
  *
  * Sets the number of times to retry a transmission if no acknowledgment was
- * was received from the other end when one was requested.
+ * received from the other end when one was requested.
  *
  * Return: 0 or linux error code
  */
index 1e1f40f..c69b87d 100644 (file)
@@ -504,6 +504,7 @@ cc2520_tx(struct ieee802154_hw *hw, struct sk_buff *skb)
                goto err_tx;
 
        if (status & CC2520_STATUS_TX_UNDERFLOW) {
+               rc = -EINVAL;
                dev_err(&priv->spi->dev, "cc2520 tx underflow exception\n");
                goto err_tx;
        }
index 1e9eae2..53a1dbe 100644 (file)
@@ -568,7 +568,7 @@ static int ipa_smem_init(struct ipa *ipa, u32 item, size_t size)
        }
 
        /* Align the address down and the size up to a page boundary */
-       addr = qcom_smem_virt_to_phys(virt) & PAGE_MASK;
+       addr = qcom_smem_virt_to_phys(virt);
        phys = addr & PAGE_MASK;
        size = PAGE_ALIGN(size + addr - phys);
        iova = phys;    /* We just want a direct mapping */
index a5b3553..6f35438 100644 (file)
@@ -48,7 +48,7 @@ struct ipa;
  *
  * The offset of registers related to resource types is computed by a macro
  * that is supplied a parameter "rt".  The "rt" represents a resource type,
- * which is is a member of the ipa_resource_type_src enumerated type for
+ * which is a member of the ipa_resource_type_src enumerated type for
  * source endpoint resources or the ipa_resource_type_dst enumerated type
  * for destination endpoint resources.
  *
index ef02f2c..cbabca1 100644 (file)
@@ -194,7 +194,7 @@ static struct notifier_block ipvtap_notifier_block __read_mostly = {
        .notifier_call  = ipvtap_device_event,
 };
 
-static int ipvtap_init(void)
+static int __init ipvtap_init(void)
 {
        int err;
 
@@ -228,7 +228,7 @@ out1:
 }
 module_init(ipvtap_init);
 
-static void ipvtap_exit(void)
+static void __exit ipvtap_exit(void)
 {
        rtnl_link_unregister(&ipvtap_link_ops);
        unregister_netdevice_notifier(&ipvtap_notifier_block);
index ee6087e..c6d271e 100644 (file)
@@ -462,11 +462,6 @@ static struct macsec_eth_header *macsec_ethhdr(struct sk_buff *skb)
        return (struct macsec_eth_header *)skb_mac_header(skb);
 }
 
-static sci_t dev_to_sci(struct net_device *dev, __be16 port)
-{
-       return make_sci(dev->dev_addr, port);
-}
-
 static void __macsec_pn_wrapped(struct macsec_secy *secy,
                                struct macsec_tx_sa *tx_sa)
 {
@@ -3661,7 +3656,6 @@ static int macsec_set_mac_address(struct net_device *dev, void *p)
 
 out:
        eth_hw_addr_set(dev, addr->sa_data);
-       macsec->secy.sci = dev_to_sci(dev, MACSEC_PORT_ES);
 
        /* If h/w offloading is available, propagate to the device */
        if (macsec_is_offloaded(macsec)) {
@@ -4000,6 +3994,11 @@ static bool sci_exists(struct net_device *dev, sci_t sci)
        return false;
 }
 
+static sci_t dev_to_sci(struct net_device *dev, __be16 port)
+{
+       return make_sci(dev->dev_addr, port);
+}
+
 static int macsec_add_dev(struct net_device *dev, sci_t sci, u8 icv_len)
 {
        struct macsec_dev *macsec = macsec_priv(dev);
index 3e79c2c..1c1584f 100644 (file)
@@ -47,7 +47,9 @@ int fwnode_mdiobus_phy_device_register(struct mii_bus *mdio,
         * just fall back to poll mode
         */
        if (rc == -EPROBE_DEFER)
-               rc = -ENODEV;
+               rc = driver_deferred_probe_check_state(&phy->mdio.dev);
+       if (rc == -EPROBE_DEFER)
+               return rc;
 
        if (rc > 0) {
                phy->irq = rc;
index e470e33..9a1a5b2 100644 (file)
@@ -67,10 +67,10 @@ nsim_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
        unsigned int start;
 
        do {
-               start = u64_stats_fetch_begin(&ns->syncp);
+               start = u64_stats_fetch_begin_irq(&ns->syncp);
                stats->tx_bytes = ns->tx_bytes;
                stats->tx_packets = ns->tx_packets;
-       } while (u64_stats_fetch_retry(&ns->syncp, start));
+       } while (u64_stats_fetch_retry_irq(&ns->syncp, start));
 }
 
 static int
index 73f7962..c49062a 100644 (file)
@@ -243,13 +243,7 @@ static irqreturn_t meson_gxl_handle_interrupt(struct phy_device *phydev)
            irq_status == INTSRC_ENERGY_DETECT)
                return IRQ_HANDLED;
 
-       /* Give PHY some time before MAC starts sending data. This works
-        * around an issue where network doesn't come up properly.
-        */
-       if (!(irq_status & INTSRC_LINK_DOWN))
-               phy_queue_state_machine(phydev, msecs_to_jiffies(100));
-       else
-               phy_trigger_machine(phydev);
+       phy_trigger_machine(phydev);
 
        return IRQ_HANDLED;
 }
index e78d0bf..6f52b4f 100644 (file)
@@ -2873,12 +2873,18 @@ static int lan8814_config_init(struct phy_device *phydev)
        return 0;
 }
 
+/* It is expected that there will not be any 'lan8814_take_coma_mode'
+ * function called in suspend. Because the GPIO line can be shared, so if one of
+ * the phys goes back in coma mode, then all the other PHYs will go, which is
+ * wrong.
+ */
 static int lan8814_release_coma_mode(struct phy_device *phydev)
 {
        struct gpio_desc *gpiod;
 
        gpiod = devm_gpiod_get_optional(&phydev->mdio.dev, "coma-mode",
-                                       GPIOD_OUT_HIGH_OPEN_DRAIN);
+                                       GPIOD_OUT_HIGH_OPEN_DRAIN |
+                                       GPIOD_FLAGS_BIT_NONEXCLUSIVE);
        if (IS_ERR(gpiod))
                return PTR_ERR(gpiod);
 
index d4c93d5..8569a54 100644 (file)
 
 /* Interrupt Source Register */
 #define LAN87XX_INTERRUPT_SOURCE                (0x18)
+#define LAN87XX_INTERRUPT_SOURCE_2              (0x08)
 
 /* Interrupt Mask Register */
 #define LAN87XX_INTERRUPT_MASK                  (0x19)
 #define LAN87XX_MASK_LINK_UP                    (0x0004)
 #define LAN87XX_MASK_LINK_DOWN                  (0x0002)
 
+#define LAN87XX_INTERRUPT_MASK_2                (0x09)
+#define LAN87XX_MASK_COMM_RDY                  BIT(10)
+
 /* MISC Control 1 Register */
 #define LAN87XX_CTRL_1                          (0x11)
 #define LAN87XX_MASK_RGMII_TXC_DLY_EN           (0x4000)
@@ -424,17 +428,55 @@ static int lan87xx_phy_config_intr(struct phy_device *phydev)
        int rc, val = 0;
 
        if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
-               /* unmask all source and clear them before enable */
-               rc = phy_write(phydev, LAN87XX_INTERRUPT_MASK, 0x7FFF);
+               /* clear all interrupt */
+               rc = phy_write(phydev, LAN87XX_INTERRUPT_MASK, val);
+               if (rc < 0)
+                       return rc;
+
                rc = phy_read(phydev, LAN87XX_INTERRUPT_SOURCE);
-               val = LAN87XX_MASK_LINK_UP | LAN87XX_MASK_LINK_DOWN;
+               if (rc < 0)
+                       return rc;
+
+               rc = access_ereg(phydev, PHYACC_ATTR_MODE_WRITE,
+                                PHYACC_ATTR_BANK_MISC,
+                                LAN87XX_INTERRUPT_MASK_2, val);
+               if (rc < 0)
+                       return rc;
+
+               rc = access_ereg(phydev, PHYACC_ATTR_MODE_READ,
+                                PHYACC_ATTR_BANK_MISC,
+                                LAN87XX_INTERRUPT_SOURCE_2, 0);
+               if (rc < 0)
+                       return rc;
+
+               /* enable link down and comm ready interrupt */
+               val = LAN87XX_MASK_LINK_DOWN;
                rc = phy_write(phydev, LAN87XX_INTERRUPT_MASK, val);
+               if (rc < 0)
+                       return rc;
+
+               val = LAN87XX_MASK_COMM_RDY;
+               rc = access_ereg(phydev, PHYACC_ATTR_MODE_WRITE,
+                                PHYACC_ATTR_BANK_MISC,
+                                LAN87XX_INTERRUPT_MASK_2, val);
        } else {
                rc = phy_write(phydev, LAN87XX_INTERRUPT_MASK, val);
-               if (rc)
+               if (rc < 0)
                        return rc;
 
                rc = phy_read(phydev, LAN87XX_INTERRUPT_SOURCE);
+               if (rc < 0)
+                       return rc;
+
+               rc = access_ereg(phydev, PHYACC_ATTR_MODE_WRITE,
+                                PHYACC_ATTR_BANK_MISC,
+                                LAN87XX_INTERRUPT_MASK_2, val);
+               if (rc < 0)
+                       return rc;
+
+               rc = access_ereg(phydev, PHYACC_ATTR_MODE_READ,
+                                PHYACC_ATTR_BANK_MISC,
+                                LAN87XX_INTERRUPT_SOURCE_2, 0);
        }
 
        return rc < 0 ? rc : 0;
@@ -444,6 +486,14 @@ static irqreturn_t lan87xx_handle_interrupt(struct phy_device *phydev)
 {
        int irq_status;
 
+       irq_status  = access_ereg(phydev, PHYACC_ATTR_MODE_READ,
+                                 PHYACC_ATTR_BANK_MISC,
+                                 LAN87XX_INTERRUPT_SOURCE_2, 0);
+       if (irq_status < 0) {
+               phy_error(phydev);
+               return IRQ_NONE;
+       }
+
        irq_status = phy_read(phydev, LAN87XX_INTERRUPT_SOURCE);
        if (irq_status < 0) {
                phy_error(phydev);
index 0c6efd7..12ff276 100644 (file)
@@ -316,11 +316,11 @@ static __maybe_unused int mdio_bus_phy_resume(struct device *dev)
 
        phydev->suspended_by_mdio_bus = 0;
 
-       /* If we managed to get here with the PHY state machine in a state other
-        * than PHY_HALTED this is an indication that something went wrong and
-        * we should most likely be using MAC managed PM and we are not.
+       /* If we manged to get here with the PHY state machine in a state neither
+        * PHY_HALTED nor PHY_READY this is an indication that something went wrong
+        * and we should most likely be using MAC managed PM and we are not.
         */
-       WARN_ON(phydev->state != PHY_HALTED && !phydev->mac_managed_pm);
+       WARN_ON(phydev->state != PHY_HALTED && phydev->state != PHY_READY);
 
        ret = phy_init_hw(phydev);
        if (ret < 0)
index 2de09ad..e11f709 100644 (file)
@@ -777,6 +777,13 @@ static const struct usb_device_id  products[] = {
 },
 #endif
 
+/* Lenovo ThinkPad OneLink+ Dock (based on Realtek RTL8153) */
+{
+       USB_DEVICE_AND_INTERFACE_INFO(LENOVO_VENDOR_ID, 0x3054, USB_CLASS_COMM,
+                       USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
+       .driver_info = 0,
+},
+
 /* ThinkPad USB-C Dock (based on Realtek RTL8153) */
 {
        USB_DEVICE_AND_INTERFACE_INFO(LENOVO_VENDOR_ID, 0x3062, USB_CLASS_COMM,
index 709e3c5..0cb187d 100644 (file)
@@ -1087,6 +1087,7 @@ static const struct usb_device_id products[] = {
        {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0512)},   /* Quectel EG12/EM12 */
        {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0620)},   /* Quectel EM160R-GL */
        {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0800)},   /* Quectel RM500Q-GL */
+       {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0801)},   /* Quectel RM520N */
 
        /* 3. Combined interface devices matching on interface number */
        {QMI_FIXED_INTF(0x0408, 0xea42, 4)},    /* Yota / Megafon M100-1 */
index 0f6efaa..688905e 100644 (file)
@@ -770,6 +770,7 @@ enum rtl8152_flags {
        RX_EPROTO,
 };
 
+#define DEVICE_ID_THINKPAD_ONELINK_PLUS_DOCK           0x3054
 #define DEVICE_ID_THINKPAD_THUNDERBOLT3_DOCK_GEN2      0x3082
 #define DEVICE_ID_THINKPAD_USB_C_DONGLE                        0x720c
 #define DEVICE_ID_THINKPAD_USB_C_DOCK_GEN2             0xa387
@@ -5906,6 +5907,11 @@ static void r8153_enter_oob(struct r8152 *tp)
        ocp_data &= ~NOW_IS_OOB;
        ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
 
+       /* RX FIFO settings for OOB */
+       ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL0, RXFIFO_THR1_OOB);
+       ocp_write_word(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1, RXFIFO_THR2_OOB);
+       ocp_write_word(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2, RXFIFO_THR3_OOB);
+
        rtl_disable(tp);
        rtl_reset_bmu(tp);
 
@@ -6431,21 +6437,8 @@ static void r8156_fc_parameter(struct r8152 *tp)
        u32 pause_on = tp->fc_pause_on ? tp->fc_pause_on : fc_pause_on_auto(tp);
        u32 pause_off = tp->fc_pause_off ? tp->fc_pause_off : fc_pause_off_auto(tp);
 
-       switch (tp->version) {
-       case RTL_VER_10:
-       case RTL_VER_11:
-               ocp_write_word(tp, MCU_TYPE_PLA, PLA_RX_FIFO_FULL, pause_on / 8);
-               ocp_write_word(tp, MCU_TYPE_PLA, PLA_RX_FIFO_EMPTY, pause_off / 8);
-               break;
-       case RTL_VER_12:
-       case RTL_VER_13:
-       case RTL_VER_15:
-               ocp_write_word(tp, MCU_TYPE_PLA, PLA_RX_FIFO_FULL, pause_on / 16);
-               ocp_write_word(tp, MCU_TYPE_PLA, PLA_RX_FIFO_EMPTY, pause_off / 16);
-               break;
-       default:
-               break;
-       }
+       ocp_write_word(tp, MCU_TYPE_PLA, PLA_RX_FIFO_FULL, pause_on / 16);
+       ocp_write_word(tp, MCU_TYPE_PLA, PLA_RX_FIFO_EMPTY, pause_off / 16);
 }
 
 static void rtl8156_change_mtu(struct r8152 *tp)
@@ -6557,6 +6550,11 @@ static void rtl8156_down(struct r8152 *tp)
        ocp_data &= ~NOW_IS_OOB;
        ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
 
+       /* RX FIFO settings for OOB */
+       ocp_write_word(tp, MCU_TYPE_PLA, PLA_RXFIFO_FULL, 64 / 16);
+       ocp_write_word(tp, MCU_TYPE_PLA, PLA_RX_FIFO_FULL, 1024 / 16);
+       ocp_write_word(tp, MCU_TYPE_PLA, PLA_RX_FIFO_EMPTY, 4096 / 16);
+
        rtl_disable(tp);
        rtl_reset_bmu(tp);
 
@@ -9584,6 +9582,7 @@ static bool rtl8152_supports_lenovo_macpassthru(struct usb_device *udev)
 
        if (vendor_id == VENDOR_ID_LENOVO) {
                switch (product_id) {
+               case DEVICE_ID_THINKPAD_ONELINK_PLUS_DOCK:
                case DEVICE_ID_THINKPAD_THUNDERBOLT3_DOCK_GEN2:
                case DEVICE_ID_THINKPAD_USB_C_DOCK_GEN2:
                case DEVICE_ID_THINKPAD_USB_C_DOCK_GEN3:
@@ -9831,6 +9830,7 @@ static const struct usb_device_id rtl8152_table[] = {
        REALTEK_USB_DEVICE(VENDOR_ID_MICROSOFT, 0x0927),
        REALTEK_USB_DEVICE(VENDOR_ID_SAMSUNG, 0xa101),
        REALTEK_USB_DEVICE(VENDOR_ID_LENOVO,  0x304f),
+       REALTEK_USB_DEVICE(VENDOR_ID_LENOVO,  0x3054),
        REALTEK_USB_DEVICE(VENDOR_ID_LENOVO,  0x3062),
        REALTEK_USB_DEVICE(VENDOR_ID_LENOVO,  0x3069),
        REALTEK_USB_DEVICE(VENDOR_ID_LENOVO,  0x3082),
index d934774..9cce7de 100644 (file)
@@ -1211,7 +1211,7 @@ static void virtio_skb_set_hash(const struct virtio_net_hdr_v1_hash *hdr_hash,
        if (!hdr_hash || !skb)
                return;
 
-       switch ((int)hdr_hash->hash_report) {
+       switch (__le16_to_cpu(hdr_hash->hash_report)) {
        case VIRTIO_NET_HASH_REPORT_TCPv4:
        case VIRTIO_NET_HASH_REPORT_UDPv4:
        case VIRTIO_NET_HASH_REPORT_TCPv6:
@@ -1229,7 +1229,7 @@ static void virtio_skb_set_hash(const struct virtio_net_hdr_v1_hash *hdr_hash,
        default:
                rss_hash_type = PKT_HASH_TYPE_NONE;
        }
-       skb_set_hash(skb, (unsigned int)hdr_hash->hash_value, rss_hash_type);
+       skb_set_hash(skb, __le32_to_cpu(hdr_hash->hash_value), rss_hash_type);
 }
 
 static void receive_buf(struct virtnet_info *vi, struct receive_queue *rq,
@@ -3432,29 +3432,6 @@ static unsigned int mergeable_min_buf_len(struct virtnet_info *vi, struct virtqu
                   (unsigned int)GOOD_PACKET_LEN);
 }
 
-static void virtnet_config_sizes(struct virtnet_info *vi, u32 *sizes)
-{
-       u32 i, rx_size, tx_size;
-
-       if (vi->speed == SPEED_UNKNOWN || vi->speed < SPEED_10000) {
-               rx_size = 1024;
-               tx_size = 1024;
-
-       } else if (vi->speed < SPEED_40000) {
-               rx_size = 1024 * 4;
-               tx_size = 1024 * 4;
-
-       } else {
-               rx_size = 1024 * 8;
-               tx_size = 1024 * 8;
-       }
-
-       for (i = 0; i < vi->max_queue_pairs; i++) {
-               sizes[rxq2vq(i)] = rx_size;
-               sizes[txq2vq(i)] = tx_size;
-       }
-}
-
 static int virtnet_find_vqs(struct virtnet_info *vi)
 {
        vq_callback_t **callbacks;
@@ -3462,7 +3439,6 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
        int ret = -ENOMEM;
        int i, total_vqs;
        const char **names;
-       u32 *sizes;
        bool *ctx;
 
        /* We expect 1 RX virtqueue followed by 1 TX virtqueue, followed by
@@ -3490,15 +3466,10 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
                ctx = NULL;
        }
 
-       sizes = kmalloc_array(total_vqs, sizeof(*sizes), GFP_KERNEL);
-       if (!sizes)
-               goto err_sizes;
-
        /* Parameters for control virtqueue, if any */
        if (vi->has_cvq) {
                callbacks[total_vqs - 1] = NULL;
                names[total_vqs - 1] = "control";
-               sizes[total_vqs - 1] = 64;
        }
 
        /* Allocate/initialize parameters for send/receive virtqueues */
@@ -3513,10 +3484,8 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
                        ctx[rxq2vq(i)] = true;
        }
 
-       virtnet_config_sizes(vi, sizes);
-
-       ret = virtio_find_vqs_ctx_size(vi->vdev, total_vqs, vqs, callbacks,
-                                      names, sizes, ctx, NULL);
+       ret = virtio_find_vqs_ctx(vi->vdev, total_vqs, vqs, callbacks,
+                                 names, ctx, NULL);
        if (ret)
                goto err_find;
 
@@ -3536,8 +3505,6 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
 
 
 err_find:
-       kfree(sizes);
-err_sizes:
        kfree(ctx);
 err_ctx:
        kfree(names);
@@ -3897,9 +3864,6 @@ static int virtnet_probe(struct virtio_device *vdev)
                vi->curr_queue_pairs = num_online_cpus();
        vi->max_queue_pairs = max_queue_pairs;
 
-       virtnet_init_settings(dev);
-       virtnet_update_settings(vi);
-
        /* Allocate/initialize the rx/tx queues, and invoke find_vqs */
        err = init_vqs(vi);
        if (err)
@@ -3912,6 +3876,8 @@ static int virtnet_probe(struct virtio_device *vdev)
        netif_set_real_num_tx_queues(dev, vi->curr_queue_pairs);
        netif_set_real_num_rx_queues(dev, vi->curr_queue_pairs);
 
+       virtnet_init_settings(dev);
+
        if (virtio_has_feature(vdev, VIRTIO_NET_F_STANDBY)) {
                vi->failover = net_failover_create(vi->dev);
                if (IS_ERR(vi->failover)) {
index c62f299..d8a5dbf 100644 (file)
@@ -2403,7 +2403,7 @@ il4965_rs_fill_link_cmd(struct il_priv *il, struct il_lq_sta *lq_sta,
                /* Repeat initial/next rate.
                 * For legacy IL_NUMBER_TRY == 1, this loop will not execute.
                 * For HT IL_HT_NUMBER_TRY == 3, this executes twice. */
-               while (repeat_rate > 0) {
+               while (repeat_rate > 0 && idx < (LINK_QUAL_MAX_RETRY_NUM - 1)) {
                        if (is_legacy(tbl_type.lq_type)) {
                                if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE)
                                        ant_toggle_cnt++;
@@ -2422,8 +2422,6 @@ il4965_rs_fill_link_cmd(struct il_priv *il, struct il_lq_sta *lq_sta,
                            cpu_to_le32(new_rate);
                        repeat_rate--;
                        idx++;
-                       if (idx >= LINK_QUAL_MAX_RETRY_NUM)
-                               goto out;
                }
 
                il4965_rs_get_tbl_info_from_mcs(new_rate, lq_sta->band,
@@ -2468,7 +2466,6 @@ il4965_rs_fill_link_cmd(struct il_priv *il, struct il_lq_sta *lq_sta,
                repeat_rate--;
        }
 
-out:
        lq_cmd->agg_params.agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_DEF;
        lq_cmd->agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF;
 
index 6e55f15..1f301a5 100644 (file)
@@ -5060,6 +5060,10 @@ static int hwsim_virtio_handle_cmd(struct sk_buff *skb)
 
        nlh = nlmsg_hdr(skb);
        gnlh = nlmsg_data(nlh);
+
+       if (skb->len < nlh->nlmsg_len)
+               return -EINVAL;
+
        err = genlmsg_parse(nlh, &hwsim_genl_family, tb, HWSIM_ATTR_MAX,
                            hwsim_genl_policy, NULL);
        if (err) {
@@ -5102,7 +5106,8 @@ static void hwsim_virtio_rx_work(struct work_struct *work)
        spin_unlock_irqrestore(&hwsim_virtio_lock, flags);
 
        skb->data = skb->head;
-       skb_set_tail_pointer(skb, len);
+       skb_reset_tail_pointer(skb);
+       skb_put(skb, len);
        hwsim_virtio_handle_cmd(skb);
 
        spin_lock_irqsave(&hwsim_virtio_lock, flags);
index e180067..576a014 100644 (file)
@@ -261,7 +261,7 @@ int mt7921e_mac_reset(struct mt7921_dev *dev)
 
        err = mt7921e_driver_own(dev);
        if (err)
-               return err;
+               goto out;
 
        err = mt7921_run_firmware(dev);
        if (err)
index 43c085c..bb1a315 100644 (file)
@@ -245,6 +245,7 @@ struct wilc {
        u8 *rx_buffer;
        u32 rx_buffer_offset;
        u8 *tx_buffer;
+       u32 *vmm_table;
 
        struct txq_handle txq[NQUEUES];
        int txq_entries;
index 600cc57..7390f94 100644 (file)
@@ -28,6 +28,7 @@ struct wilc_sdio {
        u32 block_size;
        bool isinit;
        int has_thrpt_enh3;
+       u8 *cmd53_buf;
 };
 
 struct sdio_cmd52 {
@@ -47,6 +48,7 @@ struct sdio_cmd53 {
        u32 count:              9;
        u8 *buffer;
        u32 block_size;
+       bool use_global_buf;
 };
 
 static const struct wilc_hif_func wilc_hif_sdio;
@@ -91,6 +93,8 @@ static int wilc_sdio_cmd53(struct wilc *wilc, struct sdio_cmd53 *cmd)
 {
        struct sdio_func *func = container_of(wilc->dev, struct sdio_func, dev);
        int size, ret;
+       struct wilc_sdio *sdio_priv = wilc->bus_data;
+       u8 *buf = cmd->buffer;
 
        sdio_claim_host(func);
 
@@ -101,12 +105,23 @@ static int wilc_sdio_cmd53(struct wilc *wilc, struct sdio_cmd53 *cmd)
        else
                size = cmd->count;
 
+       if (cmd->use_global_buf) {
+               if (size > sizeof(u32))
+                       return -EINVAL;
+
+               buf = sdio_priv->cmd53_buf;
+       }
+
        if (cmd->read_write) {  /* write */
-               ret = sdio_memcpy_toio(func, cmd->address,
-                                      (void *)cmd->buffer, size);
+               if (cmd->use_global_buf)
+                       memcpy(buf, cmd->buffer, size);
+
+               ret = sdio_memcpy_toio(func, cmd->address, buf, size);
        } else {        /* read */
-               ret = sdio_memcpy_fromio(func, (void *)cmd->buffer,
-                                        cmd->address,  size);
+               ret = sdio_memcpy_fromio(func, buf, cmd->address, size);
+
+               if (cmd->use_global_buf)
+                       memcpy(cmd->buffer, buf, size);
        }
 
        sdio_release_host(func);
@@ -128,6 +143,12 @@ static int wilc_sdio_probe(struct sdio_func *func,
        if (!sdio_priv)
                return -ENOMEM;
 
+       sdio_priv->cmd53_buf = kzalloc(sizeof(u32), GFP_KERNEL);
+       if (!sdio_priv->cmd53_buf) {
+               ret = -ENOMEM;
+               goto free;
+       }
+
        ret = wilc_cfg80211_init(&wilc, &func->dev, WILC_HIF_SDIO,
                                 &wilc_hif_sdio);
        if (ret)
@@ -161,6 +182,7 @@ dispose_irq:
        irq_dispose_mapping(wilc->dev_irq_num);
        wilc_netdev_cleanup(wilc);
 free:
+       kfree(sdio_priv->cmd53_buf);
        kfree(sdio_priv);
        return ret;
 }
@@ -172,6 +194,7 @@ static void wilc_sdio_remove(struct sdio_func *func)
 
        clk_disable_unprepare(wilc->rtc_clk);
        wilc_netdev_cleanup(wilc);
+       kfree(sdio_priv->cmd53_buf);
        kfree(sdio_priv);
 }
 
@@ -375,8 +398,9 @@ static int wilc_sdio_write_reg(struct wilc *wilc, u32 addr, u32 data)
                cmd.address = WILC_SDIO_FBR_DATA_REG;
                cmd.block_mode = 0;
                cmd.increment = 1;
-               cmd.count = 4;
+               cmd.count = sizeof(u32);
                cmd.buffer = (u8 *)&data;
+               cmd.use_global_buf = true;
                cmd.block_size = sdio_priv->block_size;
                ret = wilc_sdio_cmd53(wilc, &cmd);
                if (ret)
@@ -414,6 +438,7 @@ static int wilc_sdio_write(struct wilc *wilc, u32 addr, u8 *buf, u32 size)
        nblk = size / block_size;
        nleft = size % block_size;
 
+       cmd.use_global_buf = false;
        if (nblk > 0) {
                cmd.block_mode = 1;
                cmd.increment = 1;
@@ -492,8 +517,9 @@ static int wilc_sdio_read_reg(struct wilc *wilc, u32 addr, u32 *data)
                cmd.address = WILC_SDIO_FBR_DATA_REG;
                cmd.block_mode = 0;
                cmd.increment = 1;
-               cmd.count = 4;
+               cmd.count = sizeof(u32);
                cmd.buffer = (u8 *)data;
+               cmd.use_global_buf = true;
 
                cmd.block_size = sdio_priv->block_size;
                ret = wilc_sdio_cmd53(wilc, &cmd);
@@ -535,6 +561,7 @@ static int wilc_sdio_read(struct wilc *wilc, u32 addr, u8 *buf, u32 size)
        nblk = size / block_size;
        nleft = size % block_size;
 
+       cmd.use_global_buf = false;
        if (nblk > 0) {
                cmd.block_mode = 1;
                cmd.increment = 1;
index 947d9a0..58bbf50 100644 (file)
@@ -714,7 +714,7 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
        int ret = 0;
        int counter;
        int timeout;
-       u32 vmm_table[WILC_VMM_TBL_SIZE];
+       u32 *vmm_table = wilc->vmm_table;
        u8 ac_pkt_num_to_chip[NQUEUES] = {0, 0, 0, 0};
        const struct wilc_hif_func *func;
        int srcu_idx;
@@ -1252,6 +1252,8 @@ void wilc_wlan_cleanup(struct net_device *dev)
        while ((rqe = wilc_wlan_rxq_remove(wilc)))
                kfree(rqe);
 
+       kfree(wilc->vmm_table);
+       wilc->vmm_table = NULL;
        kfree(wilc->rx_buffer);
        wilc->rx_buffer = NULL;
        kfree(wilc->tx_buffer);
@@ -1489,6 +1491,14 @@ int wilc_wlan_init(struct net_device *dev)
                        goto fail;
        }
 
+       if (!wilc->vmm_table)
+               wilc->vmm_table = kzalloc(WILC_VMM_TBL_SIZE, GFP_KERNEL);
+
+       if (!wilc->vmm_table) {
+               ret = -ENOBUFS;
+               goto fail;
+       }
+
        if (!wilc->tx_buffer)
                wilc->tx_buffer = kmalloc(WILC_TX_BUFF_SIZE, GFP_KERNEL);
 
@@ -1513,7 +1523,8 @@ int wilc_wlan_init(struct net_device *dev)
        return 0;
 
 fail:
-
+       kfree(wilc->vmm_table);
+       wilc->vmm_table = NULL;
        kfree(wilc->rx_buffer);
        wilc->rx_buffer = NULL;
        kfree(wilc->tx_buffer);
index 990360d..e85b3c5 100644 (file)
@@ -256,7 +256,6 @@ static void backend_disconnect(struct backend_info *be)
                unsigned int queue_index;
 
                xen_unregister_watchers(vif);
-               xenbus_rm(XBT_NIL, be->dev->nodename, "hotplug-status");
 #ifdef CONFIG_DEBUG_FS
                xenvif_debugfs_delif(vif);
 #endif /* CONFIG_DEBUG_FS */
@@ -984,6 +983,7 @@ static int netback_remove(struct xenbus_device *dev)
        struct backend_info *be = dev_get_drvdata(&dev->dev);
 
        unregister_hotplug_status_watch(be);
+       xenbus_rm(XBT_NIL, dev->nodename, "hotplug-status");
        if (be->vif) {
                kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
                backend_disconnect(be);
index 2caf997..07596bf 100644 (file)
@@ -310,6 +310,7 @@ static void pn532_uart_remove(struct serdev_device *serdev)
        pn53x_unregister_nfc(pn532->priv);
        serdev_device_close(serdev);
        pn53x_common_clean(pn532->priv);
+       del_timer_sync(&pn532->cmd_timeout);
        kfree_skb(pn532->recv_skb);
        kfree(pn532);
 }
index af367b2..66446f1 100644 (file)
@@ -4703,6 +4703,8 @@ static void nvme_fw_act_work(struct work_struct *work)
        nvme_start_queues(ctrl);
        /* read FW slot information to clear the AER */
        nvme_get_fw_slot_info(ctrl);
+
+       queue_work(nvme_wq, &ctrl->async_event_work);
 }
 
 static u32 nvme_aer_type(u32 result)
@@ -4715,9 +4717,10 @@ static u32 nvme_aer_subtype(u32 result)
        return (result & 0xff00) >> 8;
 }
 
-static void nvme_handle_aen_notice(struct nvme_ctrl *ctrl, u32 result)
+static bool nvme_handle_aen_notice(struct nvme_ctrl *ctrl, u32 result)
 {
        u32 aer_notice_type = nvme_aer_subtype(result);
+       bool requeue = true;
 
        trace_nvme_async_event(ctrl, aer_notice_type);
 
@@ -4734,6 +4737,7 @@ static void nvme_handle_aen_notice(struct nvme_ctrl *ctrl, u32 result)
                 */
                if (nvme_change_ctrl_state(ctrl, NVME_CTRL_RESETTING)) {
                        nvme_auth_stop(ctrl);
+                       requeue = false;
                        queue_work(nvme_wq, &ctrl->fw_act_work);
                }
                break;
@@ -4750,6 +4754,7 @@ static void nvme_handle_aen_notice(struct nvme_ctrl *ctrl, u32 result)
        default:
                dev_warn(ctrl->device, "async event result %08x\n", result);
        }
+       return requeue;
 }
 
 static void nvme_handle_aer_persistent_error(struct nvme_ctrl *ctrl)
@@ -4765,13 +4770,14 @@ void nvme_complete_async_event(struct nvme_ctrl *ctrl, __le16 status,
        u32 result = le32_to_cpu(res->u32);
        u32 aer_type = nvme_aer_type(result);
        u32 aer_subtype = nvme_aer_subtype(result);
+       bool requeue = true;
 
        if (le16_to_cpu(status) >> 1 != NVME_SC_SUCCESS)
                return;
 
        switch (aer_type) {
        case NVME_AER_NOTICE:
-               nvme_handle_aen_notice(ctrl, result);
+               requeue = nvme_handle_aen_notice(ctrl, result);
                break;
        case NVME_AER_ERROR:
                /*
@@ -4792,7 +4798,9 @@ void nvme_complete_async_event(struct nvme_ctrl *ctrl, __le16 status,
        default:
                break;
        }
-       queue_work(nvme_wq, &ctrl->async_event_work);
+
+       if (requeue)
+               queue_work(nvme_wq, &ctrl->async_event_work);
 }
 EXPORT_SYMBOL_GPL(nvme_complete_async_event);
 
index 3a1c37f..98864b8 100644 (file)
@@ -3517,6 +3517,8 @@ static const struct pci_device_id nvme_id_table[] = {
                .driver_data = NVME_QUIRK_NO_DEEPEST_PS, },
        { PCI_DEVICE(0xc0a9, 0x540a),   /* Crucial P2 */
                .driver_data = NVME_QUIRK_BOGUS_NID, },
+       { PCI_DEVICE(0x1d97, 0x2263), /* Lexar NM610 */
+               .driver_data = NVME_QUIRK_BOGUS_NID, },
        { PCI_DEVICE(PCI_VENDOR_ID_AMAZON, 0x0061),
                .driver_data = NVME_QUIRK_DMA_ADDRESS_BITS_48, },
        { PCI_DEVICE(PCI_VENDOR_ID_AMAZON, 0x0065),
index 044da18..d5871fd 100644 (file)
@@ -121,7 +121,6 @@ struct nvme_tcp_queue {
        struct mutex            send_mutex;
        struct llist_head       req_list;
        struct list_head        send_list;
-       bool                    more_requests;
 
        /* recv state */
        void                    *pdu;
@@ -320,7 +319,7 @@ static inline void nvme_tcp_send_all(struct nvme_tcp_queue *queue)
 static inline bool nvme_tcp_queue_more(struct nvme_tcp_queue *queue)
 {
        return !list_empty(&queue->send_list) ||
-               !llist_empty(&queue->req_list) || queue->more_requests;
+               !llist_empty(&queue->req_list);
 }
 
 static inline void nvme_tcp_queue_request(struct nvme_tcp_request *req,
@@ -339,9 +338,7 @@ static inline void nvme_tcp_queue_request(struct nvme_tcp_request *req,
         */
        if (queue->io_cpu == raw_smp_processor_id() &&
            sync && empty && mutex_trylock(&queue->send_mutex)) {
-               queue->more_requests = !last;
                nvme_tcp_send_all(queue);
-               queue->more_requests = false;
                mutex_unlock(&queue->send_mutex);
        }
 
@@ -1229,7 +1226,7 @@ static void nvme_tcp_io_work(struct work_struct *w)
                else if (unlikely(result < 0))
                        return;
 
-               if (!pending)
+               if (!pending || !queue->rd_enabled)
                        return;
 
        } while (!time_after(jiffies, deadline)); /* quota is exhausted */
index cf690df..c4113b4 100644 (file)
@@ -196,6 +196,7 @@ int nvmet_setup_auth(struct nvmet_ctrl *ctrl)
        if (IS_ERR(ctrl->ctrl_key)) {
                ret = PTR_ERR(ctrl->ctrl_key);
                ctrl->ctrl_key = NULL;
+               goto out_free_hash;
        }
        pr_debug("%s: using ctrl hash %s key %*ph\n", __func__,
                 ctrl->ctrl_key->hash > 0 ?
index a134579..7f4083c 100644 (file)
@@ -735,6 +735,8 @@ static void nvmet_set_error(struct nvmet_req *req, u16 status)
 
 static void __nvmet_req_complete(struct nvmet_req *req, u16 status)
 {
+       struct nvmet_ns *ns = req->ns;
+
        if (!req->sq->sqhd_disabled)
                nvmet_update_sq_head(req);
        req->cqe->sq_id = cpu_to_le16(req->sq->qid);
@@ -745,9 +747,9 @@ static void __nvmet_req_complete(struct nvmet_req *req, u16 status)
 
        trace_nvmet_req_complete(req);
 
-       if (req->ns)
-               nvmet_put_namespace(req->ns);
        req->ops->queue_response(req);
+       if (ns)
+               nvmet_put_namespace(ns);
 }
 
 void nvmet_req_complete(struct nvmet_req *req, u16 status)
index dc3b4dc..a3694a3 100644 (file)
@@ -1506,6 +1506,9 @@ static void nvmet_tcp_state_change(struct sock *sk)
                goto done;
 
        switch (sk->sk_state) {
+       case TCP_FIN_WAIT2:
+       case TCP_LAST_ACK:
+               break;
        case TCP_FIN_WAIT1:
        case TCP_CLOSE_WAIT:
        case TCP_CLOSE:
index c7ef69f..835bfda 100644 (file)
@@ -100,6 +100,7 @@ void nvmet_execute_identify_cns_cs_ns(struct nvmet_req *req)
        struct nvme_id_ns_zns *id_zns;
        u64 zsze;
        u16 status;
+       u32 mar, mor;
 
        if (le32_to_cpu(req->cmd->identify.nsid) == NVME_NSID_ALL) {
                req->error_loc = offsetof(struct nvme_identify, nsid);
@@ -130,8 +131,20 @@ void nvmet_execute_identify_cns_cs_ns(struct nvmet_req *req)
        zsze = (bdev_zone_sectors(req->ns->bdev) << 9) >>
                                        req->ns->blksize_shift;
        id_zns->lbafe[0].zsze = cpu_to_le64(zsze);
-       id_zns->mor = cpu_to_le32(bdev_max_open_zones(req->ns->bdev));
-       id_zns->mar = cpu_to_le32(bdev_max_active_zones(req->ns->bdev));
+
+       mor = bdev_max_open_zones(req->ns->bdev);
+       if (!mor)
+               mor = U32_MAX;
+       else
+               mor--;
+       id_zns->mor = cpu_to_le32(mor);
+
+       mar = bdev_max_active_zones(req->ns->bdev);
+       if (!mar)
+               mar = U32_MAX;
+       else
+               mar--;
+       id_zns->mar = cpu_to_le32(mar);
 
 done:
        status = nvmet_copy_to_sgl(req, 0, id_zns, sizeof(*id_zns));
index 7bc9292..1c573e7 100644 (file)
@@ -314,7 +314,7 @@ static int unflatten_dt_nodes(const void *blob,
        for (offset = 0;
             offset >= 0 && depth >= initial_depth;
             offset = fdt_next_node(blob, offset, &depth)) {
-               if (WARN_ON_ONCE(depth >= FDT_MAX_DEPTH))
+               if (WARN_ON_ONCE(depth >= FDT_MAX_DEPTH - 1))
                        continue;
 
                if (!IS_ENABLED(CONFIG_OF_KOBJ) &&
index 9be007c..a663860 100644 (file)
@@ -268,7 +268,7 @@ static int ioc_count;
 *   Each bit can represent a number of pages.
 *   LSbs represent lower addresses (IOVA's).
 *
-*   This was was copied from sba_iommu.c. Don't try to unify
+*   This was copied from sba_iommu.c. Don't try to unify
 *   the two resource managers unless a way to have different
 *   allocation policies is also adjusted. We'd like to avoid
 *   I/O TLB thrashing by having resource allocation policy
@@ -1380,15 +1380,17 @@ ccio_init_resource(struct resource *res, char *name, void __iomem *ioaddr)
        }
 }
 
-static void __init ccio_init_resources(struct ioc *ioc)
+static int __init ccio_init_resources(struct ioc *ioc)
 {
        struct resource *res = ioc->mmio_region;
        char *name = kmalloc(14, GFP_KERNEL);
-
+       if (unlikely(!name))
+               return -ENOMEM;
        snprintf(name, 14, "GSC Bus [%d/]", ioc->hw_path);
 
        ccio_init_resource(res, name, &ioc->ioc_regs->io_io_low);
        ccio_init_resource(res + 1, name, &ioc->ioc_regs->io_io_low_hv);
+       return 0;
 }
 
 static int new_ioc_area(struct resource *res, unsigned long size,
@@ -1543,7 +1545,11 @@ static int __init ccio_probe(struct parisc_device *dev)
                return -ENOMEM;
        }
        ccio_ioc_init(ioc);
-       ccio_init_resources(ioc);
+       if (ccio_init_resources(ioc)) {
+               iounmap(ioc->ioc_regs);
+               kfree(ioc);
+               return -ENOMEM;
+       }
        hppa_dma_ops = &ccio_ops;
 
        hba = kzalloc(sizeof(*hba), GFP_KERNEL);
index 3a8c986..bdef7a8 100644 (file)
@@ -221,16 +221,7 @@ static size_t irt_num_entry;
 
 static struct irt_entry *iosapic_alloc_irt(int num_entries)
 {
-       unsigned long a;
-
-       /* The IRT needs to be 8-byte aligned for the PDC call. 
-        * Normally kmalloc would guarantee larger alignment, but
-        * if CONFIG_DEBUG_SLAB is enabled, then we can get only
-        * 4-byte alignment on 32-bit kernels
-        */
-       a = (unsigned long)kmalloc(sizeof(struct irt_entry) * num_entries + 8, GFP_KERNEL);
-       a = (a + 7UL) & ~7UL;
-       return (struct irt_entry *)a;
+       return kcalloc(num_entries, sizeof(struct irt_entry), GFP_KERNEL);
 }
 
 /**
index 1e4a566..d4be9d2 100644 (file)
@@ -646,7 +646,7 @@ int lcd_print( const char *str )
                cancel_delayed_work_sync(&led_task);
 
        /* copy display string to buffer for procfs */
-       strlcpy(lcd_text, str, sizeof(lcd_text));
+       strscpy(lcd_text, str, sizeof(lcd_text));
 
        /* Set LCD Cursor to 1st character */
        gsc_writeb(lcd_info.reset_cmd1, LCD_CMD_REG);
index 1925ddc..731c5d8 100644 (file)
@@ -523,7 +523,7 @@ static int aspeed_peci_probe(struct platform_device *pdev)
                return PTR_ERR(priv->base);
 
        priv->irq = platform_get_irq(pdev, 0);
-       if (!priv->irq)
+       if (priv->irq < 0)
                return priv->irq;
 
        ret = devm_request_irq(&pdev->dev, priv->irq, aspeed_peci_irq_handler,
index 68eb61c..de4a7b3 100644 (file)
@@ -188,8 +188,6 @@ static void adev_release(struct device *dev)
 {
        struct auxiliary_device *adev = to_auxiliary_dev(dev);
 
-       auxiliary_device_uninit(adev);
-
        kfree(adev->name);
        kfree(adev);
 }
@@ -234,6 +232,7 @@ static void unregister_adev(void *_adev)
        struct auxiliary_device *adev = _adev;
 
        auxiliary_device_delete(adev);
+       auxiliary_device_uninit(adev);
 }
 
 static int devm_adev_add(struct device *dev, int idx)
index 513de1f..933b96e 100644 (file)
@@ -117,7 +117,7 @@ static int pmu_parse_irqs(struct arm_pmu *pmu)
 
        if (num_irqs == 1) {
                int irq = platform_get_irq(pdev, 0);
-               if (irq && irq_is_percpu_devid(irq))
+               if ((irq > 0) && irq_is_percpu_devid(irq))
                        return pmu_parse_percpu_irq(pmu, irq);
        }
 
index 3427787..2c20b0d 100644 (file)
@@ -72,7 +72,7 @@ static void pmu_legacy_ctr_start(struct perf_event *event, u64 ival)
        local64_set(&hwc->prev_count, initial_val);
 }
 
-/**
+/*
  * This is just a simple implementation to allow legacy implementations
  * compatible with new RISC-V PMU driver framework.
  * This driver only allows reading two counters i.e CYCLE & INSTRET.
index 6f6681b..8de4ca2 100644 (file)
@@ -473,7 +473,7 @@ static int pmu_sbi_get_ctrinfo(int nctr)
        if (!pmu_ctr_list)
                return -ENOMEM;
 
-       for (i = 0; i <= nctr; i++) {
+       for (i = 0; i < nctr; i++) {
                ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_GET_INFO, i, 0, 0, 0, 0, 0);
                if (ret.error)
                        /* The logical counter ids are not expected to be contiguous */
index c5fd154..c7df8c5 100644 (file)
@@ -331,6 +331,7 @@ struct ocelot_pinctrl {
        const struct ocelot_pincfg_data *pincfg_data;
        struct ocelot_pmx_func func[FUNC_MAX];
        u8 stride;
+       struct workqueue_struct *wq;
 };
 
 struct ocelot_match_data {
@@ -338,6 +339,11 @@ struct ocelot_match_data {
        struct ocelot_pincfg_data pincfg_data;
 };
 
+struct ocelot_irq_work {
+       struct work_struct irq_work;
+       struct irq_desc *irq_desc;
+};
+
 #define LUTON_P(p, f0, f1)                                             \
 static struct ocelot_pin_caps luton_pin_##p = {                                \
        .pin = p,                                                       \
@@ -1813,6 +1819,75 @@ static void ocelot_irq_mask(struct irq_data *data)
        gpiochip_disable_irq(chip, gpio);
 }
 
+static void ocelot_irq_work(struct work_struct *work)
+{
+       struct ocelot_irq_work *w = container_of(work, struct ocelot_irq_work, irq_work);
+       struct irq_chip *parent_chip = irq_desc_get_chip(w->irq_desc);
+       struct gpio_chip *chip = irq_desc_get_chip_data(w->irq_desc);
+       struct irq_data *data = irq_desc_get_irq_data(w->irq_desc);
+       unsigned int gpio = irqd_to_hwirq(data);
+
+       local_irq_disable();
+       chained_irq_enter(parent_chip, w->irq_desc);
+       generic_handle_domain_irq(chip->irq.domain, gpio);
+       chained_irq_exit(parent_chip, w->irq_desc);
+       local_irq_enable();
+
+       kfree(w);
+}
+
+static void ocelot_irq_unmask_level(struct irq_data *data)
+{
+       struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+       struct ocelot_pinctrl *info = gpiochip_get_data(chip);
+       struct irq_desc *desc = irq_data_to_desc(data);
+       unsigned int gpio = irqd_to_hwirq(data);
+       unsigned int bit = BIT(gpio % 32);
+       bool ack = false, active = false;
+       u8 trigger_level;
+       int val;
+
+       trigger_level = irqd_get_trigger_type(data);
+
+       /* Check if the interrupt line is still active. */
+       regmap_read(info->map, REG(OCELOT_GPIO_IN, info, gpio), &val);
+       if ((!(val & bit) && trigger_level == IRQ_TYPE_LEVEL_LOW) ||
+             (val & bit && trigger_level == IRQ_TYPE_LEVEL_HIGH))
+               active = true;
+
+       /*
+        * Check if the interrupt controller has seen any changes in the
+        * interrupt line.
+        */
+       regmap_read(info->map, REG(OCELOT_GPIO_INTR, info, gpio), &val);
+       if (val & bit)
+               ack = true;
+
+       /* Enable the interrupt now */
+       gpiochip_enable_irq(chip, gpio);
+       regmap_update_bits(info->map, REG(OCELOT_GPIO_INTR_ENA, info, gpio),
+                          bit, bit);
+
+       /*
+        * In case the interrupt line is still active and the interrupt
+        * controller has not seen any changes in the interrupt line, then it
+        * means that there happen another interrupt while the line was active.
+        * So we missed that one, so we need to kick the interrupt again
+        * handler.
+        */
+       if (active && !ack) {
+               struct ocelot_irq_work *work;
+
+               work = kmalloc(sizeof(*work), GFP_ATOMIC);
+               if (!work)
+                       return;
+
+               work->irq_desc = desc;
+               INIT_WORK(&work->irq_work, ocelot_irq_work);
+               queue_work(info->wq, &work->irq_work);
+       }
+}
+
 static void ocelot_irq_unmask(struct irq_data *data)
 {
        struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
@@ -1836,13 +1911,12 @@ static void ocelot_irq_ack(struct irq_data *data)
 
 static int ocelot_irq_set_type(struct irq_data *data, unsigned int type);
 
-static struct irq_chip ocelot_eoi_irqchip = {
+static struct irq_chip ocelot_level_irqchip = {
        .name           = "gpio",
        .irq_mask       = ocelot_irq_mask,
-       .irq_eoi        = ocelot_irq_ack,
-       .irq_unmask     = ocelot_irq_unmask,
-       .flags          = IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED |
-                         IRQCHIP_IMMUTABLE,
+       .irq_ack        = ocelot_irq_ack,
+       .irq_unmask     = ocelot_irq_unmask_level,
+       .flags          = IRQCHIP_IMMUTABLE,
        .irq_set_type   = ocelot_irq_set_type,
        GPIOCHIP_IRQ_RESOURCE_HELPERS
 };
@@ -1859,14 +1933,9 @@ static struct irq_chip ocelot_irqchip = {
 
 static int ocelot_irq_set_type(struct irq_data *data, unsigned int type)
 {
-       type &= IRQ_TYPE_SENSE_MASK;
-
-       if (!(type & (IRQ_TYPE_EDGE_BOTH | IRQ_TYPE_LEVEL_HIGH)))
-               return -EINVAL;
-
-       if (type & IRQ_TYPE_LEVEL_HIGH)
-               irq_set_chip_handler_name_locked(data, &ocelot_eoi_irqchip,
-                                                handle_fasteoi_irq, NULL);
+       if (type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
+               irq_set_chip_handler_name_locked(data, &ocelot_level_irqchip,
+                                                handle_level_irq, NULL);
        if (type & IRQ_TYPE_EDGE_BOTH)
                irq_set_chip_handler_name_locked(data, &ocelot_irqchip,
                                                 handle_edge_irq, NULL);
@@ -1996,6 +2065,10 @@ static int ocelot_pinctrl_probe(struct platform_device *pdev)
        if (!info->desc)
                return -ENOMEM;
 
+       info->wq = alloc_ordered_workqueue("ocelot_ordered", 0);
+       if (!info->wq)
+               return -ENOMEM;
+
        info->pincfg_data = &data->pincfg_data;
 
        reset = devm_reset_control_get_optional_shared(dev, "switch");
@@ -2018,7 +2091,7 @@ static int ocelot_pinctrl_probe(struct platform_device *pdev)
                dev_err(dev, "Failed to create regmap\n");
                return PTR_ERR(info->map);
        }
-       dev_set_drvdata(dev, info->map);
+       dev_set_drvdata(dev, info);
        info->dev = dev;
 
        /* Pinconf registers */
@@ -2043,6 +2116,15 @@ static int ocelot_pinctrl_probe(struct platform_device *pdev)
        return 0;
 }
 
+static int ocelot_pinctrl_remove(struct platform_device *pdev)
+{
+       struct ocelot_pinctrl *info = platform_get_drvdata(pdev);
+
+       destroy_workqueue(info->wq);
+
+       return 0;
+}
+
 static struct platform_driver ocelot_pinctrl_driver = {
        .driver = {
                .name = "pinctrl-ocelot",
@@ -2050,6 +2132,7 @@ static struct platform_driver ocelot_pinctrl_driver = {
                .suppress_bind_attrs = true,
        },
        .probe = ocelot_pinctrl_probe,
+       .remove = ocelot_pinctrl_remove,
 };
 module_platform_driver(ocelot_pinctrl_driver);
 MODULE_LICENSE("Dual MIT/GPL");
index 6bec7f1..704a99d 100644 (file)
@@ -530,10 +530,10 @@ DECLARE_MSM_GPIO_PINS(187);
 DECLARE_MSM_GPIO_PINS(188);
 DECLARE_MSM_GPIO_PINS(189);
 
-static const unsigned int sdc2_clk_pins[] = { 190 };
-static const unsigned int sdc2_cmd_pins[] = { 191 };
-static const unsigned int sdc2_data_pins[] = { 192 };
-static const unsigned int ufs_reset_pins[] = { 193 };
+static const unsigned int ufs_reset_pins[] = { 190 };
+static const unsigned int sdc2_clk_pins[] = { 191 };
+static const unsigned int sdc2_cmd_pins[] = { 192 };
+static const unsigned int sdc2_data_pins[] = { 193 };
 
 enum sc8180x_functions {
        msm_mux_adsp_ext,
@@ -1582,7 +1582,7 @@ static const int sc8180x_acpi_reserved_gpios[] = {
 static const struct msm_gpio_wakeirq_map sc8180x_pdc_map[] = {
        { 3, 31 }, { 5, 32 }, { 8, 33 }, { 9, 34 }, { 10, 100 }, { 12, 104 },
        { 24, 37 }, { 26, 38 }, { 27, 41 }, { 28, 42 }, { 30, 39 }, { 36, 43 },
-       { 37, 43 }, { 38, 45 }, { 39, 118 }, { 39, 125 }, { 41, 47 },
+       { 37, 44 }, { 38, 45 }, { 39, 118 }, { 39, 125 }, { 41, 47 },
        { 42, 48 }, { 46, 50 }, { 47, 49 }, { 48, 51 }, { 49, 53 }, { 50, 52 },
        { 51, 116 }, { 51, 123 }, { 53, 54 }, { 54, 55 }, { 55, 56 },
        { 56, 57 }, { 58, 58 }, { 60, 60 }, { 68, 62 }, { 70, 63 }, { 76, 86 },
index afc1f5d..b82ad13 100644 (file)
@@ -99,7 +99,7 @@ MODULE_DEVICE_TABLE(of, a100_r_pinctrl_match);
 static struct platform_driver a100_r_pinctrl_driver = {
        .probe  = a100_r_pinctrl_probe,
        .driver = {
-               .name           = "sun50iw10p1-r-pinctrl",
+               .name           = "sun50i-a100-r-pinctrl",
                .of_match_table = a100_r_pinctrl_match,
        },
 };
index 8be13d4..1ae3c56 100644 (file)
@@ -928,7 +928,6 @@ static int mlxbf_tmfifo_virtio_find_vqs(struct virtio_device *vdev,
                                        struct virtqueue *vqs[],
                                        vq_callback_t *callbacks[],
                                        const char * const names[],
-                                       u32 sizes[],
                                        const bool *ctx,
                                        struct irq_affinity *desc)
 {
index 55834cc..1e071df 100644 (file)
@@ -460,8 +460,6 @@ static int mlxreg_lc_power_on_off(struct mlxreg_lc *mlxreg_lc, u8 action)
        u32 regval;
        int err;
 
-       mutex_lock(&mlxreg_lc->lock);
-
        err = regmap_read(mlxreg_lc->par_regmap, mlxreg_lc->data->reg_pwr, &regval);
        if (err)
                goto regmap_read_fail;
@@ -474,7 +472,6 @@ static int mlxreg_lc_power_on_off(struct mlxreg_lc *mlxreg_lc, u8 action)
        err = regmap_write(mlxreg_lc->par_regmap, mlxreg_lc->data->reg_pwr, regval);
 
 regmap_read_fail:
-       mutex_unlock(&mlxreg_lc->lock);
        return err;
 }
 
@@ -491,8 +488,6 @@ static int mlxreg_lc_enable_disable(struct mlxreg_lc *mlxreg_lc, bool action)
         * line card which is already has been enabled. Disabling does not affect the disabled line
         * card.
         */
-       mutex_lock(&mlxreg_lc->lock);
-
        err = regmap_read(mlxreg_lc->par_regmap, mlxreg_lc->data->reg_ena, &regval);
        if (err)
                goto regmap_read_fail;
@@ -505,7 +500,6 @@ static int mlxreg_lc_enable_disable(struct mlxreg_lc *mlxreg_lc, bool action)
        err = regmap_write(mlxreg_lc->par_regmap, mlxreg_lc->data->reg_ena, regval);
 
 regmap_read_fail:
-       mutex_unlock(&mlxreg_lc->lock);
        return err;
 }
 
@@ -538,6 +532,15 @@ mlxreg_lc_sn4800_c16_config_init(struct mlxreg_lc *mlxreg_lc, void *regmap,
 static void
 mlxreg_lc_state_update(struct mlxreg_lc *mlxreg_lc, enum mlxreg_lc_state state, u8 action)
 {
+       if (action)
+               mlxreg_lc->state |= state;
+       else
+               mlxreg_lc->state &= ~state;
+}
+
+static void
+mlxreg_lc_state_update_locked(struct mlxreg_lc *mlxreg_lc, enum mlxreg_lc_state state, u8 action)
+{
        mutex_lock(&mlxreg_lc->lock);
 
        if (action)
@@ -560,8 +563,11 @@ static int mlxreg_lc_event_handler(void *handle, enum mlxreg_hotplug_kind kind,
        dev_info(mlxreg_lc->dev, "linecard#%d state %d event kind %d action %d\n",
                 mlxreg_lc->data->slot, mlxreg_lc->state, kind, action);
 
-       if (!(mlxreg_lc->state & MLXREG_LC_INITIALIZED))
+       mutex_lock(&mlxreg_lc->lock);
+       if (!(mlxreg_lc->state & MLXREG_LC_INITIALIZED)) {
+               mutex_unlock(&mlxreg_lc->lock);
                return 0;
+       }
 
        switch (kind) {
        case MLXREG_HOTPLUG_LC_SYNCED:
@@ -574,7 +580,7 @@ static int mlxreg_lc_event_handler(void *handle, enum mlxreg_hotplug_kind kind,
                if (!(mlxreg_lc->state & MLXREG_LC_POWERED) && action) {
                        err = mlxreg_lc_power_on_off(mlxreg_lc, 1);
                        if (err)
-                               return err;
+                               goto mlxreg_lc_power_on_off_fail;
                }
                /* In case line card is configured - enable it. */
                if (mlxreg_lc->state & MLXREG_LC_CONFIGURED && action)
@@ -588,12 +594,13 @@ static int mlxreg_lc_event_handler(void *handle, enum mlxreg_hotplug_kind kind,
                                /* In case line card is configured - enable it. */
                                if (mlxreg_lc->state & MLXREG_LC_CONFIGURED)
                                        err = mlxreg_lc_enable_disable(mlxreg_lc, 1);
+                               mutex_unlock(&mlxreg_lc->lock);
                                return err;
                        }
                        err = mlxreg_lc_create_static_devices(mlxreg_lc, mlxreg_lc->main_devs,
                                                              mlxreg_lc->main_devs_num);
                        if (err)
-                               return err;
+                               goto mlxreg_lc_create_static_devices_fail;
 
                        /* In case line card is already in ready state - enable it. */
                        if (mlxreg_lc->state & MLXREG_LC_CONFIGURED)
@@ -620,6 +627,10 @@ static int mlxreg_lc_event_handler(void *handle, enum mlxreg_hotplug_kind kind,
                break;
        }
 
+mlxreg_lc_power_on_off_fail:
+mlxreg_lc_create_static_devices_fail:
+       mutex_unlock(&mlxreg_lc->lock);
+
        return err;
 }
 
@@ -665,7 +676,7 @@ static int mlxreg_lc_completion_notify(void *handle, struct i2c_adapter *parent,
                if (err)
                        goto mlxreg_lc_create_static_devices_failed;
 
-               mlxreg_lc_state_update(mlxreg_lc, MLXREG_LC_POWERED, 1);
+               mlxreg_lc_state_update_locked(mlxreg_lc, MLXREG_LC_POWERED, 1);
        }
 
        /* Verify if line card is synchronized. */
@@ -676,7 +687,7 @@ static int mlxreg_lc_completion_notify(void *handle, struct i2c_adapter *parent,
        /* Power on line card if necessary. */
        if (regval & mlxreg_lc->data->mask) {
                mlxreg_lc->state |= MLXREG_LC_SYNCED;
-               mlxreg_lc_state_update(mlxreg_lc, MLXREG_LC_SYNCED, 1);
+               mlxreg_lc_state_update_locked(mlxreg_lc, MLXREG_LC_SYNCED, 1);
                if (mlxreg_lc->state & ~MLXREG_LC_POWERED) {
                        err = mlxreg_lc_power_on_off(mlxreg_lc, 1);
                        if (err)
@@ -684,7 +695,7 @@ static int mlxreg_lc_completion_notify(void *handle, struct i2c_adapter *parent,
                }
        }
 
-       mlxreg_lc_state_update(mlxreg_lc, MLXREG_LC_INITIALIZED, 1);
+       mlxreg_lc_state_update_locked(mlxreg_lc, MLXREG_LC_INITIALIZED, 1);
 
        return 0;
 
@@ -814,10 +825,9 @@ static int mlxreg_lc_probe(struct platform_device *pdev)
 
        mutex_init(&mlxreg_lc->lock);
        /* Set event notification callback. */
-       if (data->notifier) {
-               data->notifier->user_handler = mlxreg_lc_event_handler;
-               data->notifier->handle = mlxreg_lc;
-       }
+       data->notifier->user_handler = mlxreg_lc_event_handler;
+       data->notifier->handle = mlxreg_lc;
+
        data->hpdev.adapter = i2c_get_adapter(data->hpdev.nr);
        if (!data->hpdev.adapter) {
                dev_err(&pdev->dev, "Failed to get adapter for bus %d\n",
@@ -863,7 +873,6 @@ static int mlxreg_lc_probe(struct platform_device *pdev)
        if (err) {
                dev_err(&pdev->dev, "Failed to sync regmap for client %s at bus %d at addr 0x%02x\n",
                        data->hpdev.brdinfo->type, data->hpdev.nr, data->hpdev.brdinfo->addr);
-               err = PTR_ERR(regmap);
                goto regcache_sync_fail;
        }
 
@@ -878,16 +887,14 @@ static int mlxreg_lc_probe(struct platform_device *pdev)
        if (err)
                goto mlxreg_lc_config_init_fail;
 
-       return err;
+       return 0;
 
 mlxreg_lc_config_init_fail:
 regcache_sync_fail:
 regmap_write_fail:
 devm_regmap_init_i2c_fail:
-       if (data->hpdev.client) {
-               i2c_unregister_device(data->hpdev.client);
-               data->hpdev.client = NULL;
-       }
+       i2c_unregister_device(data->hpdev.client);
+       data->hpdev.client = NULL;
 i2c_new_device_fail:
        i2c_put_adapter(data->hpdev.adapter);
        data->hpdev.adapter = NULL;
@@ -905,6 +912,8 @@ static int mlxreg_lc_remove(struct platform_device *pdev)
        struct mlxreg_core_data *data = dev_get_platdata(&pdev->dev);
        struct mlxreg_lc *mlxreg_lc = platform_get_drvdata(pdev);
 
+       mlxreg_lc_state_update_locked(mlxreg_lc, MLXREG_LC_INITIALIZED, 0);
+
        /*
         * Probing and removing are invoked by hotplug events raised upon line card insertion and
         * removing. If probing procedure fails all data is cleared. However, hotplug event still
index d5655f6..5859110 100644 (file)
@@ -86,38 +86,38 @@ static const struct software_node ssam_node_bas_dtx = {
        .parent = &ssam_node_root,
 };
 
-/* HID keyboard (TID1). */
-static const struct software_node ssam_node_hid_tid1_keyboard = {
+/* HID keyboard (SAM, TID=1). */
+static const struct software_node ssam_node_hid_sam_keyboard = {
        .name = "ssam:01:15:01:01:00",
        .parent = &ssam_node_root,
 };
 
-/* HID pen stash (TID1; pen taken / stashed away evens). */
-static const struct software_node ssam_node_hid_tid1_penstash = {
+/* HID pen stash (SAM, TID=1; pen taken / stashed away evens). */
+static const struct software_node ssam_node_hid_sam_penstash = {
        .name = "ssam:01:15:01:02:00",
        .parent = &ssam_node_root,
 };
 
-/* HID touchpad (TID1). */
-static const struct software_node ssam_node_hid_tid1_touchpad = {
+/* HID touchpad (SAM, TID=1). */
+static const struct software_node ssam_node_hid_sam_touchpad = {
        .name = "ssam:01:15:01:03:00",
        .parent = &ssam_node_root,
 };
 
-/* HID device instance 6 (TID1, unknown HID device). */
-static const struct software_node ssam_node_hid_tid1_iid6 = {
+/* HID device instance 6 (SAM, TID=1, HID sensor collection). */
+static const struct software_node ssam_node_hid_sam_sensors = {
        .name = "ssam:01:15:01:06:00",
        .parent = &ssam_node_root,
 };
 
-/* HID device instance 7 (TID1, unknown HID device). */
-static const struct software_node ssam_node_hid_tid1_iid7 = {
+/* HID device instance 7 (SAM, TID=1, UCM UCSI HID client). */
+static const struct software_node ssam_node_hid_sam_ucm_ucsi = {
        .name = "ssam:01:15:01:07:00",
        .parent = &ssam_node_root,
 };
 
-/* HID system controls (TID1). */
-static const struct software_node ssam_node_hid_tid1_sysctrl = {
+/* HID system controls (SAM, TID=1). */
+static const struct software_node ssam_node_hid_sam_sysctrl = {
        .name = "ssam:01:15:01:08:00",
        .parent = &ssam_node_root,
 };
@@ -182,8 +182,8 @@ static const struct software_node ssam_node_hid_kip_touchpad = {
        .parent = &ssam_node_hub_kip,
 };
 
-/* HID device instance 5 (KIP hub, unknown HID device). */
-static const struct software_node ssam_node_hid_kip_iid5 = {
+/* HID device instance 5 (KIP hub, type-cover firmware update). */
+static const struct software_node ssam_node_hid_kip_fwupd = {
        .name = "ssam:01:15:02:05:00",
        .parent = &ssam_node_hub_kip,
 };
@@ -241,12 +241,12 @@ static const struct software_node *ssam_node_group_sls[] = {
        &ssam_node_bat_main,
        &ssam_node_tmp_pprof,
        &ssam_node_pos_tablet_switch,
-       &ssam_node_hid_tid1_keyboard,
-       &ssam_node_hid_tid1_penstash,
-       &ssam_node_hid_tid1_touchpad,
-       &ssam_node_hid_tid1_iid6,
-       &ssam_node_hid_tid1_iid7,
-       &ssam_node_hid_tid1_sysctrl,
+       &ssam_node_hid_sam_keyboard,
+       &ssam_node_hid_sam_penstash,
+       &ssam_node_hid_sam_touchpad,
+       &ssam_node_hid_sam_sensors,
+       &ssam_node_hid_sam_ucm_ucsi,
+       &ssam_node_hid_sam_sysctrl,
        NULL,
 };
 
@@ -278,7 +278,9 @@ static const struct software_node *ssam_node_group_sp8[] = {
        &ssam_node_hid_kip_keyboard,
        &ssam_node_hid_kip_penstash,
        &ssam_node_hid_kip_touchpad,
-       &ssam_node_hid_kip_iid5,
+       &ssam_node_hid_kip_fwupd,
+       &ssam_node_hid_sam_sensors,
+       &ssam_node_hid_sam_ucm_ucsi,
        NULL,
 };
 
@@ -325,6 +327,9 @@ static const struct acpi_device_id ssam_platform_hub_match[] = {
        /* Surface Laptop Go 1 */
        { "MSHW0118", (unsigned long)ssam_node_group_slg1 },
 
+       /* Surface Laptop Go 2 */
+       { "MSHW0290", (unsigned long)ssam_node_group_slg1 },
+
        /* Surface Laptop Studio */
        { "MSHW0123", (unsigned long)ssam_node_group_sls },
 
index e0230ea..f1259d8 100644 (file)
@@ -99,6 +99,7 @@ static const struct key_entry acer_wmi_keymap[] __initconst = {
        {KE_KEY, 0x22, {KEY_PROG2} },    /* Arcade */
        {KE_KEY, 0x23, {KEY_PROG3} },    /* P_Key */
        {KE_KEY, 0x24, {KEY_PROG4} },    /* Social networking_Key */
+       {KE_KEY, 0x27, {KEY_HELP} },
        {KE_KEY, 0x29, {KEY_PROG3} },    /* P_Key for TM8372 */
        {KE_IGNORE, 0x41, {KEY_MUTE} },
        {KE_IGNORE, 0x42, {KEY_PREVIOUSSONG} },
@@ -112,7 +113,13 @@ static const struct key_entry acer_wmi_keymap[] __initconst = {
        {KE_IGNORE, 0x48, {KEY_VOLUMEUP} },
        {KE_IGNORE, 0x49, {KEY_VOLUMEDOWN} },
        {KE_IGNORE, 0x4a, {KEY_VOLUMEDOWN} },
-       {KE_IGNORE, 0x61, {KEY_SWITCHVIDEOMODE} },
+       /*
+        * 0x61 is KEY_SWITCHVIDEOMODE. Usually this is a duplicate input event
+        * with the "Video Bus" input device events. But sometimes it is not
+        * a dup. Map it to KEY_UNKNOWN instead of using KE_IGNORE so that
+        * udev/hwdb can override it on systems where it is not a dup.
+        */
+       {KE_KEY, 0x61, {KEY_UNKNOWN} },
        {KE_IGNORE, 0x62, {KEY_BRIGHTNESSUP} },
        {KE_IGNORE, 0x63, {KEY_BRIGHTNESSDOWN} },
        {KE_KEY, 0x64, {KEY_SWITCHVIDEOMODE} }, /* Display Switch */
index 89b604e..eec7d0e 100644 (file)
@@ -107,7 +107,7 @@ module_param(fnlock_default, bool, 0444);
 #define WMI_EVENT_MASK                 0xFFFF
 
 #define FAN_CURVE_POINTS               8
-#define FAN_CURVE_BUF_LEN              (FAN_CURVE_POINTS * 2)
+#define FAN_CURVE_BUF_LEN              32
 #define FAN_CURVE_DEV_CPU              0x00
 #define FAN_CURVE_DEV_GPU              0x01
 /* Mask to determine if setting temperature or percentage */
@@ -1118,7 +1118,7 @@ static int asus_wmi_led_init(struct asus_wmi *asus)
        }
 
        if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MICMUTE_LED)) {
-               asus->micmute_led.name = "asus::micmute";
+               asus->micmute_led.name = "platform::micmute";
                asus->micmute_led.max_brightness = 1;
                asus->micmute_led.brightness = ledtrig_audio_get(LED_AUDIO_MICMUTE);
                asus->micmute_led.brightness_set_blocking = micmute_led_set;
@@ -2233,8 +2233,10 @@ static int fan_curve_get_factory_default(struct asus_wmi *asus, u32 fan_dev)
        curves = &asus->custom_fan_curves[fan_idx];
        err = asus_wmi_evaluate_method_buf(asus->dsts_id, fan_dev, mode, buf,
                                           FAN_CURVE_BUF_LEN);
-       if (err)
+       if (err) {
+               pr_warn("%s (0x%08x) failed: %d\n", __func__, fan_dev, err);
                return err;
+       }
 
        fan_curve_copy_from_buf(curves, buf);
        curves->device_id = fan_dev;
@@ -2252,9 +2254,6 @@ static int fan_curve_check_present(struct asus_wmi *asus, bool *available,
 
        err = fan_curve_get_factory_default(asus, fan_dev);
        if (err) {
-               pr_debug("fan_curve_get_factory_default(0x%08x) failed: %d\n",
-                        fan_dev, err);
-               /* Don't cause probe to fail on devices without fan-curves */
                return 0;
        }
 
index fb2e141..384d096 100644 (file)
@@ -42,10 +42,24 @@ static int p2sb_get_devfn(unsigned int *devfn)
        return 0;
 }
 
+/* Copy resource from the first BAR of the device in question */
 static int p2sb_read_bar0(struct pci_dev *pdev, struct resource *mem)
 {
-       /* Copy resource from the first BAR of the device in question */
-       *mem = pdev->resource[0];
+       struct resource *bar0 = &pdev->resource[0];
+
+       /* Make sure we have no dangling pointers in the output */
+       memset(mem, 0, sizeof(*mem));
+
+       /*
+        * We copy only selected fields from the original resource.
+        * Because a PCI device will be removed soon, we may not use
+        * any allocated data, hence we may not copy any pointers.
+        */
+       mem->start = bar0->start;
+       mem->end = bar0->end;
+       mem->flags = bar0->flags;
+       mem->desc = bar0->desc;
+
        return 0;
 }
 
index 154317e..5c757c7 100644 (file)
@@ -232,7 +232,7 @@ static void pmc_power_off(void)
        pm1_cnt_port = acpi_base_addr + PM1_CNT;
 
        pm1_cnt_value = inl(pm1_cnt_port);
-       pm1_cnt_value &= SLEEP_TYPE_MASK;
+       pm1_cnt_value &= ~SLEEP_TYPE_MASK;
        pm1_cnt_value |= SLEEP_TYPE_S5;
        pm1_cnt_value |= SLEEP_ENABLE;
 
index 67feed2..5362f1a 100644 (file)
@@ -328,6 +328,7 @@ static const struct acpi_device_id smi_acpi_ids[] = {
        { "INT3515", (unsigned long)&int3515_data },
        /* Non-conforming _HID for Cirrus Logic already released */
        { "CLSA0100", (unsigned long)&cs35l41_hda },
+       { "CLSA0101", (unsigned long)&cs35l41_hda },
        { }
 };
 MODULE_DEVICE_TABLE(acpi, smi_acpi_ids);
index 22d4e86..2dbb9fc 100644 (file)
@@ -10592,10 +10592,9 @@ static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm)
        /* Ensure initial values are correct */
        dytc_profile_refresh();
 
-       /* Set AMT correctly now we know current profile */
-       if ((dytc_capabilities & BIT(DYTC_FC_PSC)) &&
-           (dytc_capabilities & BIT(DYTC_FC_AMT)))
-           dytc_control_amt(dytc_current_profile == PLATFORM_PROFILE_BALANCED);
+       /* Workaround for https://bugzilla.kernel.org/show_bug.cgi?id=216347 */
+       if (dytc_capabilities & BIT(DYTC_FC_PSC))
+               dytc_profile_set(NULL, PLATFORM_PROFILE_BALANCED);
 
        return 0;
 }
index 4803759..4acd6fa 100644 (file)
@@ -663,9 +663,23 @@ static const struct x86_i2c_client_info chuwi_hi8_i2c_clients[] __initconst = {
        },
 };
 
+static int __init chuwi_hi8_init(void)
+{
+       /*
+        * Avoid the acpi_unregister_gsi() call in x86_acpi_irq_helper_get()
+        * breaking the touchscreen + logging various errors when the Windows
+        * BIOS is used.
+        */
+       if (acpi_dev_present("MSSL0001", NULL, 1))
+               return -ENODEV;
+
+       return 0;
+}
+
 static const struct x86_dev_info chuwi_hi8_info __initconst = {
        .i2c_client_info = chuwi_hi8_i2c_clients,
        .i2c_client_count = ARRAY_SIZE(chuwi_hi8_i2c_clients),
+       .init = chuwi_hi8_init,
 };
 
 #define CZC_EC_EXTRA_PORT      0x68
index 7150b1d..d3e8dc3 100644 (file)
@@ -2733,13 +2733,18 @@ static int _regulator_do_enable(struct regulator_dev *rdev)
  */
 static int _regulator_handle_consumer_enable(struct regulator *regulator)
 {
+       int ret;
        struct regulator_dev *rdev = regulator->rdev;
 
        lockdep_assert_held_once(&rdev->mutex.base);
 
        regulator->enable_count++;
-       if (regulator->uA_load && regulator->enable_count == 1)
-               return drms_uA_update(rdev);
+       if (regulator->uA_load && regulator->enable_count == 1) {
+               ret = drms_uA_update(rdev);
+               if (ret)
+                       regulator->enable_count--;
+               return ret;
+       }
 
        return 0;
 }
@@ -4784,10 +4789,10 @@ int regulator_bulk_get(struct device *dev, int num_consumers,
                consumers[i].consumer = regulator_get(dev,
                                                      consumers[i].supply);
                if (IS_ERR(consumers[i].consumer)) {
-                       consumers[i].consumer = NULL;
                        ret = dev_err_probe(dev, PTR_ERR(consumers[i].consumer),
                                            "Failed to get supply '%s'",
                                            consumers[i].supply);
+                       consumers[i].consumer = NULL;
                        goto err;
                }
 
index 6b61702..d899d6e 100644 (file)
@@ -766,7 +766,7 @@ static int pfuze100_regulator_probe(struct i2c_client *client,
                ((pfuze_chip->chip_id == PFUZE3000) ? "3000" : "3001"))));
 
        memcpy(pfuze_chip->regulator_descs, pfuze_chip->pfuze_regulators,
-               sizeof(pfuze_chip->regulator_descs));
+               regulator_num * sizeof(struct pfuze_regulator));
 
        ret = pfuze_parse_regulators_dt(pfuze_chip);
        if (ret)
index 81c4f57..0f7706e 100644 (file)
@@ -158,7 +158,6 @@ static int rproc_virtio_find_vqs(struct virtio_device *vdev, unsigned int nvqs,
                                 struct virtqueue *vqs[],
                                 vq_callback_t *callbacks[],
                                 const char * const names[],
-                                u32 sizes[],
                                 const bool * ctx,
                                 struct irq_affinity *desc)
 {
index 8f1d1cf..59ac98f 100644 (file)
@@ -2086,6 +2086,9 @@ static inline void ap_scan_adapter(int ap)
  */
 static bool ap_get_configuration(void)
 {
+       if (!ap_qci_info)       /* QCI not supported */
+               return false;
+
        memcpy(ap_qci_info_old, ap_qci_info, sizeof(*ap_qci_info));
        ap_fetch_qci_info(ap_qci_info);
 
index 0c40af1..0f17933 100644 (file)
@@ -148,12 +148,16 @@ struct ap_driver {
        /*
         * Called at the start of the ap bus scan function when
         * the crypto config information (qci) has changed.
+        * This callback is not invoked if there is no AP
+        * QCI support available.
         */
        void (*on_config_changed)(struct ap_config_info *new_config_info,
                                  struct ap_config_info *old_config_info);
        /*
         * Called at the end of the ap bus scan function when
         * the crypto config information (qci) has changed.
+        * This callback is not invoked if there is no AP
+        * QCI support available.
         */
        void (*on_scan_complete)(struct ap_config_info *new_config_info,
                                 struct ap_config_info *old_config_info);
index 896896e..a10dbe6 100644 (file)
@@ -637,7 +637,6 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs,
                               struct virtqueue *vqs[],
                               vq_callback_t *callbacks[],
                               const char * const names[],
-                              u32 sizes[],
                               const bool *ctx,
                               struct irq_affinity *desc)
 {
index 0738238..9857dba 100644 (file)
@@ -182,6 +182,15 @@ void scsi_remove_host(struct Scsi_Host *shost)
        mutex_unlock(&shost->scan_mutex);
        scsi_proc_host_rm(shost);
 
+       /*
+        * New SCSI devices cannot be attached anymore because of the SCSI host
+        * state so drop the tag set refcnt. Wait until the tag set refcnt drops
+        * to zero because .exit_cmd_priv implementations may need the host
+        * pointer.
+        */
+       kref_put(&shost->tagset_refcnt, scsi_mq_free_tags);
+       wait_for_completion(&shost->tagset_freed);
+
        spin_lock_irqsave(shost->host_lock, flags);
        if (scsi_host_set_state(shost, SHOST_DEL))
                BUG_ON(scsi_host_set_state(shost, SHOST_DEL_RECOVERY));
@@ -190,15 +199,6 @@ void scsi_remove_host(struct Scsi_Host *shost)
        transport_unregister_device(&shost->shost_gendev);
        device_unregister(&shost->shost_dev);
        device_del(&shost->shost_gendev);
-
-       /*
-        * After scsi_remove_host() has returned the scsi LLD module can be
-        * unloaded and/or the host resources can be released. Hence wait until
-        * the dependent SCSI targets and devices are gone before returning.
-        */
-       wait_event(shost->targets_wq, atomic_read(&shost->target_count) == 0);
-
-       scsi_mq_destroy_tags(shost);
 }
 EXPORT_SYMBOL(scsi_remove_host);
 
@@ -254,6 +254,9 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
        if (error)
                goto fail;
 
+       kref_init(&shost->tagset_refcnt);
+       init_completion(&shost->tagset_freed);
+
        /*
         * Increase usage count temporarily here so that calling
         * scsi_autopm_put_host() will trigger runtime idle if there is
@@ -309,8 +312,8 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
        return error;
 
        /*
-        * Any resources associated with the SCSI host in this function except
-        * the tag set will be freed by scsi_host_dev_release().
+        * Any host allocation in this function will be freed in
+        * scsi_host_dev_release().
         */
  out_del_dev:
        device_del(&shost->shost_dev);
@@ -326,7 +329,7 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
        pm_runtime_disable(&shost->shost_gendev);
        pm_runtime_set_suspended(&shost->shost_gendev);
        pm_runtime_put_noidle(&shost->shost_gendev);
-       scsi_mq_destroy_tags(shost);
+       kref_put(&shost->tagset_refcnt, scsi_mq_free_tags);
  fail:
        return error;
 }
@@ -406,7 +409,6 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
        INIT_LIST_HEAD(&shost->starved_list);
        init_waitqueue_head(&shost->host_wait);
        mutex_init(&shost->scan_mutex);
-       init_waitqueue_head(&shost->targets_wq);
 
        index = ida_alloc(&host_index_ida, GFP_KERNEL);
        if (index < 0) {
index c69c5a0..55a1ad6 100644 (file)
@@ -8053,7 +8053,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
        /* Allocate device driver memory */
        rc = lpfc_mem_alloc(phba, SGL_ALIGN_SZ);
        if (rc)
-               return -ENOMEM;
+               goto out_destroy_workqueue;
 
        /* IF Type 2 ports get initialized now. */
        if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) >=
@@ -8481,6 +8481,9 @@ out_free_bsmbx:
        lpfc_destroy_bootstrap_mbox(phba);
 out_free_mem:
        lpfc_mem_free(phba);
+out_destroy_workqueue:
+       destroy_workqueue(phba->wq);
+       phba->wq = NULL;
        return rc;
 }
 
index 084c0f9..938a5e4 100644 (file)
@@ -4272,7 +4272,7 @@ lpfc_fcp_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn,
                    lpfc_cmd->result == IOERR_ABORT_REQUESTED ||
                    lpfc_cmd->result == IOERR_RPI_SUSPENDED ||
                    lpfc_cmd->result == IOERR_SLER_CMD_RCV_FAILURE) {
-                       cmd->result = DID_REQUEUE << 16;
+                       cmd->result = DID_TRANSPORT_DISRUPTED << 16;
                        break;
                }
                if ((lpfc_cmd->result == IOERR_RX_DMA_FAILED ||
@@ -4562,7 +4562,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
                            lpfc_cmd->result == IOERR_NO_RESOURCES ||
                            lpfc_cmd->result == IOERR_ABORT_REQUESTED ||
                            lpfc_cmd->result == IOERR_SLER_CMD_RCV_FAILURE) {
-                               cmd->result = DID_REQUEUE << 16;
+                               cmd->result = DID_TRANSPORT_DISRUPTED << 16;
                                break;
                        }
                        if ((lpfc_cmd->result == IOERR_RX_DMA_FAILED ||
index a3e117a..f6c37a9 100644 (file)
@@ -7153,22 +7153,18 @@ static int megasas_alloc_ctrl_mem(struct megasas_instance *instance)
        switch (instance->adapter_type) {
        case MFI_SERIES:
                if (megasas_alloc_mfi_ctrl_mem(instance))
-                       goto fail;
+                       return -ENOMEM;
                break;
        case AERO_SERIES:
        case VENTURA_SERIES:
        case THUNDERBOLT_SERIES:
        case INVADER_SERIES:
                if (megasas_alloc_fusion_context(instance))
-                       goto fail;
+                       return -ENOMEM;
                break;
        }
 
        return 0;
- fail:
-       kfree(instance->reply_map);
-       instance->reply_map = NULL;
-       return -ENOMEM;
 }
 
 /*
index e48d426..09c5fe3 100644 (file)
@@ -5310,7 +5310,6 @@ megasas_alloc_fusion_context(struct megasas_instance *instance)
                if (!fusion->log_to_span) {
                        dev_err(&instance->pdev->dev, "Failed from %s %d\n",
                                __func__, __LINE__);
-                       kfree(instance->ctrl_context);
                        return -ENOMEM;
                }
        }
index def37a7..bd6a5f1 100644 (file)
@@ -3670,6 +3670,7 @@ static struct fw_event_work *dequeue_next_fw_event(struct MPT3SAS_ADAPTER *ioc)
                fw_event = list_first_entry(&ioc->fw_event_list,
                                struct fw_event_work, list);
                list_del_init(&fw_event->list);
+               fw_event_work_put(fw_event);
        }
        spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
 
@@ -3751,7 +3752,6 @@ _scsih_fw_event_cleanup_queue(struct MPT3SAS_ADAPTER *ioc)
                if (cancel_work_sync(&fw_event->work))
                        fw_event_work_put(fw_event);
 
-               fw_event_work_put(fw_event);
        }
        ioc->fw_events_cleanup = 0;
 }
index 2b2f682..62666df 100644 (file)
@@ -6935,14 +6935,8 @@ qlt_24xx_config_rings(struct scsi_qla_host *vha)
 
        if (ha->flags.msix_enabled) {
                if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
-                       if (IS_QLA2071(ha)) {
-                               /* 4 ports Baker: Enable Interrupt Handshake */
-                               icb->msix_atio = 0;
-                               icb->firmware_options_2 |= cpu_to_le32(BIT_26);
-                       } else {
-                               icb->msix_atio = cpu_to_le16(msix->entry);
-                               icb->firmware_options_2 &= cpu_to_le32(~BIT_26);
-                       }
+                       icb->msix_atio = cpu_to_le16(msix->entry);
+                       icb->firmware_options_2 &= cpu_to_le32(~BIT_26);
                        ql_dbg(ql_dbg_init, vha, 0xf072,
                            "Registering ICB vector 0x%x for atio que.\n",
                            msix->entry);
index 086ec5b..c59eac7 100644 (file)
@@ -586,13 +586,10 @@ EXPORT_SYMBOL(scsi_device_get);
  */
 void scsi_device_put(struct scsi_device *sdev)
 {
-       /*
-        * Decreasing the module reference count before the device reference
-        * count is safe since scsi_remove_host() only returns after all
-        * devices have been removed.
-        */
-       module_put(sdev->host->hostt->module);
+       struct module *mod = sdev->host->hostt->module;
+
        put_device(&sdev->sdev_gendev);
+       module_put(mod);
 }
 EXPORT_SYMBOL(scsi_device_put);
 
index 4dbd29a..96e7e3e 100644 (file)
@@ -111,7 +111,7 @@ scsi_set_blocked(struct scsi_cmnd *cmd, int reason)
        }
 }
 
-static void scsi_mq_requeue_cmd(struct scsi_cmnd *cmd)
+static void scsi_mq_requeue_cmd(struct scsi_cmnd *cmd, unsigned long msecs)
 {
        struct request *rq = scsi_cmd_to_rq(cmd);
 
@@ -121,7 +121,12 @@ static void scsi_mq_requeue_cmd(struct scsi_cmnd *cmd)
        } else {
                WARN_ON_ONCE(true);
        }
-       blk_mq_requeue_request(rq, true);
+
+       if (msecs) {
+               blk_mq_requeue_request(rq, false);
+               blk_mq_delay_kick_requeue_list(rq->q, msecs);
+       } else
+               blk_mq_requeue_request(rq, true);
 }
 
 /**
@@ -651,14 +656,6 @@ static unsigned int scsi_rq_err_bytes(const struct request *rq)
        return bytes;
 }
 
-/* Helper for scsi_io_completion() when "reprep" action required. */
-static void scsi_io_completion_reprep(struct scsi_cmnd *cmd,
-                                     struct request_queue *q)
-{
-       /* A new command will be prepared and issued. */
-       scsi_mq_requeue_cmd(cmd);
-}
-
 static bool scsi_cmd_runtime_exceeced(struct scsi_cmnd *cmd)
 {
        struct request *req = scsi_cmd_to_rq(cmd);
@@ -676,14 +673,21 @@ static bool scsi_cmd_runtime_exceeced(struct scsi_cmnd *cmd)
        return false;
 }
 
+/*
+ * When ALUA transition state is returned, reprep the cmd to
+ * use the ALUA handler's transition timeout. Delay the reprep
+ * 1 sec to avoid aggressive retries of the target in that
+ * state.
+ */
+#define ALUA_TRANSITION_REPREP_DELAY   1000
+
 /* Helper for scsi_io_completion() when special action required. */
 static void scsi_io_completion_action(struct scsi_cmnd *cmd, int result)
 {
-       struct request_queue *q = cmd->device->request_queue;
        struct request *req = scsi_cmd_to_rq(cmd);
        int level = 0;
-       enum {ACTION_FAIL, ACTION_REPREP, ACTION_RETRY,
-             ACTION_DELAYED_RETRY} action;
+       enum {ACTION_FAIL, ACTION_REPREP, ACTION_DELAYED_REPREP,
+             ACTION_RETRY, ACTION_DELAYED_RETRY} action;
        struct scsi_sense_hdr sshdr;
        bool sense_valid;
        bool sense_current = true;      /* false implies "deferred sense" */
@@ -772,8 +776,8 @@ static void scsi_io_completion_action(struct scsi_cmnd *cmd, int result)
                                        action = ACTION_DELAYED_RETRY;
                                        break;
                                case 0x0a: /* ALUA state transition */
-                                       blk_stat = BLK_STS_TRANSPORT;
-                                       fallthrough;
+                                       action = ACTION_DELAYED_REPREP;
+                                       break;
                                default:
                                        action = ACTION_FAIL;
                                        break;
@@ -832,7 +836,10 @@ static void scsi_io_completion_action(struct scsi_cmnd *cmd, int result)
                        return;
                fallthrough;
        case ACTION_REPREP:
-               scsi_io_completion_reprep(cmd, q);
+               scsi_mq_requeue_cmd(cmd, 0);
+               break;
+       case ACTION_DELAYED_REPREP:
+               scsi_mq_requeue_cmd(cmd, ALUA_TRANSITION_REPREP_DELAY);
                break;
        case ACTION_RETRY:
                /* Retry the same command immediately */
@@ -926,7 +933,7 @@ static int scsi_io_completion_nz_result(struct scsi_cmnd *cmd, int result,
  * command block will be released and the queue function will be goosed. If we
  * are not done then we have to figure out what to do next:
  *
- *   a) We can call scsi_io_completion_reprep().  The request will be
+ *   a) We can call scsi_mq_requeue_cmd().  The request will be
  *     unprepared and put back on the queue.  Then a new command will
  *     be created for it.  This should be used if we made forward
  *     progress, or if we want to switch from READ(10) to READ(6) for
@@ -942,7 +949,6 @@ static int scsi_io_completion_nz_result(struct scsi_cmnd *cmd, int result,
 void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
 {
        int result = cmd->result;
-       struct request_queue *q = cmd->device->request_queue;
        struct request *req = scsi_cmd_to_rq(cmd);
        blk_status_t blk_stat = BLK_STS_OK;
 
@@ -979,7 +985,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
         * request just queue the command up again.
         */
        if (likely(result == 0))
-               scsi_io_completion_reprep(cmd, q);
+               scsi_mq_requeue_cmd(cmd, 0);
        else
                scsi_io_completion_action(cmd, result);
 }
@@ -1542,7 +1548,6 @@ static blk_status_t scsi_prepare_cmd(struct request *req)
        scsi_init_command(sdev, cmd);
 
        cmd->eh_eflags = 0;
-       cmd->allowed = 0;
        cmd->prot_type = 0;
        cmd->prot_flags = 0;
        cmd->submitter = 0;
@@ -1593,6 +1598,8 @@ static blk_status_t scsi_prepare_cmd(struct request *req)
                        return ret;
        }
 
+       /* Usually overridden by the ULP */
+       cmd->allowed = 0;
        memset(cmd->cmnd, 0, sizeof(cmd->cmnd));
        return scsi_cmd_to_driver(cmd)->init_command(cmd);
 }
@@ -1976,9 +1983,13 @@ int scsi_mq_setup_tags(struct Scsi_Host *shost)
        return blk_mq_alloc_tag_set(tag_set);
 }
 
-void scsi_mq_destroy_tags(struct Scsi_Host *shost)
+void scsi_mq_free_tags(struct kref *kref)
 {
+       struct Scsi_Host *shost = container_of(kref, typeof(*shost),
+                                              tagset_refcnt);
+
        blk_mq_free_tag_set(&shost->tag_set);
+       complete(&shost->tagset_freed);
 }
 
 /**
index 429663b..f385b3f 100644 (file)
@@ -94,7 +94,7 @@ extern void scsi_run_host_queues(struct Scsi_Host *shost);
 extern void scsi_requeue_run_queue(struct work_struct *work);
 extern void scsi_start_queue(struct scsi_device *sdev);
 extern int scsi_mq_setup_tags(struct Scsi_Host *shost);
-extern void scsi_mq_destroy_tags(struct Scsi_Host *shost);
+extern void scsi_mq_free_tags(struct kref *kref);
 extern void scsi_exit_queue(void);
 extern void scsi_evt_thread(struct work_struct *work);
 
index ac60597..5d27f51 100644 (file)
@@ -340,6 +340,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
                kfree(sdev);
                goto out;
        }
+       kref_get(&sdev->host->tagset_refcnt);
        sdev->request_queue = q;
        q->queuedata = sdev;
        __scsi_init_queue(sdev->host, q);
@@ -406,14 +407,9 @@ static void scsi_target_destroy(struct scsi_target *starget)
 static void scsi_target_dev_release(struct device *dev)
 {
        struct device *parent = dev->parent;
-       struct Scsi_Host *shost = dev_to_shost(parent);
        struct scsi_target *starget = to_scsi_target(dev);
 
        kfree(starget);
-
-       if (atomic_dec_return(&shost->target_count) == 0)
-               wake_up(&shost->targets_wq);
-
        put_device(parent);
 }
 
@@ -526,10 +522,6 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
        starget->state = STARGET_CREATED;
        starget->scsi_level = SCSI_2;
        starget->max_target_blocked = SCSI_DEFAULT_TARGET_BLOCKED;
-       init_waitqueue_head(&starget->sdev_wq);
-
-       atomic_inc(&shost->target_count);
-
  retry:
        spin_lock_irqsave(shost->host_lock, flags);
 
index 9dad2fd..5d61f58 100644 (file)
@@ -443,15 +443,18 @@ static void scsi_device_cls_release(struct device *class_dev)
 
 static void scsi_device_dev_release_usercontext(struct work_struct *work)
 {
-       struct scsi_device *sdev = container_of(work, struct scsi_device,
-                                               ew.work);
-       struct scsi_target *starget = sdev->sdev_target;
+       struct scsi_device *sdev;
        struct device *parent;
        struct list_head *this, *tmp;
        struct scsi_vpd *vpd_pg80 = NULL, *vpd_pg83 = NULL;
        struct scsi_vpd *vpd_pg0 = NULL, *vpd_pg89 = NULL;
        struct scsi_vpd *vpd_pgb0 = NULL, *vpd_pgb1 = NULL, *vpd_pgb2 = NULL;
        unsigned long flags;
+       struct module *mod;
+
+       sdev = container_of(work, struct scsi_device, ew.work);
+
+       mod = sdev->host->hostt->module;
 
        scsi_dh_release_device(sdev);
 
@@ -513,16 +516,19 @@ static void scsi_device_dev_release_usercontext(struct work_struct *work)
        kfree(sdev->inquiry);
        kfree(sdev);
 
-       if (starget && atomic_dec_return(&starget->sdev_count) == 0)
-               wake_up(&starget->sdev_wq);
-
        if (parent)
                put_device(parent);
+       module_put(mod);
 }
 
 static void scsi_device_dev_release(struct device *dev)
 {
        struct scsi_device *sdp = to_scsi_device(dev);
+
+       /* Set module pointer as NULL in case of module unloading */
+       if (!try_module_get(sdp->host->hostt->module))
+               sdp->host->hostt->module = NULL;
+
        execute_in_process_context(scsi_device_dev_release_usercontext,
                                   &sdp->ew);
 }
@@ -1470,6 +1476,7 @@ void __scsi_remove_device(struct scsi_device *sdev)
        mutex_unlock(&sdev->state_mutex);
 
        blk_mq_destroy_queue(sdev->request_queue);
+       kref_put(&sdev->host->tagset_refcnt, scsi_mq_free_tags);
        cancel_work_sync(&sdev->requeue_work);
 
        if (sdev->host->hostt->slave_destroy)
@@ -1529,14 +1536,6 @@ static void __scsi_remove_target(struct scsi_target *starget)
                goto restart;
        }
        spin_unlock_irqrestore(shost->host_lock, flags);
-
-       /*
-        * After scsi_remove_target() returns its caller can remove resources
-        * associated with @starget, e.g. an rport or session. Wait until all
-        * devices associated with @starget have been removed to prevent that
-        * a SCSI error handling callback function triggers a use-after-free.
-        */
-       wait_event(starget->sdev_wq, atomic_read(&starget->sdev_count) == 0);
 }
 
 /**
@@ -1647,9 +1646,6 @@ void scsi_sysfs_device_initialize(struct scsi_device *sdev)
        list_add_tail(&sdev->same_target_siblings, &starget->devices);
        list_add_tail(&sdev->siblings, &shost->__devices);
        spin_unlock_irqrestore(shost->host_lock, flags);
-
-       atomic_inc(&starget->sdev_count);
-
        /*
         * device can now only be removed via __scsi_remove_device() so hold
         * the target.  Target will be held in CREATED state until something
index 8f79fa6..eb76ba0 100644 (file)
@@ -103,7 +103,6 @@ static void sd_config_discard(struct scsi_disk *, unsigned int);
 static void sd_config_write_same(struct scsi_disk *);
 static int  sd_revalidate_disk(struct gendisk *);
 static void sd_unlock_native_capacity(struct gendisk *disk);
-static void sd_start_done_work(struct work_struct *work);
 static int  sd_probe(struct device *);
 static int  sd_remove(struct device *);
 static void sd_shutdown(struct device *);
@@ -3471,7 +3470,6 @@ static int sd_probe(struct device *dev)
        sdkp->max_retries = SD_MAX_RETRIES;
        atomic_set(&sdkp->openers, 0);
        atomic_set(&sdkp->device->ioerr_cnt, 0);
-       INIT_WORK(&sdkp->start_done_work, sd_start_done_work);
 
        if (!sdp->request_queue->rq_timeout) {
                if (sdp->type != TYPE_MOD)
@@ -3594,69 +3592,12 @@ static void scsi_disk_release(struct device *dev)
        kfree(sdkp);
 }
 
-/* Process sense data after a START command finished. */
-static void sd_start_done_work(struct work_struct *work)
-{
-       struct scsi_disk *sdkp = container_of(work, typeof(*sdkp),
-                                             start_done_work);
-       struct scsi_sense_hdr sshdr;
-       int res = sdkp->start_result;
-
-       if (res == 0)
-               return;
-
-       sd_print_result(sdkp, "Start/Stop Unit failed", res);
-
-       if (res < 0)
-               return;
-
-       if (scsi_normalize_sense(sdkp->start_sense_buffer,
-                                sdkp->start_sense_len, &sshdr))
-               sd_print_sense_hdr(sdkp, &sshdr);
-}
-
-/* A START command finished. May be called from interrupt context. */
-static void sd_start_done(struct request *req, blk_status_t status)
-{
-       const struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(req);
-       struct scsi_disk *sdkp = scsi_disk(req->q->disk);
-
-       sdkp->start_result = scmd->result;
-       WARN_ON_ONCE(scmd->sense_len > SCSI_SENSE_BUFFERSIZE);
-       sdkp->start_sense_len = scmd->sense_len;
-       memcpy(sdkp->start_sense_buffer, scmd->sense_buffer,
-              ARRAY_SIZE(sdkp->start_sense_buffer));
-       WARN_ON_ONCE(!schedule_work(&sdkp->start_done_work));
-}
-
-/* Submit a START command asynchronously. */
-static int sd_submit_start(struct scsi_disk *sdkp, u8 cmd[], u8 cmd_len)
-{
-       struct scsi_device *sdev = sdkp->device;
-       struct request_queue *q = sdev->request_queue;
-       struct request *req;
-       struct scsi_cmnd *scmd;
-
-       req = scsi_alloc_request(q, REQ_OP_DRV_IN, BLK_MQ_REQ_PM);
-       if (IS_ERR(req))
-               return PTR_ERR(req);
-
-       scmd = blk_mq_rq_to_pdu(req);
-       scmd->cmd_len = cmd_len;
-       memcpy(scmd->cmnd, cmd, cmd_len);
-       scmd->allowed = sdkp->max_retries;
-       req->timeout = SD_TIMEOUT;
-       req->rq_flags |= RQF_PM | RQF_QUIET;
-       req->end_io = sd_start_done;
-       blk_execute_rq_nowait(req, /*at_head=*/true);
-
-       return 0;
-}
-
 static int sd_start_stop_device(struct scsi_disk *sdkp, int start)
 {
        unsigned char cmd[6] = { START_STOP };  /* START_VALID */
+       struct scsi_sense_hdr sshdr;
        struct scsi_device *sdp = sdkp->device;
+       int res;
 
        if (start)
                cmd[4] |= 1;    /* START */
@@ -3667,10 +3608,23 @@ static int sd_start_stop_device(struct scsi_disk *sdkp, int start)
        if (!scsi_device_online(sdp))
                return -ENODEV;
 
-       /* Wait until processing of sense data has finished. */
-       flush_work(&sdkp->start_done_work);
+       res = scsi_execute(sdp, cmd, DMA_NONE, NULL, 0, NULL, &sshdr,
+                       SD_TIMEOUT, sdkp->max_retries, 0, RQF_PM, NULL);
+       if (res) {
+               sd_print_result(sdkp, "Start/Stop Unit failed", res);
+               if (res > 0 && scsi_sense_valid(&sshdr)) {
+                       sd_print_sense_hdr(sdkp, &sshdr);
+                       /* 0x3a is medium not present */
+                       if (sshdr.asc == 0x3a)
+                               res = 0;
+               }
+       }
 
-       return sd_submit_start(sdkp, cmd, sizeof(cmd));
+       /* SCSI error codes must not go to the generic layer */
+       if (res)
+               return -EIO;
+
+       return 0;
 }
 
 /*
@@ -3697,8 +3651,6 @@ static void sd_shutdown(struct device *dev)
                sd_printk(KERN_NOTICE, sdkp, "Stopping disk\n");
                sd_start_stop_device(sdkp, 0);
        }
-
-       flush_work(&sdkp->start_done_work);
 }
 
 static int sd_suspend_common(struct device *dev, bool ignore_stop_errors)
index b891877..5eea762 100644 (file)
@@ -150,11 +150,6 @@ struct scsi_disk {
        unsigned        urswrz : 1;
        unsigned        security : 1;
        unsigned        ignore_medium_access_errors : 1;
-
-       int             start_result;
-       u32             start_sense_len;
-       u8              start_sense_buffer[SCSI_SENSE_BUFFERSIZE];
-       struct work_struct start_done_work;
 };
 #define to_scsi_disk(obj) container_of(obj, struct scsi_disk, disk_dev)
 
index fe000da..8ced292 100644 (file)
@@ -2012,7 +2012,7 @@ static int storvsc_probe(struct hv_device *device,
         */
        host_dev->handle_error_wq =
                        alloc_ordered_workqueue("storvsc_error_wq_%d",
-                                               WQ_MEM_RECLAIM,
+                                               0,
                                                host->host_no);
        if (!host_dev->handle_error_wq) {
                ret = -ENOMEM;
index d6b30d5..775da69 100644 (file)
@@ -684,13 +684,14 @@ static int brcmstb_pm_probe(struct platform_device *pdev)
        const struct of_device_id *of_id = NULL;
        struct device_node *dn;
        void __iomem *base;
-       int ret, i;
+       int ret, i, s;
 
        /* AON ctrl registers */
        base = brcmstb_ioremap_match(aon_ctrl_dt_ids, 0, NULL);
        if (IS_ERR(base)) {
                pr_err("error mapping AON_CTRL\n");
-               return PTR_ERR(base);
+               ret = PTR_ERR(base);
+               goto aon_err;
        }
        ctrl.aon_ctrl_base = base;
 
@@ -700,8 +701,10 @@ static int brcmstb_pm_probe(struct platform_device *pdev)
                /* Assume standard offset */
                ctrl.aon_sram = ctrl.aon_ctrl_base +
                                     AON_CTRL_SYSTEM_DATA_RAM_OFS;
+               s = 0;
        } else {
                ctrl.aon_sram = base;
+               s = 1;
        }
 
        writel_relaxed(0, ctrl.aon_sram + AON_REG_PANIC);
@@ -711,7 +714,8 @@ static int brcmstb_pm_probe(struct platform_device *pdev)
                                     (const void **)&ddr_phy_data);
        if (IS_ERR(base)) {
                pr_err("error mapping DDR PHY\n");
-               return PTR_ERR(base);
+               ret = PTR_ERR(base);
+               goto ddr_phy_err;
        }
        ctrl.support_warm_boot = ddr_phy_data->supports_warm_boot;
        ctrl.pll_status_offset = ddr_phy_data->pll_status_offset;
@@ -731,17 +735,20 @@ static int brcmstb_pm_probe(struct platform_device *pdev)
        for_each_matching_node(dn, ddr_shimphy_dt_ids) {
                i = ctrl.num_memc;
                if (i >= MAX_NUM_MEMC) {
+                       of_node_put(dn);
                        pr_warn("too many MEMCs (max %d)\n", MAX_NUM_MEMC);
                        break;
                }
 
                base = of_io_request_and_map(dn, 0, dn->full_name);
                if (IS_ERR(base)) {
+                       of_node_put(dn);
                        if (!ctrl.support_warm_boot)
                                break;
 
                        pr_err("error mapping DDR SHIMPHY %d\n", i);
-                       return PTR_ERR(base);
+                       ret = PTR_ERR(base);
+                       goto ddr_shimphy_err;
                }
                ctrl.memcs[i].ddr_shimphy_base = base;
                ctrl.num_memc++;
@@ -752,14 +759,18 @@ static int brcmstb_pm_probe(struct platform_device *pdev)
        for_each_matching_node(dn, brcmstb_memc_of_match) {
                base = of_iomap(dn, 0);
                if (!base) {
+                       of_node_put(dn);
                        pr_err("error mapping DDR Sequencer %d\n", i);
-                       return -ENOMEM;
+                       ret = -ENOMEM;
+                       goto brcmstb_memc_err;
                }
 
                of_id = of_match_node(brcmstb_memc_of_match, dn);
                if (!of_id) {
                        iounmap(base);
-                       return -EINVAL;
+                       of_node_put(dn);
+                       ret = -EINVAL;
+                       goto brcmstb_memc_err;
                }
 
                ddr_seq_data = of_id->data;
@@ -779,21 +790,24 @@ static int brcmstb_pm_probe(struct platform_device *pdev)
        dn = of_find_matching_node(NULL, sram_dt_ids);
        if (!dn) {
                pr_err("SRAM not found\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto brcmstb_memc_err;
        }
 
        ret = brcmstb_init_sram(dn);
        of_node_put(dn);
        if (ret) {
                pr_err("error setting up SRAM for PM\n");
-               return ret;
+               goto brcmstb_memc_err;
        }
 
        ctrl.pdev = pdev;
 
        ctrl.s3_params = kmalloc(sizeof(*ctrl.s3_params), GFP_KERNEL);
-       if (!ctrl.s3_params)
-               return -ENOMEM;
+       if (!ctrl.s3_params) {
+               ret = -ENOMEM;
+               goto s3_params_err;
+       }
        ctrl.s3_params_pa = dma_map_single(&pdev->dev, ctrl.s3_params,
                                           sizeof(*ctrl.s3_params),
                                           DMA_TO_DEVICE);
@@ -813,7 +827,21 @@ static int brcmstb_pm_probe(struct platform_device *pdev)
 
 out:
        kfree(ctrl.s3_params);
-
+s3_params_err:
+       iounmap(ctrl.boot_sram);
+brcmstb_memc_err:
+       for (i--; i >= 0; i--)
+               iounmap(ctrl.memcs[i].ddr_ctrl);
+ddr_shimphy_err:
+       for (i = 0; i < ctrl.num_memc; i++)
+               iounmap(ctrl.memcs[i].ddr_shimphy_base);
+
+       iounmap(ctrl.memcs[0].ddr_phy_base);
+ddr_phy_err:
+       iounmap(ctrl.aon_ctrl_base);
+       if (s)
+               iounmap(ctrl.aon_sram);
+aon_err:
        pr_warn("PM: initialization failed with code %d\n", ret);
 
        return ret;
index 07d52ca..fcec6ed 100644 (file)
@@ -24,6 +24,7 @@ config FSL_MC_DPIO
         tristate "QorIQ DPAA2 DPIO driver"
         depends on FSL_MC_BUS
         select SOC_BUS
+        select FSL_GUTS
         select DIMLIB
         help
          Driver for the DPAA2 DPIO object.  A DPIO provides queue and
index 6383a4e..88aee59 100644 (file)
@@ -335,6 +335,8 @@ static int imx_pgc_power_up(struct generic_pm_domain *genpd)
                }
        }
 
+       reset_control_assert(domain->reset);
+
        /* Enable reset clocks for all devices in the domain */
        ret = clk_bulk_prepare_enable(domain->num_clks, domain->clks);
        if (ret) {
@@ -342,7 +344,8 @@ static int imx_pgc_power_up(struct generic_pm_domain *genpd)
                goto out_regulator_disable;
        }
 
-       reset_control_assert(domain->reset);
+       /* delays for reset to propagate */
+       udelay(5);
 
        if (domain->bits.pxx) {
                /* request the domain to power up */
index dff7529..972f289 100644 (file)
@@ -243,7 +243,6 @@ static int imx8m_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 = imx8m_blk_ctrl_power_on;
index 9df970e..3a992a6 100644 (file)
@@ -169,7 +169,7 @@ struct qcom_swrm_ctrl {
        u8 wcmd_id;
        struct qcom_swrm_port_config pconfig[QCOM_SDW_MAX_PORTS];
        struct sdw_stream_runtime *sruntime[SWRM_MAX_DAIS];
-       enum sdw_slave_status status[SDW_MAX_DEVICES];
+       enum sdw_slave_status status[SDW_MAX_DEVICES + 1];
        int (*reg_read)(struct qcom_swrm_ctrl *ctrl, int reg, u32 *val);
        int (*reg_write)(struct qcom_swrm_ctrl *ctrl, int reg, int val);
        u32 slave_status;
@@ -420,7 +420,7 @@ static int qcom_swrm_get_alert_slave_dev_num(struct qcom_swrm_ctrl *ctrl)
 
        ctrl->reg_read(ctrl, SWRM_MCP_SLV_STATUS, &val);
 
-       for (dev_num = 0; dev_num < SDW_MAX_DEVICES; dev_num++) {
+       for (dev_num = 0; dev_num <= SDW_MAX_DEVICES; dev_num++) {
                status = (val >> (dev_num * SWRM_MCP_SLV_STATUS_SZ));
 
                if ((status & SWRM_MCP_SLV_STATUS_MASK) == SDW_SLAVE_ALERT) {
@@ -440,7 +440,7 @@ static void qcom_swrm_get_device_status(struct qcom_swrm_ctrl *ctrl)
        ctrl->reg_read(ctrl, SWRM_MCP_SLV_STATUS, &val);
        ctrl->slave_status = val;
 
-       for (i = 0; i < SDW_MAX_DEVICES; i++) {
+       for (i = 0; i <= SDW_MAX_DEVICES; i++) {
                u32 s;
 
                s = (val >> (i * 2));
@@ -1356,10 +1356,6 @@ static int qcom_swrm_probe(struct platform_device *pdev)
        ctrl->bus.compute_params = &qcom_swrm_compute_params;
        ctrl->bus.clk_stop_timeout = 300;
 
-       ctrl->audio_cgcr = devm_reset_control_get_exclusive(dev, "swr_audio_cgcr");
-       if (IS_ERR(ctrl->audio_cgcr))
-               dev_err(dev, "Failed to get audio_cgcr reset required for soundwire-v1.6.0\n");
-
        ret = qcom_swrm_get_port_config(ctrl);
        if (ret)
                goto err_clk;
index 267342d..2dcbe16 100644 (file)
@@ -116,6 +116,7 @@ bitbang_txrx_le_cpha0(struct spi_device *spi,
 {
        /* if (cpol == 0) this is SPI_MODE_0; else this is SPI_MODE_2 */
 
+       u8 rxbit = bits - 1;
        u32 oldbit = !(word & 1);
        /* clock starts at inactive polarity */
        for (; likely(bits); bits--) {
@@ -135,7 +136,7 @@ bitbang_txrx_le_cpha0(struct spi_device *spi,
                /* sample LSB (from slave) on leading edge */
                word >>= 1;
                if ((flags & SPI_MASTER_NO_RX) == 0)
-                       word |= getmiso(spi) << (bits - 1);
+                       word |= getmiso(spi) << rxbit;
                setsck(spi, cpol);
        }
        return word;
@@ -148,6 +149,7 @@ bitbang_txrx_le_cpha1(struct spi_device *spi,
 {
        /* if (cpol == 0) this is SPI_MODE_1; else this is SPI_MODE_3 */
 
+       u8 rxbit = bits - 1;
        u32 oldbit = !(word & 1);
        /* clock starts at inactive polarity */
        for (; likely(bits); bits--) {
@@ -168,7 +170,7 @@ bitbang_txrx_le_cpha1(struct spi_device *spi,
                /* sample LSB (from slave) on trailing edge */
                word >>= 1;
                if ((flags & SPI_MASTER_NO_RX) == 0)
-                       word |= getmiso(spi) << (bits - 1);
+                       word |= getmiso(spi) << rxbit;
        }
        return word;
 }
index 72b1a5a..e12ab5b 100644 (file)
@@ -39,6 +39,7 @@
 #define CQSPI_DISABLE_DAC_MODE         BIT(1)
 #define CQSPI_SUPPORT_EXTERNAL_DMA     BIT(2)
 #define CQSPI_NO_SUPPORT_WR_COMPLETION BIT(3)
+#define CQSPI_SLOW_SRAM                BIT(4)
 
 /* Capabilities */
 #define CQSPI_SUPPORTS_OCTAL           BIT(0)
@@ -87,6 +88,7 @@ struct cqspi_st {
        bool                    use_dma_read;
        u32                     pd_dev_id;
        bool                    wr_completion;
+       bool                    slow_sram;
 };
 
 struct cqspi_driver_platdata {
@@ -333,7 +335,10 @@ static irqreturn_t cqspi_irq_handler(int this_irq, void *dev)
                }
        }
 
-       irq_status &= CQSPI_IRQ_MASK_RD | CQSPI_IRQ_MASK_WR;
+       else if (!cqspi->slow_sram)
+               irq_status &= CQSPI_IRQ_MASK_RD | CQSPI_IRQ_MASK_WR;
+       else
+               irq_status &= CQSPI_REG_IRQ_WATERMARK | CQSPI_IRQ_MASK_WR;
 
        if (irq_status)
                complete(&cqspi->transfer_complete);
@@ -673,7 +678,18 @@ static int cqspi_indirect_read_execute(struct cqspi_flash_pdata *f_pdata,
        /* Clear all interrupts. */
        writel(CQSPI_IRQ_STATUS_MASK, reg_base + CQSPI_REG_IRQSTATUS);
 
-       writel(CQSPI_IRQ_MASK_RD, reg_base + CQSPI_REG_IRQMASK);
+       /*
+        * On SoCFPGA platform reading the SRAM is slow due to
+        * hardware limitation and causing read interrupt storm to CPU,
+        * so enabling only watermark interrupt to disable all read
+        * interrupts later as we want to run "bytes to read" loop with
+        * all the read interrupts disabled for max performance.
+        */
+
+       if (!cqspi->slow_sram)
+               writel(CQSPI_IRQ_MASK_RD, reg_base + CQSPI_REG_IRQMASK);
+       else
+               writel(CQSPI_REG_IRQ_WATERMARK, reg_base + CQSPI_REG_IRQMASK);
 
        reinit_completion(&cqspi->transfer_complete);
        writel(CQSPI_REG_INDIRECTRD_START_MASK,
@@ -684,6 +700,13 @@ static int cqspi_indirect_read_execute(struct cqspi_flash_pdata *f_pdata,
                                                 msecs_to_jiffies(CQSPI_READ_TIMEOUT_MS)))
                        ret = -ETIMEDOUT;
 
+               /*
+                * Disable all read interrupts until
+                * we are out of "bytes to read"
+                */
+               if (cqspi->slow_sram)
+                       writel(0x0, reg_base + CQSPI_REG_IRQMASK);
+
                bytes_to_read = cqspi_get_rd_sram_level(cqspi);
 
                if (ret && bytes_to_read == 0) {
@@ -715,8 +738,11 @@ static int cqspi_indirect_read_execute(struct cqspi_flash_pdata *f_pdata,
                        bytes_to_read = cqspi_get_rd_sram_level(cqspi);
                }
 
-               if (remaining > 0)
+               if (remaining > 0) {
                        reinit_completion(&cqspi->transfer_complete);
+                       if (cqspi->slow_sram)
+                               writel(CQSPI_REG_IRQ_WATERMARK, reg_base + CQSPI_REG_IRQMASK);
+               }
        }
 
        /* Check indirect done status */
@@ -1667,6 +1693,8 @@ static int cqspi_probe(struct platform_device *pdev)
                        cqspi->use_dma_read = true;
                if (ddata->quirks & CQSPI_NO_SUPPORT_WR_COMPLETION)
                        cqspi->wr_completion = false;
+               if (ddata->quirks & CQSPI_SLOW_SRAM)
+                       cqspi->slow_sram = true;
 
                if (of_device_is_compatible(pdev->dev.of_node,
                                            "xlnx,versal-ospi-1.0"))
@@ -1779,7 +1807,9 @@ static const struct cqspi_driver_platdata intel_lgm_qspi = {
 };
 
 static const struct cqspi_driver_platdata socfpga_qspi = {
-       .quirks = CQSPI_DISABLE_DAC_MODE | CQSPI_NO_SUPPORT_WR_COMPLETION,
+       .quirks = CQSPI_DISABLE_DAC_MODE
+                       | CQSPI_NO_SUPPORT_WR_COMPLETION
+                       | CQSPI_SLOW_SRAM,
 };
 
 static const struct cqspi_driver_platdata versal_ospi = {
index 0bc7daa..e4cb52e 100644 (file)
@@ -156,6 +156,7 @@ struct meson_spicc_device {
        void __iomem                    *base;
        struct clk                      *core;
        struct clk                      *pclk;
+       struct clk_divider              pow2_div;
        struct clk                      *clk;
        struct spi_message              *message;
        struct spi_transfer             *xfer;
@@ -168,6 +169,8 @@ struct meson_spicc_device {
        unsigned long                   xfer_remain;
 };
 
+#define pow2_clk_to_spicc(_div) container_of(_div, struct meson_spicc_device, pow2_div)
+
 static void meson_spicc_oen_enable(struct meson_spicc_device *spicc)
 {
        u32 conf;
@@ -421,7 +424,7 @@ static int meson_spicc_prepare_message(struct spi_master *master,
 {
        struct meson_spicc_device *spicc = spi_master_get_devdata(master);
        struct spi_device *spi = message->spi;
-       u32 conf = 0;
+       u32 conf = readl_relaxed(spicc->base + SPICC_CONREG) & SPICC_DATARATE_MASK;
 
        /* Store current message */
        spicc->message = message;
@@ -458,8 +461,6 @@ static int meson_spicc_prepare_message(struct spi_master *master,
        /* Select CS */
        conf |= FIELD_PREP(SPICC_CS_MASK, spi->chip_select);
 
-       /* Default Clock rate core/4 */
-
        /* Default 8bit word */
        conf |= FIELD_PREP(SPICC_BITLENGTH_MASK, 8 - 1);
 
@@ -476,12 +477,16 @@ static int meson_spicc_prepare_message(struct spi_master *master,
 static int meson_spicc_unprepare_transfer(struct spi_master *master)
 {
        struct meson_spicc_device *spicc = spi_master_get_devdata(master);
+       u32 conf = readl_relaxed(spicc->base + SPICC_CONREG) & SPICC_DATARATE_MASK;
 
        /* Disable all IRQs */
        writel(0, spicc->base + SPICC_INTREG);
 
        device_reset_optional(&spicc->pdev->dev);
 
+       /* Set default configuration, keeping datarate field */
+       writel_relaxed(conf, spicc->base + SPICC_CONREG);
+
        return 0;
 }
 
@@ -518,14 +523,60 @@ static void meson_spicc_cleanup(struct spi_device *spi)
  * Clk path for G12A series:
  *    pclk -> pow2 fixed div -> pow2 div -> mux -> out
  *    pclk -> enh fixed div -> enh div -> mux -> out
+ *
+ * The pow2 divider is tied to the controller HW state, and the
+ * divider is only valid when the controller is initialized.
+ *
+ * A set of clock ops is added to make sure we don't read/set this
+ * clock rate while the controller is in an unknown state.
  */
 
-static int meson_spicc_clk_init(struct meson_spicc_device *spicc)
+static unsigned long meson_spicc_pow2_recalc_rate(struct clk_hw *hw,
+                                                 unsigned long parent_rate)
+{
+       struct clk_divider *divider = to_clk_divider(hw);
+       struct meson_spicc_device *spicc = pow2_clk_to_spicc(divider);
+
+       if (!spicc->master->cur_msg || !spicc->master->busy)
+               return 0;
+
+       return clk_divider_ops.recalc_rate(hw, parent_rate);
+}
+
+static int meson_spicc_pow2_determine_rate(struct clk_hw *hw,
+                                          struct clk_rate_request *req)
+{
+       struct clk_divider *divider = to_clk_divider(hw);
+       struct meson_spicc_device *spicc = pow2_clk_to_spicc(divider);
+
+       if (!spicc->master->cur_msg || !spicc->master->busy)
+               return -EINVAL;
+
+       return clk_divider_ops.determine_rate(hw, req);
+}
+
+static int meson_spicc_pow2_set_rate(struct clk_hw *hw, unsigned long rate,
+                                    unsigned long parent_rate)
+{
+       struct clk_divider *divider = to_clk_divider(hw);
+       struct meson_spicc_device *spicc = pow2_clk_to_spicc(divider);
+
+       if (!spicc->master->cur_msg || !spicc->master->busy)
+               return -EINVAL;
+
+       return clk_divider_ops.set_rate(hw, rate, parent_rate);
+}
+
+const struct clk_ops meson_spicc_pow2_clk_ops = {
+       .recalc_rate = meson_spicc_pow2_recalc_rate,
+       .determine_rate = meson_spicc_pow2_determine_rate,
+       .set_rate = meson_spicc_pow2_set_rate,
+};
+
+static int meson_spicc_pow2_clk_init(struct meson_spicc_device *spicc)
 {
        struct device *dev = &spicc->pdev->dev;
-       struct clk_fixed_factor *pow2_fixed_div, *enh_fixed_div;
-       struct clk_divider *pow2_div, *enh_div;
-       struct clk_mux *mux;
+       struct clk_fixed_factor *pow2_fixed_div;
        struct clk_init_data init;
        struct clk *clk;
        struct clk_parent_data parent_data[2];
@@ -560,31 +611,45 @@ static int meson_spicc_clk_init(struct meson_spicc_device *spicc)
        if (WARN_ON(IS_ERR(clk)))
                return PTR_ERR(clk);
 
-       pow2_div = devm_kzalloc(dev, sizeof(*pow2_div), GFP_KERNEL);
-       if (!pow2_div)
-               return -ENOMEM;
-
        snprintf(name, sizeof(name), "%s#pow2_div", dev_name(dev));
        init.name = name;
-       init.ops = &clk_divider_ops;
-       init.flags = CLK_SET_RATE_PARENT;
+       init.ops = &meson_spicc_pow2_clk_ops;
+       /*
+        * Set NOCACHE here to make sure we read the actual HW value
+        * since we reset the HW after each transfer.
+        */
+       init.flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE;
        parent_data[0].hw = &pow2_fixed_div->hw;
        init.num_parents = 1;
 
-       pow2_div->shift = 16,
-       pow2_div->width = 3,
-       pow2_div->flags = CLK_DIVIDER_POWER_OF_TWO,
-       pow2_div->reg = spicc->base + SPICC_CONREG;
-       pow2_div->hw.init = &init;
+       spicc->pow2_div.shift = 16,
+       spicc->pow2_div.width = 3,
+       spicc->pow2_div.flags = CLK_DIVIDER_POWER_OF_TWO,
+       spicc->pow2_div.reg = spicc->base + SPICC_CONREG;
+       spicc->pow2_div.hw.init = &init;
 
-       clk = devm_clk_register(dev, &pow2_div->hw);
-       if (WARN_ON(IS_ERR(clk)))
-               return PTR_ERR(clk);
+       spicc->clk = devm_clk_register(dev, &spicc->pow2_div.hw);
+       if (WARN_ON(IS_ERR(spicc->clk)))
+               return PTR_ERR(spicc->clk);
 
-       if (!spicc->data->has_enhance_clk_div) {
-               spicc->clk = clk;
-               return 0;
-       }
+       return 0;
+}
+
+static int meson_spicc_enh_clk_init(struct meson_spicc_device *spicc)
+{
+       struct device *dev = &spicc->pdev->dev;
+       struct clk_fixed_factor *enh_fixed_div;
+       struct clk_divider *enh_div;
+       struct clk_mux *mux;
+       struct clk_init_data init;
+       struct clk *clk;
+       struct clk_parent_data parent_data[2];
+       char name[64];
+
+       memset(&init, 0, sizeof(init));
+       memset(&parent_data, 0, sizeof(parent_data));
+
+       init.parent_data = parent_data;
 
        /* algorithm for enh div: rate = freq / 2 / (N + 1) */
 
@@ -637,7 +702,7 @@ static int meson_spicc_clk_init(struct meson_spicc_device *spicc)
        snprintf(name, sizeof(name), "%s#sel", dev_name(dev));
        init.name = name;
        init.ops = &clk_mux_ops;
-       parent_data[0].hw = &pow2_div->hw;
+       parent_data[0].hw = &spicc->pow2_div.hw;
        parent_data[1].hw = &enh_div->hw;
        init.num_parents = 2;
        init.flags = CLK_SET_RATE_PARENT;
@@ -754,12 +819,20 @@ static int meson_spicc_probe(struct platform_device *pdev)
 
        meson_spicc_oen_enable(spicc);
 
-       ret = meson_spicc_clk_init(spicc);
+       ret = meson_spicc_pow2_clk_init(spicc);
        if (ret) {
-               dev_err(&pdev->dev, "clock registration failed\n");
+               dev_err(&pdev->dev, "pow2 clock registration failed\n");
                goto out_clk;
        }
 
+       if (spicc->data->has_enhance_clk_div) {
+               ret = meson_spicc_enh_clk_init(spicc);
+               if (ret) {
+                       dev_err(&pdev->dev, "clock registration failed\n");
+                       goto out_clk;
+               }
+       }
+
        ret = devm_spi_register_master(&pdev->dev, master);
        if (ret) {
                dev_err(&pdev->dev, "spi master registration failed\n");
index f5d32ec..0709e98 100644 (file)
@@ -161,6 +161,7 @@ static int spi_mux_probe(struct spi_device *spi)
        ctlr->num_chipselect = mux_control_states(priv->mux);
        ctlr->bus_num = -1;
        ctlr->dev.of_node = spi->dev.of_node;
+       ctlr->must_async = true;
 
        ret = devm_spi_register_controller(&spi->dev, ctlr);
        if (ret)
index 8f97a3e..32c01e6 100644 (file)
@@ -95,7 +95,7 @@ static ssize_t driver_override_show(struct device *dev,
 }
 static DEVICE_ATTR_RW(driver_override);
 
-static struct spi_statistics *spi_alloc_pcpu_stats(struct device *dev)
+static struct spi_statistics __percpu *spi_alloc_pcpu_stats(struct device *dev)
 {
        struct spi_statistics __percpu *pcpu_stats;
 
@@ -162,7 +162,7 @@ static struct device_attribute dev_attr_spi_device_##field = {              \
 }
 
 #define SPI_STATISTICS_SHOW_NAME(name, file, field)                    \
-static ssize_t spi_statistics_##name##_show(struct spi_statistics *stat, \
+static ssize_t spi_statistics_##name##_show(struct spi_statistics __percpu *stat, \
                                            char *buf)                  \
 {                                                                      \
        ssize_t len;                                                    \
@@ -309,7 +309,7 @@ static const struct attribute_group *spi_master_groups[] = {
        NULL,
 };
 
-static void spi_statistics_add_transfer_stats(struct spi_statistics *pcpu_stats,
+static void spi_statistics_add_transfer_stats(struct spi_statistics __percpu *pcpu_stats,
                                              struct spi_transfer *xfer,
                                              struct spi_controller *ctlr)
 {
@@ -1275,8 +1275,8 @@ static int spi_transfer_wait(struct spi_controller *ctlr,
                             struct spi_message *msg,
                             struct spi_transfer *xfer)
 {
-       struct spi_statistics *statm = ctlr->pcpu_statistics;
-       struct spi_statistics *stats = msg->spi->pcpu_statistics;
+       struct spi_statistics __percpu *statm = ctlr->pcpu_statistics;
+       struct spi_statistics __percpu *stats = msg->spi->pcpu_statistics;
        u32 speed_hz = xfer->speed_hz;
        unsigned long long ms;
 
@@ -1432,8 +1432,8 @@ static int spi_transfer_one_message(struct spi_controller *ctlr,
        struct spi_transfer *xfer;
        bool keep_cs = false;
        int ret = 0;
-       struct spi_statistics *statm = ctlr->pcpu_statistics;
-       struct spi_statistics *stats = msg->spi->pcpu_statistics;
+       struct spi_statistics __percpu *statm = ctlr->pcpu_statistics;
+       struct spi_statistics __percpu *stats = msg->spi->pcpu_statistics;
 
        spi_set_cs(msg->spi, true, false);
 
@@ -1727,8 +1727,7 @@ static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread)
        spin_unlock_irqrestore(&ctlr->queue_lock, flags);
 
        ret = __spi_pump_transfer_message(ctlr, msg, was_busy);
-       if (!ret)
-               kthread_queue_work(ctlr->kworker, &ctlr->pump_messages);
+       kthread_queue_work(ctlr->kworker, &ctlr->pump_messages);
 
        ctlr->cur_msg = NULL;
        ctlr->fallback = false;
@@ -4033,7 +4032,7 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message)
         * guard against reentrancy from a different context. The io_mutex
         * will catch those cases.
         */
-       if (READ_ONCE(ctlr->queue_empty)) {
+       if (READ_ONCE(ctlr->queue_empty) && !ctlr->must_async) {
                message->actual_length = 0;
                message->status = -EINPROGRESS;
 
index cac9553..aa100b5 100644 (file)
@@ -18,6 +18,7 @@ MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Realtek Wireless Lan Driver");
 MODULE_AUTHOR("Realtek Semiconductor Corp.");
 MODULE_VERSION(DRIVERVERSION);
+MODULE_FIRMWARE("rtlwifi/rtl8188eufw.bin");
 
 #define CONFIG_BR_EXT_BRNAME "br0"
 #define RTW_NOTCH_FILTER 0 /* 0:Disable, 1:Enable, */
index cc2b44f..9147d17 100644 (file)
@@ -28,6 +28,7 @@ static struct usb_device_id rtw_usb_id_tbl[] = {
        /*=== Realtek demoboard ===*/
        {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8179)}, /* 8188EUS */
        {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x0179)}, /* 8188ETV */
+       {USB_DEVICE(USB_VENDER_ID_REALTEK, 0xffef)}, /* Rosewill USB-N150 Nano */
        /*=== Customer ID ===*/
        /****** 8188EUS ********/
        {USB_DEVICE(0x07B8, 0x8179)}, /* Abocom - Abocom */
index 2326aae..bb7db96 100644 (file)
@@ -117,34 +117,6 @@ static void r871x_internal_cmd_hdl(struct _adapter *padapter, u8 *pbuf)
        kfree(pdrvcmd->pbuf);
 }
 
-static u8 read_macreg_hdl(struct _adapter *padapter, u8 *pbuf)
-{
-       void (*pcmd_callback)(struct _adapter *dev, struct cmd_obj      *pcmd);
-       struct cmd_obj *pcmd  = (struct cmd_obj *)pbuf;
-
-       /*  invoke cmd->callback function */
-       pcmd_callback = cmd_callback[pcmd->cmdcode].callback;
-       if (!pcmd_callback)
-               r8712_free_cmd_obj(pcmd);
-       else
-               pcmd_callback(padapter, pcmd);
-       return H2C_SUCCESS;
-}
-
-static u8 write_macreg_hdl(struct _adapter *padapter, u8 *pbuf)
-{
-       void (*pcmd_callback)(struct _adapter *dev, struct cmd_obj      *pcmd);
-       struct cmd_obj *pcmd  = (struct cmd_obj *)pbuf;
-
-       /*  invoke cmd->callback function */
-       pcmd_callback = cmd_callback[pcmd->cmdcode].callback;
-       if (!pcmd_callback)
-               r8712_free_cmd_obj(pcmd);
-       else
-               pcmd_callback(padapter, pcmd);
-       return H2C_SUCCESS;
-}
-
 static u8 read_bbreg_hdl(struct _adapter *padapter, u8 *pbuf)
 {
        struct cmd_obj *pcmd  = (struct cmd_obj *)pbuf;
@@ -213,14 +185,6 @@ static struct cmd_obj *cmd_hdl_filter(struct _adapter *padapter,
        pcmd_r = NULL;
 
        switch (pcmd->cmdcode) {
-       case GEN_CMD_CODE(_Read_MACREG):
-               read_macreg_hdl(padapter, (u8 *)pcmd);
-               pcmd_r = pcmd;
-               break;
-       case GEN_CMD_CODE(_Write_MACREG):
-               write_macreg_hdl(padapter, (u8 *)pcmd);
-               pcmd_r = pcmd;
-               break;
        case GEN_CMD_CODE(_Read_BBREG):
                read_bbreg_hdl(padapter, (u8 *)pcmd);
                break;
index f2b1bce..27295bd 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/tee_drv.h>
+#include <linux/uaccess.h>
 #include <linux/uio.h>
 #include "tee_private.h"
 
@@ -326,6 +327,9 @@ struct tee_shm *tee_shm_register_user_buf(struct tee_context *ctx,
        void *ret;
        int id;
 
+       if (!access_ok((void __user *)addr, length))
+               return ERR_PTR(-EFAULT);
+
        mutex_lock(&teedev->mutex);
        id = idr_alloc(&teedev->idr, NULL, 1, 0, GFP_KERNEL);
        mutex_unlock(&teedev->mutex);
index 80d4e06..365489b 100644 (file)
@@ -527,7 +527,7 @@ static void int3400_setup_gddv(struct int3400_thermal_priv *priv)
        priv->data_vault = kmemdup(obj->package.elements[0].buffer.pointer,
                                   obj->package.elements[0].buffer.length,
                                   GFP_KERNEL);
-       if (!priv->data_vault)
+       if (ZERO_OR_NULL_PTR(priv->data_vault))
                goto out_free;
 
        bin_attr_data_vault.private = priv->data_vault;
@@ -597,7 +597,7 @@ static int int3400_thermal_probe(struct platform_device *pdev)
                        goto free_imok;
        }
 
-       if (priv->data_vault) {
+       if (!ZERO_OR_NULL_PTR(priv->data_vault)) {
                result = sysfs_create_group(&pdev->dev.kobj,
                                            &data_attribute_group);
                if (result)
@@ -615,7 +615,8 @@ static int int3400_thermal_probe(struct platform_device *pdev)
 free_sysfs:
        cleanup_odvp(priv);
        if (priv->data_vault) {
-               sysfs_remove_group(&pdev->dev.kobj, &data_attribute_group);
+               if (!ZERO_OR_NULL_PTR(priv->data_vault))
+                       sysfs_remove_group(&pdev->dev.kobj, &data_attribute_group);
                kfree(priv->data_vault);
        }
 free_uuid:
@@ -647,7 +648,7 @@ static int int3400_thermal_remove(struct platform_device *pdev)
        if (!priv->rel_misc_dev_res)
                acpi_thermal_rel_misc_device_remove(priv->adev->handle);
 
-       if (priv->data_vault)
+       if (!ZERO_OR_NULL_PTR(priv->data_vault))
                sysfs_remove_group(&pdev->dev.kobj, &data_attribute_group);
        sysfs_remove_group(&pdev->dev.kobj, &uuid_attribute_group);
        sysfs_remove_group(&pdev->dev.kobj, &imok_attribute_group);
index 6a5d0ae..50d50ce 100644 (file)
@@ -1329,6 +1329,7 @@ free_tz:
        kfree(tz);
        return ERR_PTR(result);
 }
+EXPORT_SYMBOL_GPL(thermal_zone_device_register_with_trips);
 
 struct thermal_zone_device *thermal_zone_device_register(const char *type, int ntrips, int mask,
                                                         void *devdata, struct thermal_zone_device_ops *ops,
index e76a6c1..f12d0a3 100644 (file)
@@ -29,8 +29,7 @@ config USB4_DEBUGFS_WRITE
 
 config USB4_KUNIT_TEST
        bool "KUnit tests" if !KUNIT_ALL_TESTS
-       depends on (USB4=m || KUNIT=y)
-       depends on KUNIT
+       depends on USB4 && KUNIT=y
        default KUNIT_ALL_TESTS
 
 config USB4_DMA_TEST
index e5ede5d..0c661a7 100644 (file)
@@ -407,7 +407,7 @@ static void tb_ctl_rx_submit(struct ctl_pkg *pkg)
 
 static int tb_async_error(const struct ctl_pkg *pkg)
 {
-       const struct cfg_error_pkg *error = (const struct cfg_error_pkg *)pkg;
+       const struct cfg_error_pkg *error = pkg->buffer;
 
        if (pkg->frame.eof != TB_CFG_PKG_ERROR)
                return false;
index 244f8cd..c63c1f4 100644 (file)
@@ -3786,14 +3786,18 @@ int tb_switch_pcie_l1_enable(struct tb_switch *sw)
  */
 int tb_switch_xhci_connect(struct tb_switch *sw)
 {
-       bool usb_port1, usb_port3, xhci_port1, xhci_port3;
        struct tb_port *port1, *port3;
        int ret;
 
+       if (sw->generation != 3)
+               return 0;
+
        port1 = &sw->ports[1];
        port3 = &sw->ports[3];
 
        if (tb_switch_is_alpine_ridge(sw)) {
+               bool usb_port1, usb_port3, xhci_port1, xhci_port3;
+
                usb_port1 = tb_lc_is_usb_plugged(port1);
                usb_port3 = tb_lc_is_usb_plugged(port3);
                xhci_port1 = tb_lc_is_xhci_connected(port1);
index caa5c14..01c112e 100644 (file)
@@ -248,7 +248,7 @@ struct gsm_mux {
        bool constipated;               /* Asked by remote to shut up */
        bool has_devices;               /* Devices were registered */
 
-       spinlock_t tx_lock;
+       struct mutex tx_mutex;
        unsigned int tx_bytes;          /* TX data outstanding */
 #define TX_THRESH_HI           8192
 #define TX_THRESH_LO           2048
@@ -256,7 +256,7 @@ struct gsm_mux {
        struct list_head tx_data_list;  /* Pending data packets */
 
        /* Control messages */
-       struct timer_list kick_timer;   /* Kick TX queuing on timeout */
+       struct delayed_work kick_timeout;       /* Kick TX queuing on timeout */
        struct timer_list t2_timer;     /* Retransmit timer for commands */
        int cretries;                   /* Command retry counter */
        struct gsm_control *pending_cmd;/* Our current pending command */
@@ -680,7 +680,6 @@ static int gsm_send(struct gsm_mux *gsm, int addr, int cr, int control)
        struct gsm_msg *msg;
        u8 *dp;
        int ocr;
-       unsigned long flags;
 
        msg = gsm_data_alloc(gsm, addr, 0, control);
        if (!msg)
@@ -702,10 +701,10 @@ static int gsm_send(struct gsm_mux *gsm, int addr, int cr, int control)
 
        gsm_print_packet("Q->", addr, cr, control, NULL, 0);
 
-       spin_lock_irqsave(&gsm->tx_lock, flags);
+       mutex_lock(&gsm->tx_mutex);
        list_add_tail(&msg->list, &gsm->tx_ctrl_list);
        gsm->tx_bytes += msg->len;
-       spin_unlock_irqrestore(&gsm->tx_lock, flags);
+       mutex_unlock(&gsm->tx_mutex);
        gsmld_write_trigger(gsm);
 
        return 0;
@@ -730,7 +729,7 @@ static void gsm_dlci_clear_queues(struct gsm_mux *gsm, struct gsm_dlci *dlci)
        spin_unlock_irqrestore(&dlci->lock, flags);
 
        /* Clear data packets in MUX write queue */
-       spin_lock_irqsave(&gsm->tx_lock, flags);
+       mutex_lock(&gsm->tx_mutex);
        list_for_each_entry_safe(msg, nmsg, &gsm->tx_data_list, list) {
                if (msg->addr != addr)
                        continue;
@@ -738,7 +737,7 @@ static void gsm_dlci_clear_queues(struct gsm_mux *gsm, struct gsm_dlci *dlci)
                list_del(&msg->list);
                kfree(msg);
        }
-       spin_unlock_irqrestore(&gsm->tx_lock, flags);
+       mutex_unlock(&gsm->tx_mutex);
 }
 
 /**
@@ -1009,7 +1008,7 @@ static void __gsm_data_queue(struct gsm_dlci *dlci, struct gsm_msg *msg)
        gsm->tx_bytes += msg->len;
 
        gsmld_write_trigger(gsm);
-       mod_timer(&gsm->kick_timer, jiffies + 10 * gsm->t1 * HZ / 100);
+       schedule_delayed_work(&gsm->kick_timeout, 10 * gsm->t1 * HZ / 100);
 }
 
 /**
@@ -1024,10 +1023,9 @@ static void __gsm_data_queue(struct gsm_dlci *dlci, struct gsm_msg *msg)
 
 static void gsm_data_queue(struct gsm_dlci *dlci, struct gsm_msg *msg)
 {
-       unsigned long flags;
-       spin_lock_irqsave(&dlci->gsm->tx_lock, flags);
+       mutex_lock(&dlci->gsm->tx_mutex);
        __gsm_data_queue(dlci, msg);
-       spin_unlock_irqrestore(&dlci->gsm->tx_lock, flags);
+       mutex_unlock(&dlci->gsm->tx_mutex);
 }
 
 /**
@@ -1039,7 +1037,7 @@ static void gsm_data_queue(struct gsm_dlci *dlci, struct gsm_msg *msg)
  *     is data. Keep to the MRU of the mux. This path handles the usual tty
  *     interface which is a byte stream with optional modem data.
  *
- *     Caller must hold the tx_lock of the mux.
+ *     Caller must hold the tx_mutex of the mux.
  */
 
 static int gsm_dlci_data_output(struct gsm_mux *gsm, struct gsm_dlci *dlci)
@@ -1099,7 +1097,7 @@ static int gsm_dlci_data_output(struct gsm_mux *gsm, struct gsm_dlci *dlci)
  *     is data. Keep to the MRU of the mux. This path handles framed data
  *     queued as skbuffs to the DLCI.
  *
- *     Caller must hold the tx_lock of the mux.
+ *     Caller must hold the tx_mutex of the mux.
  */
 
 static int gsm_dlci_data_output_framed(struct gsm_mux *gsm,
@@ -1115,7 +1113,7 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm,
        if (dlci->adaption == 4)
                overhead = 1;
 
-       /* dlci->skb is locked by tx_lock */
+       /* dlci->skb is locked by tx_mutex */
        if (dlci->skb == NULL) {
                dlci->skb = skb_dequeue_tail(&dlci->skb_list);
                if (dlci->skb == NULL)
@@ -1169,7 +1167,7 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm,
  *     Push an empty frame in to the transmit queue to update the modem status
  *     bits and to transmit an optional break.
  *
- *     Caller must hold the tx_lock of the mux.
+ *     Caller must hold the tx_mutex of the mux.
  */
 
 static int gsm_dlci_modem_output(struct gsm_mux *gsm, struct gsm_dlci *dlci,
@@ -1283,13 +1281,12 @@ static int gsm_dlci_data_sweep(struct gsm_mux *gsm)
 
 static void gsm_dlci_data_kick(struct gsm_dlci *dlci)
 {
-       unsigned long flags;
        int sweep;
 
        if (dlci->constipated)
                return;
 
-       spin_lock_irqsave(&dlci->gsm->tx_lock, flags);
+       mutex_lock(&dlci->gsm->tx_mutex);
        /* If we have nothing running then we need to fire up */
        sweep = (dlci->gsm->tx_bytes < TX_THRESH_LO);
        if (dlci->gsm->tx_bytes == 0) {
@@ -1300,7 +1297,7 @@ static void gsm_dlci_data_kick(struct gsm_dlci *dlci)
        }
        if (sweep)
                gsm_dlci_data_sweep(dlci->gsm);
-       spin_unlock_irqrestore(&dlci->gsm->tx_lock, flags);
+       mutex_unlock(&dlci->gsm->tx_mutex);
 }
 
 /*
@@ -1984,24 +1981,23 @@ static void gsm_dlci_command(struct gsm_dlci *dlci, const u8 *data, int len)
 }
 
 /**
- *     gsm_kick_timer  -       transmit if possible
- *     @t: timer contained in our gsm object
+ *     gsm_kick_timeout        -       transmit if possible
+ *     @work: work contained in our gsm object
  *
  *     Transmit data from DLCIs if the queue is empty. We can't rely on
  *     a tty wakeup except when we filled the pipe so we need to fire off
  *     new data ourselves in other cases.
  */
-static void gsm_kick_timer(struct timer_list *t)
+static void gsm_kick_timeout(struct work_struct *work)
 {
-       struct gsm_mux *gsm = from_timer(gsm, t, kick_timer);
-       unsigned long flags;
+       struct gsm_mux *gsm = container_of(work, struct gsm_mux, kick_timeout.work);
        int sent = 0;
 
-       spin_lock_irqsave(&gsm->tx_lock, flags);
+       mutex_lock(&gsm->tx_mutex);
        /* If we have nothing running then we need to fire up */
        if (gsm->tx_bytes < TX_THRESH_LO)
                sent = gsm_dlci_data_sweep(gsm);
-       spin_unlock_irqrestore(&gsm->tx_lock, flags);
+       mutex_unlock(&gsm->tx_mutex);
 
        if (sent && debug & 4)
                pr_info("%s TX queue stalled\n", __func__);
@@ -2458,7 +2454,7 @@ static void gsm_cleanup_mux(struct gsm_mux *gsm, bool disc)
        }
 
        /* Finish outstanding timers, making sure they are done */
-       del_timer_sync(&gsm->kick_timer);
+       cancel_delayed_work_sync(&gsm->kick_timeout);
        del_timer_sync(&gsm->t2_timer);
 
        /* Finish writing to ldisc */
@@ -2501,13 +2497,6 @@ static int gsm_activate_mux(struct gsm_mux *gsm)
        if (dlci == NULL)
                return -ENOMEM;
 
-       timer_setup(&gsm->kick_timer, gsm_kick_timer, 0);
-       timer_setup(&gsm->t2_timer, gsm_control_retransmit, 0);
-       INIT_WORK(&gsm->tx_work, gsmld_write_task);
-       init_waitqueue_head(&gsm->event);
-       spin_lock_init(&gsm->control_lock);
-       spin_lock_init(&gsm->tx_lock);
-
        if (gsm->encoding == 0)
                gsm->receive = gsm0_receive;
        else
@@ -2538,6 +2527,7 @@ static void gsm_free_mux(struct gsm_mux *gsm)
                        break;
                }
        }
+       mutex_destroy(&gsm->tx_mutex);
        mutex_destroy(&gsm->mutex);
        kfree(gsm->txframe);
        kfree(gsm->buf);
@@ -2609,9 +2599,15 @@ static struct gsm_mux *gsm_alloc_mux(void)
        }
        spin_lock_init(&gsm->lock);
        mutex_init(&gsm->mutex);
+       mutex_init(&gsm->tx_mutex);
        kref_init(&gsm->ref);
        INIT_LIST_HEAD(&gsm->tx_ctrl_list);
        INIT_LIST_HEAD(&gsm->tx_data_list);
+       INIT_DELAYED_WORK(&gsm->kick_timeout, gsm_kick_timeout);
+       timer_setup(&gsm->t2_timer, gsm_control_retransmit, 0);
+       INIT_WORK(&gsm->tx_work, gsmld_write_task);
+       init_waitqueue_head(&gsm->event);
+       spin_lock_init(&gsm->control_lock);
 
        gsm->t1 = T1;
        gsm->t2 = T2;
@@ -2636,6 +2632,7 @@ static struct gsm_mux *gsm_alloc_mux(void)
        }
        spin_unlock(&gsm_mux_lock);
        if (i == MAX_MUX) {
+               mutex_destroy(&gsm->tx_mutex);
                mutex_destroy(&gsm->mutex);
                kfree(gsm->txframe);
                kfree(gsm->buf);
@@ -2791,17 +2788,16 @@ static void gsmld_write_trigger(struct gsm_mux *gsm)
 static void gsmld_write_task(struct work_struct *work)
 {
        struct gsm_mux *gsm = container_of(work, struct gsm_mux, tx_work);
-       unsigned long flags;
        int i, ret;
 
        /* All outstanding control channel and control messages and one data
         * frame is sent.
         */
        ret = -ENODEV;
-       spin_lock_irqsave(&gsm->tx_lock, flags);
+       mutex_lock(&gsm->tx_mutex);
        if (gsm->tty)
                ret = gsm_data_kick(gsm);
-       spin_unlock_irqrestore(&gsm->tx_lock, flags);
+       mutex_unlock(&gsm->tx_mutex);
 
        if (ret >= 0)
                for (i = 0; i < NUM_DLCI; i++)
@@ -2858,7 +2854,8 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
                        flags = *fp++;
                switch (flags) {
                case TTY_NORMAL:
-                       gsm->receive(gsm, *cp);
+                       if (gsm->receive)
+                               gsm->receive(gsm, *cp);
                        break;
                case TTY_OVERRUN:
                case TTY_BREAK:
@@ -2946,10 +2943,6 @@ static int gsmld_open(struct tty_struct *tty)
 
        gsmld_attach_gsm(tty, gsm);
 
-       timer_setup(&gsm->kick_timer, gsm_kick_timer, 0);
-       timer_setup(&gsm->t2_timer, gsm_control_retransmit, 0);
-       INIT_WORK(&gsm->tx_work, gsmld_write_task);
-
        return 0;
 }
 
@@ -3012,7 +3005,6 @@ static ssize_t gsmld_write(struct tty_struct *tty, struct file *file,
                           const unsigned char *buf, size_t nr)
 {
        struct gsm_mux *gsm = tty->disc_data;
-       unsigned long flags;
        int space;
        int ret;
 
@@ -3020,13 +3012,13 @@ static ssize_t gsmld_write(struct tty_struct *tty, struct file *file,
                return -ENODEV;
 
        ret = -ENOBUFS;
-       spin_lock_irqsave(&gsm->tx_lock, flags);
+       mutex_lock(&gsm->tx_mutex);
        space = tty_write_room(tty);
        if (space >= nr)
                ret = tty->ops->write(tty, buf, nr);
        else
                set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
-       spin_unlock_irqrestore(&gsm->tx_lock, flags);
+       mutex_unlock(&gsm->tx_mutex);
 
        return ret;
 }
@@ -3323,14 +3315,13 @@ static struct tty_ldisc_ops tty_ldisc_packet = {
 static void gsm_modem_upd_via_data(struct gsm_dlci *dlci, u8 brk)
 {
        struct gsm_mux *gsm = dlci->gsm;
-       unsigned long flags;
 
        if (dlci->state != DLCI_OPEN || dlci->adaption != 2)
                return;
 
-       spin_lock_irqsave(&gsm->tx_lock, flags);
+       mutex_lock(&gsm->tx_mutex);
        gsm_dlci_modem_output(gsm, dlci, brk);
-       spin_unlock_irqrestore(&gsm->tx_lock, flags);
+       mutex_unlock(&gsm->tx_mutex);
 }
 
 /**
index 30ba9ee..7450d38 100644 (file)
@@ -294,9 +294,6 @@ static int atmel_config_rs485(struct uart_port *port, struct ktermios *termios,
 
        mode = atmel_uart_readl(port, ATMEL_US_MR);
 
-       /* Resetting serial mode to RS232 (0x0) */
-       mode &= ~ATMEL_US_USMODE;
-
        if (rs485conf->flags & SER_RS485_ENABLED) {
                dev_dbg(port->dev, "Setting UART to RS485\n");
                if (rs485conf->flags & SER_RS485_RX_DURING_TX)
@@ -306,6 +303,7 @@ static int atmel_config_rs485(struct uart_port *port, struct ktermios *termios,
 
                atmel_uart_writel(port, ATMEL_US_TTGR,
                                  rs485conf->delay_rts_after_send);
+               mode &= ~ATMEL_US_USMODE;
                mode |= ATMEL_US_USMODE_RS485;
        } else {
                dev_dbg(port->dev, "Setting UART to RS232\n");
index f6c33cd..b20f6f2 100644 (file)
@@ -1394,9 +1394,9 @@ static int lpuart_config_rs485(struct uart_port *port, struct ktermios *termios,
                 * Note: UART is assumed to be active high.
                 */
                if (rs485->flags & SER_RS485_RTS_ON_SEND)
-                       modem &= ~UARTMODEM_TXRTSPOL;
-               else if (rs485->flags & SER_RS485_RTS_AFTER_SEND)
                        modem |= UARTMODEM_TXRTSPOL;
+               else if (rs485->flags & SER_RS485_RTS_AFTER_SEND)
+                       modem &= ~UARTMODEM_TXRTSPOL;
        }
 
        writeb(modem, sport->port.membase + UARTMODEM);
@@ -2191,6 +2191,7 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
        uart_update_timeout(port, termios->c_cflag, baud);
 
        /* wait transmit engin complete */
+       lpuart32_write(&sport->port, 0, UARTMODIR);
        lpuart32_wait_bit_set(&sport->port, UARTSTAT, UARTSTAT_TC);
 
        /* disable transmit and receive */
index 9fdecc7..5e287de 100644 (file)
@@ -470,7 +470,6 @@ static void lookahead_bufs(struct tty_port *port, struct tty_buffer *head)
 
        while (head) {
                struct tty_buffer *next;
-               unsigned char *p, *f = NULL;
                unsigned int count;
 
                /*
@@ -489,11 +488,16 @@ static void lookahead_bufs(struct tty_port *port, struct tty_buffer *head)
                        continue;
                }
 
-               p = char_buf_ptr(head, head->lookahead);
-               if (~head->flags & TTYB_NORMAL)
-                       f = flag_buf_ptr(head, head->lookahead);
+               if (port->client_ops->lookahead_buf) {
+                       unsigned char *p, *f = NULL;
+
+                       p = char_buf_ptr(head, head->lookahead);
+                       if (~head->flags & TTYB_NORMAL)
+                               f = flag_buf_ptr(head, head->lookahead);
+
+                       port->client_ops->lookahead_buf(port, p, f, count);
+               }
 
-               port->client_ops->lookahead_buf(port, p, f, count);
                head->lookahead += count;
        }
 }
index ae9c926..0b669c8 100644 (file)
@@ -4662,9 +4662,11 @@ static int con_font_set(struct vc_data *vc, struct console_font_op *op)
        console_lock();
        if (vc->vc_mode != KD_TEXT)
                rc = -EINVAL;
-       else if (vc->vc_sw->con_font_set)
+       else if (vc->vc_sw->con_font_set) {
+               if (vc_is_sel(vc))
+                       clear_selection();
                rc = vc->vc_sw->con_font_set(vc, &font, op->flags);
-       else
+       else
                rc = -ENOSYS;
        console_unlock();
        kfree(font.data);
@@ -4691,9 +4693,11 @@ static int con_font_default(struct vc_data *vc, struct console_font_op *op)
                console_unlock();
                return -EINVAL;
        }
-       if (vc->vc_sw->con_font_default)
+       if (vc->vc_sw->con_font_default) {
+               if (vc_is_sel(vc))
+                       clear_selection();
                rc = vc->vc_sw->con_font_default(vc, &font, s);
-       else
+       else
                rc = -ENOSYS;
        console_unlock();
        if (!rc) {
index 6bc679d..a202d7d 100644 (file)
@@ -8741,6 +8741,8 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba,
        struct scsi_device *sdp;
        unsigned long flags;
        int ret, retries;
+       unsigned long deadline;
+       int32_t remaining;
 
        spin_lock_irqsave(hba->host->host_lock, flags);
        sdp = hba->ufs_device_wlun;
@@ -8773,9 +8775,14 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba,
         * callbacks hence set the RQF_PM flag so that it doesn't resume the
         * already suspended childs.
         */
+       deadline = jiffies + 10 * HZ;
        for (retries = 3; retries > 0; --retries) {
+               ret = -ETIMEDOUT;
+               remaining = deadline - jiffies;
+               if (remaining <= 0)
+                       break;
                ret = scsi_execute(sdp, cmd, DMA_NONE, NULL, 0, NULL, &sshdr,
-                               START_STOP_TIMEOUT, 0, 0, RQF_PM, NULL);
+                                  remaining / HZ, 0, 0, RQF_PM, NULL);
                if (!scsi_status_is_check_condition(ret) ||
                                !scsi_sense_valid(&sshdr) ||
                                sshdr.sense_key != UNIT_ATTENTION)
index eced975..c3628a8 100644 (file)
@@ -1711,7 +1711,7 @@ static struct exynos_ufs_uic_attr fsd_uic_attr = {
        .pa_dbg_option_suite            = 0x2E820183,
 };
 
-struct exynos_ufs_drv_data fsd_ufs_drvs = {
+static const struct exynos_ufs_drv_data fsd_ufs_drvs = {
        .uic_attr               = &fsd_uic_attr,
        .quirks                 = UFSHCD_QUIRK_PRDT_BYTE_GRAN |
                                  UFSHCI_QUIRK_BROKEN_REQ_LIST_CLR |
index d21b699..5adcb34 100644 (file)
@@ -1530,7 +1530,8 @@ static void cdns3_transfer_completed(struct cdns3_device *priv_dev,
                                                TRB_LEN(le32_to_cpu(trb->length));
 
                                if (priv_req->num_of_trb > 1 &&
-                                       le32_to_cpu(trb->control) & TRB_SMM)
+                                       le32_to_cpu(trb->control) & TRB_SMM &&
+                                       le32_to_cpu(trb->control) & TRB_CHAIN)
                                        transfer_end = true;
 
                                cdns3_ep_inc_deq(priv_ep);
@@ -1690,6 +1691,7 @@ static int cdns3_check_ep_interrupt_proceed(struct cdns3_endpoint *priv_ep)
                                ep_cfg &= ~EP_CFG_ENABLE;
                                writel(ep_cfg, &priv_dev->regs->ep_cfg);
                                priv_ep->flags &= ~EP_QUIRK_ISO_OUT_EN;
+                               priv_ep->flags |= EP_UPDATE_EP_TRBADDR;
                        }
                        cdns3_transfer_completed(priv_dev, priv_ep);
                } else if (!(priv_ep->flags & EP_STALLED) &&
index 483bcb1..cc637c4 100644 (file)
@@ -1810,6 +1810,9 @@ static const struct usb_device_id acm_ids[] = {
        { USB_DEVICE(0x09d8, 0x0320), /* Elatec GmbH TWN3 */
        .driver_info = NO_UNION_NORMAL, /* has misplaced union descriptor */
        },
+       { USB_DEVICE(0x0c26, 0x0020), /* Icom ICF3400 Serie */
+       .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */
+       },
        { USB_DEVICE(0x0ca6, 0xa050), /* Castles VEGA3000 */
        .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */
        },
index 2633acd..d4b1e70 100644 (file)
@@ -6038,6 +6038,11 @@ re_enumerate:
  * the reset is over (using their post_reset method).
  *
  * Return: The same as for usb_reset_and_verify_device().
+ * However, if a reset is already in progress (for instance, if a
+ * driver doesn't have pre_ or post_reset() callbacks, and while
+ * being unbound or re-bound during the ongoing reset its disconnect()
+ * or probe() routine tries to perform a second, nested reset), the
+ * routine returns -EINPROGRESS.
  *
  * Note:
  * The caller must own the device lock.  For example, it's safe to use
@@ -6071,6 +6076,10 @@ int usb_reset_device(struct usb_device *udev)
                return -EISDIR;
        }
 
+       if (udev->reset_in_progress)
+               return -EINPROGRESS;
+       udev->reset_in_progress = 1;
+
        port_dev = hub->ports[udev->portnum - 1];
 
        /*
@@ -6135,6 +6144,7 @@ int usb_reset_device(struct usb_device *udev)
 
        usb_autosuspend_device(udev);
        memalloc_noio_restore(noio_flag);
+       udev->reset_in_progress = 0;
        return ret;
 }
 EXPORT_SYMBOL_GPL(usb_reset_device);
index c8ba87d..fd0ccf6 100644 (file)
@@ -154,9 +154,9 @@ static int __dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg)
        } else if (hsotg->plat && hsotg->plat->phy_init) {
                ret = hsotg->plat->phy_init(pdev, hsotg->plat->phy_type);
        } else {
-               ret = phy_power_on(hsotg->phy);
+               ret = phy_init(hsotg->phy);
                if (ret == 0)
-                       ret = phy_init(hsotg->phy);
+                       ret = phy_power_on(hsotg->phy);
        }
 
        return ret;
@@ -188,9 +188,9 @@ static int __dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg)
        } else if (hsotg->plat && hsotg->plat->phy_exit) {
                ret = hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type);
        } else {
-               ret = phy_exit(hsotg->phy);
+               ret = phy_power_off(hsotg->phy);
                if (ret == 0)
-                       ret = phy_power_off(hsotg->phy);
+                       ret = phy_exit(hsotg->phy);
        }
        if (ret)
                return ret;
index c5c238a..8c8e326 100644 (file)
@@ -833,15 +833,16 @@ static void dwc3_core_exit(struct dwc3 *dwc)
 {
        dwc3_event_buffers_cleanup(dwc);
 
+       usb_phy_set_suspend(dwc->usb2_phy, 1);
+       usb_phy_set_suspend(dwc->usb3_phy, 1);
+       phy_power_off(dwc->usb2_generic_phy);
+       phy_power_off(dwc->usb3_generic_phy);
+
        usb_phy_shutdown(dwc->usb2_phy);
        usb_phy_shutdown(dwc->usb3_phy);
        phy_exit(dwc->usb2_generic_phy);
        phy_exit(dwc->usb3_generic_phy);
 
-       usb_phy_set_suspend(dwc->usb2_phy, 1);
-       usb_phy_set_suspend(dwc->usb3_phy, 1);
-       phy_power_off(dwc->usb2_generic_phy);
-       phy_power_off(dwc->usb3_generic_phy);
        dwc3_clk_disable(dwc);
        reset_control_assert(dwc->reset);
 }
@@ -1821,7 +1822,6 @@ static int dwc3_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, dwc);
        dwc3_cache_hwparams(dwc);
-       device_init_wakeup(&pdev->dev, of_property_read_bool(dev->of_node, "wakeup-source"));
 
        spin_lock_init(&dwc->lock);
        mutex_init(&dwc->mutex);
@@ -1879,16 +1879,16 @@ err5:
        dwc3_debugfs_exit(dwc);
        dwc3_event_buffers_cleanup(dwc);
 
-       usb_phy_shutdown(dwc->usb2_phy);
-       usb_phy_shutdown(dwc->usb3_phy);
-       phy_exit(dwc->usb2_generic_phy);
-       phy_exit(dwc->usb3_generic_phy);
-
        usb_phy_set_suspend(dwc->usb2_phy, 1);
        usb_phy_set_suspend(dwc->usb3_phy, 1);
        phy_power_off(dwc->usb2_generic_phy);
        phy_power_off(dwc->usb3_generic_phy);
 
+       usb_phy_shutdown(dwc->usb2_phy);
+       usb_phy_shutdown(dwc->usb3_phy);
+       phy_exit(dwc->usb2_generic_phy);
+       phy_exit(dwc->usb3_generic_phy);
+
        dwc3_ulpi_exit(dwc);
 
 err4:
@@ -1983,7 +1983,7 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
                dwc3_core_exit(dwc);
                break;
        case DWC3_GCTL_PRTCAP_HOST:
-               if (!PMSG_IS_AUTO(msg) && !device_can_wakeup(dwc->dev)) {
+               if (!PMSG_IS_AUTO(msg) && !device_may_wakeup(dwc->dev)) {
                        dwc3_core_exit(dwc);
                        break;
                }
@@ -2044,7 +2044,7 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
                spin_unlock_irqrestore(&dwc->lock, flags);
                break;
        case DWC3_GCTL_PRTCAP_HOST:
-               if (!PMSG_IS_AUTO(msg) && !device_can_wakeup(dwc->dev)) {
+               if (!PMSG_IS_AUTO(msg) && !device_may_wakeup(dwc->dev)) {
                        ret = dwc3_core_init_for_resume(dwc);
                        if (ret)
                                return ret;
index 6b01804..4ee4ca0 100644 (file)
@@ -44,6 +44,7 @@
 #define PCI_DEVICE_ID_INTEL_ADLP               0x51ee
 #define PCI_DEVICE_ID_INTEL_ADLM               0x54ee
 #define PCI_DEVICE_ID_INTEL_ADLS               0x7ae1
+#define PCI_DEVICE_ID_INTEL_RPL                        0x460e
 #define PCI_DEVICE_ID_INTEL_RPLS               0x7a61
 #define PCI_DEVICE_ID_INTEL_MTLP               0x7ec1
 #define PCI_DEVICE_ID_INTEL_MTL                        0x7e7e
@@ -456,6 +457,9 @@ static const struct pci_device_id dwc3_pci_id_table[] = {
        { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADLS),
          (kernel_ulong_t) &dwc3_pci_intel_swnode, },
 
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_RPL),
+         (kernel_ulong_t) &dwc3_pci_intel_swnode, },
+
        { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_RPLS),
          (kernel_ulong_t) &dwc3_pci_intel_swnode, },
 
index c5e482f..d3f3937 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <linux/phy/phy.h>
-#include <linux/pm_domain.h>
 #include <linux/usb/of.h>
 #include <linux/reset.h>
 #include <linux/iopoll.h>
@@ -299,11 +298,24 @@ static void dwc3_qcom_interconnect_exit(struct dwc3_qcom *qcom)
        icc_put(qcom->icc_path_apps);
 }
 
+/* Only usable in contexts where the role can not change. */
+static bool dwc3_qcom_is_host(struct dwc3_qcom *qcom)
+{
+       struct dwc3 *dwc = platform_get_drvdata(qcom->dwc3);
+
+       return dwc->xhci;
+}
+
 static enum usb_device_speed dwc3_qcom_read_usb2_speed(struct dwc3_qcom *qcom)
 {
        struct dwc3 *dwc = platform_get_drvdata(qcom->dwc3);
-       struct usb_hcd *hcd = platform_get_drvdata(dwc->xhci);
        struct usb_device *udev;
+       struct usb_hcd __maybe_unused *hcd;
+
+       /*
+        * FIXME: Fix this layering violation.
+        */
+       hcd = platform_get_drvdata(dwc->xhci);
 
        /*
         * It is possible to query the speed of all children of
@@ -311,8 +323,11 @@ static enum usb_device_speed dwc3_qcom_read_usb2_speed(struct dwc3_qcom *qcom)
         * currently supports only 1 port per controller. So
         * this is sufficient.
         */
+#ifdef CONFIG_USB
        udev = usb_hub_find_child(hcd->self.root_hub, 1);
-
+#else
+       udev = NULL;
+#endif
        if (!udev)
                return USB_SPEED_UNKNOWN;
 
@@ -387,7 +402,7 @@ static void dwc3_qcom_enable_interrupts(struct dwc3_qcom *qcom)
        dwc3_qcom_enable_wakeup_irq(qcom->ss_phy_irq, 0);
 }
 
-static int dwc3_qcom_suspend(struct dwc3_qcom *qcom)
+static int dwc3_qcom_suspend(struct dwc3_qcom *qcom, bool wakeup)
 {
        u32 val;
        int i, ret;
@@ -406,7 +421,11 @@ static int dwc3_qcom_suspend(struct dwc3_qcom *qcom)
        if (ret)
                dev_warn(qcom->dev, "failed to disable interconnect: %d\n", ret);
 
-       if (device_may_wakeup(qcom->dev)) {
+       /*
+        * The role is stable during suspend as role switching is done from a
+        * freezable workqueue.
+        */
+       if (dwc3_qcom_is_host(qcom) && wakeup) {
                qcom->usb2_speed = dwc3_qcom_read_usb2_speed(qcom);
                dwc3_qcom_enable_interrupts(qcom);
        }
@@ -416,7 +435,7 @@ static int dwc3_qcom_suspend(struct dwc3_qcom *qcom)
        return 0;
 }
 
-static int dwc3_qcom_resume(struct dwc3_qcom *qcom)
+static int dwc3_qcom_resume(struct dwc3_qcom *qcom, bool wakeup)
 {
        int ret;
        int i;
@@ -424,7 +443,7 @@ static int dwc3_qcom_resume(struct dwc3_qcom *qcom)
        if (!qcom->is_suspended)
                return 0;
 
-       if (device_may_wakeup(qcom->dev))
+       if (dwc3_qcom_is_host(qcom) && wakeup)
                dwc3_qcom_disable_interrupts(qcom);
 
        for (i = 0; i < qcom->num_clocks; i++) {
@@ -458,7 +477,11 @@ static irqreturn_t qcom_dwc3_resume_irq(int irq, void *data)
        if (qcom->pm_suspended)
                return IRQ_HANDLED;
 
-       if (dwc->xhci)
+       /*
+        * This is safe as role switching is done from a freezable workqueue
+        * and the wakeup interrupts are disabled as part of resume.
+        */
+       if (dwc3_qcom_is_host(qcom))
                pm_runtime_resume(&dwc->xhci->dev);
 
        return IRQ_HANDLED;
@@ -757,13 +780,13 @@ dwc3_qcom_create_urs_usb_platdev(struct device *dev)
 
 static int dwc3_qcom_probe(struct platform_device *pdev)
 {
-       struct device_node *np = pdev->dev.of_node;
-       struct device *dev = &pdev->dev;
-       struct dwc3_qcom *qcom;
-       struct resource *res, *parent_res = NULL;
-       int ret, i;
-       bool ignore_pipe_clk;
-       struct generic_pm_domain *genpd;
+       struct device_node      *np = pdev->dev.of_node;
+       struct device           *dev = &pdev->dev;
+       struct dwc3_qcom        *qcom;
+       struct resource         *res, *parent_res = NULL;
+       int                     ret, i;
+       bool                    ignore_pipe_clk;
+       bool                    wakeup_source;
 
        qcom = devm_kzalloc(&pdev->dev, sizeof(*qcom), GFP_KERNEL);
        if (!qcom)
@@ -772,8 +795,6 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, qcom);
        qcom->dev = &pdev->dev;
 
-       genpd = pd_to_genpd(qcom->dev->pm_domain);
-
        if (has_acpi_companion(dev)) {
                qcom->acpi_pdata = acpi_device_get_match_data(dev);
                if (!qcom->acpi_pdata) {
@@ -881,16 +902,9 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
        if (ret)
                goto interconnect_exit;
 
-       if (device_can_wakeup(&qcom->dwc3->dev)) {
-               /*
-                * Setting GENPD_FLAG_ALWAYS_ON flag takes care of keeping
-                * genpd on in both runtime suspend and system suspend cases.
-                */
-               genpd->flags |= GENPD_FLAG_ALWAYS_ON;
-               device_init_wakeup(&pdev->dev, true);
-       } else {
-               genpd->flags |= GENPD_FLAG_RPM_ALWAYS_ON;
-       }
+       wakeup_source = of_property_read_bool(dev->of_node, "wakeup-source");
+       device_init_wakeup(&pdev->dev, wakeup_source);
+       device_init_wakeup(&qcom->dwc3->dev, wakeup_source);
 
        qcom->is_suspended = false;
        pm_runtime_set_active(dev);
@@ -944,39 +958,45 @@ static int dwc3_qcom_remove(struct platform_device *pdev)
 static int __maybe_unused dwc3_qcom_pm_suspend(struct device *dev)
 {
        struct dwc3_qcom *qcom = dev_get_drvdata(dev);
-       int ret = 0;
+       bool wakeup = device_may_wakeup(dev);
+       int ret;
 
-       ret = dwc3_qcom_suspend(qcom);
-       if (!ret)
-               qcom->pm_suspended = true;
+       ret = dwc3_qcom_suspend(qcom, wakeup);
+       if (ret)
+               return ret;
 
-       return ret;
+       qcom->pm_suspended = true;
+
+       return 0;
 }
 
 static int __maybe_unused dwc3_qcom_pm_resume(struct device *dev)
 {
        struct dwc3_qcom *qcom = dev_get_drvdata(dev);
+       bool wakeup = device_may_wakeup(dev);
        int ret;
 
-       ret = dwc3_qcom_resume(qcom);
-       if (!ret)
-               qcom->pm_suspended = false;
+       ret = dwc3_qcom_resume(qcom, wakeup);
+       if (ret)
+               return ret;
 
-       return ret;
+       qcom->pm_suspended = false;
+
+       return 0;
 }
 
 static int __maybe_unused dwc3_qcom_runtime_suspend(struct device *dev)
 {
        struct dwc3_qcom *qcom = dev_get_drvdata(dev);
 
-       return dwc3_qcom_suspend(qcom);
+       return dwc3_qcom_suspend(qcom, true);
 }
 
 static int __maybe_unused dwc3_qcom_runtime_resume(struct device *dev)
 {
        struct dwc3_qcom *qcom = dev_get_drvdata(dev);
 
-       return dwc3_qcom_resume(qcom);
+       return dwc3_qcom_resume(qcom, true);
 }
 
 static const struct dev_pm_ops dwc3_qcom_dev_pm_ops = {
index aeeec75..eca945f 100644 (file)
@@ -2539,9 +2539,6 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
 
        is_on = !!is_on;
 
-       if (dwc->pullups_connected == is_on)
-               return 0;
-
        dwc->softconnect = is_on;
 
        /*
@@ -2566,6 +2563,11 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
                return 0;
        }
 
+       if (dwc->pullups_connected == is_on) {
+               pm_runtime_put(dwc->dev);
+               return 0;
+       }
+
        if (!is_on) {
                ret = dwc3_gadget_soft_disconnect(dwc);
        } else {
index f56c30c..a7154fe 100644 (file)
 #include <linux/of.h>
 #include <linux/platform_device.h>
 
+#include "../host/xhci-plat.h"
 #include "core.h"
 
+static const struct xhci_plat_priv dwc3_xhci_plat_priv = {
+       .quirks = XHCI_SKIP_PHY_INIT,
+};
+
 static void dwc3_host_fill_xhci_irq_res(struct dwc3 *dwc,
                                        int irq, char *name)
 {
@@ -92,6 +97,11 @@ int dwc3_host_init(struct dwc3 *dwc)
                goto err;
        }
 
+       ret = platform_device_add_data(xhci, &dwc3_xhci_plat_priv,
+                                       sizeof(dwc3_xhci_plat_priv));
+       if (ret)
+               goto err;
+
        memset(props, 0, sizeof(struct property_entry) * ARRAY_SIZE(props));
 
        if (dwc->usb3_lpm_capable)
@@ -135,4 +145,5 @@ err:
 void dwc3_host_exit(struct dwc3 *dwc)
 {
        platform_device_unregister(dwc->xhci);
+       dwc->xhci = NULL;
 }
index 1905a8d..08726e4 100644 (file)
@@ -291,6 +291,12 @@ static struct usb_endpoint_descriptor ss_ep_int_desc = {
        .bInterval = 4,
 };
 
+static struct usb_ss_ep_comp_descriptor ss_ep_int_desc_comp = {
+       .bLength = sizeof(ss_ep_int_desc_comp),
+       .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+       .wBytesPerInterval = cpu_to_le16(6),
+};
+
 /* Audio Streaming OUT Interface - Alt0 */
 static struct usb_interface_descriptor std_as_out_if0_desc = {
        .bLength = sizeof std_as_out_if0_desc,
@@ -604,7 +610,8 @@ static struct usb_descriptor_header *ss_audio_desc[] = {
        (struct usb_descriptor_header *)&in_feature_unit_desc,
        (struct usb_descriptor_header *)&io_out_ot_desc,
 
-  (struct usb_descriptor_header *)&ss_ep_int_desc,
+       (struct usb_descriptor_header *)&ss_ep_int_desc,
+       (struct usb_descriptor_header *)&ss_ep_int_desc_comp,
 
        (struct usb_descriptor_header *)&std_as_out_if0_desc,
        (struct usb_descriptor_header *)&std_as_out_if1_desc,
@@ -800,6 +807,7 @@ static void setup_headers(struct f_uac2_opts *opts,
        struct usb_ss_ep_comp_descriptor *epout_desc_comp = NULL;
        struct usb_ss_ep_comp_descriptor *epin_desc_comp = NULL;
        struct usb_ss_ep_comp_descriptor *epin_fback_desc_comp = NULL;
+       struct usb_ss_ep_comp_descriptor *ep_int_desc_comp = NULL;
        struct usb_endpoint_descriptor *epout_desc;
        struct usb_endpoint_descriptor *epin_desc;
        struct usb_endpoint_descriptor *epin_fback_desc;
@@ -827,6 +835,7 @@ static void setup_headers(struct f_uac2_opts *opts,
                epin_fback_desc = &ss_epin_fback_desc;
                epin_fback_desc_comp = &ss_epin_fback_desc_comp;
                ep_int_desc = &ss_ep_int_desc;
+               ep_int_desc_comp = &ss_ep_int_desc_comp;
        }
 
        i = 0;
@@ -855,8 +864,11 @@ static void setup_headers(struct f_uac2_opts *opts,
        if (EPOUT_EN(opts))
                headers[i++] = USBDHDR(&io_out_ot_desc);
 
-       if (FUOUT_EN(opts) || FUIN_EN(opts))
+       if (FUOUT_EN(opts) || FUIN_EN(opts)) {
                headers[i++] = USBDHDR(ep_int_desc);
+               if (ep_int_desc_comp)
+                       headers[i++] = USBDHDR(ep_int_desc_comp);
+       }
 
        if (EPOUT_EN(opts)) {
                headers[i++] = USBDHDR(&std_as_out_if0_desc);
index 03035db..208c6a9 100644 (file)
@@ -294,8 +294,10 @@ EXPORT_SYMBOL_GPL(fsg_lun_fsync_sub);
 void store_cdrom_address(u8 *dest, int msf, u32 addr)
 {
        if (msf) {
-               /* Convert to Minutes-Seconds-Frames */
-               addr >>= 2;             /* Convert to 2048-byte frames */
+               /*
+                * Convert to Minutes-Seconds-Frames.
+                * Sector size is already set to 2048 bytes.
+                */
                addr += 2*75;           /* Lead-in occupies 2 seconds */
                dest[3] = addr % 75;    /* Frames */
                addr /= 75;
index cafcf26..c63c0c2 100644 (file)
@@ -736,7 +736,10 @@ int usb_gadget_disconnect(struct usb_gadget *gadget)
        ret = gadget->ops->pullup(gadget, 0);
        if (!ret) {
                gadget->connected = 0;
-               gadget->udc->driver->disconnect(gadget);
+               mutex_lock(&udc_lock);
+               if (gadget->udc->driver)
+                       gadget->udc->driver->disconnect(gadget);
+               mutex_unlock(&udc_lock);
        }
 
 out:
@@ -1489,7 +1492,6 @@ static int gadget_bind_driver(struct device *dev)
 
        usb_gadget_udc_set_speed(udc, driver->max_speed);
 
-       mutex_lock(&udc_lock);
        ret = driver->bind(udc->gadget, driver);
        if (ret)
                goto err_bind;
@@ -1499,7 +1501,6 @@ static int gadget_bind_driver(struct device *dev)
                goto err_start;
        usb_gadget_enable_async_callbacks(udc);
        usb_udc_connect_control(udc);
-       mutex_unlock(&udc_lock);
 
        kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
        return 0;
@@ -1512,6 +1513,7 @@ static int gadget_bind_driver(struct device *dev)
                dev_err(&udc->dev, "failed to start %s: %d\n",
                        driver->function, ret);
 
+       mutex_lock(&udc_lock);
        udc->driver = NULL;
        driver->is_bound = false;
        mutex_unlock(&udc_lock);
@@ -1529,7 +1531,6 @@ static void gadget_unbind_driver(struct device *dev)
 
        kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
 
-       mutex_lock(&udc_lock);
        usb_gadget_disconnect(gadget);
        usb_gadget_disable_async_callbacks(udc);
        if (gadget->irq)
@@ -1537,6 +1538,7 @@ static void gadget_unbind_driver(struct device *dev)
        udc->driver->unbind(gadget);
        usb_gadget_udc_stop(udc);
 
+       mutex_lock(&udc_lock);
        driver->is_bound = false;
        udc->driver = NULL;
        mutex_unlock(&udc_lock);
@@ -1612,7 +1614,7 @@ static ssize_t soft_connect_store(struct device *dev,
        struct usb_udc          *udc = container_of(dev, struct usb_udc, dev);
        ssize_t                 ret;
 
-       mutex_lock(&udc_lock);
+       device_lock(&udc->gadget->dev);
        if (!udc->driver) {
                dev_err(dev, "soft-connect without a gadget driver\n");
                ret = -EOPNOTSUPP;
@@ -1633,7 +1635,7 @@ static ssize_t soft_connect_store(struct device *dev,
 
        ret = n;
 out:
-       mutex_unlock(&udc_lock);
+       device_unlock(&udc->gadget->dev);
        return ret;
 }
 static DEVICE_ATTR_WO(soft_connect);
@@ -1652,11 +1654,15 @@ static ssize_t function_show(struct device *dev, struct device_attribute *attr,
                             char *buf)
 {
        struct usb_udc          *udc = container_of(dev, struct usb_udc, dev);
-       struct usb_gadget_driver *drv = udc->driver;
+       struct usb_gadget_driver *drv;
+       int                     rc = 0;
 
-       if (!drv || !drv->function)
-               return 0;
-       return scnprintf(buf, PAGE_SIZE, "%s\n", drv->function);
+       mutex_lock(&udc_lock);
+       drv = udc->driver;
+       if (drv && drv->function)
+               rc = scnprintf(buf, PAGE_SIZE, "%s\n", drv->function);
+       mutex_unlock(&udc_lock);
+       return rc;
 }
 static DEVICE_ATTR_RO(function);
 
index 0fdc014..4619d5e 100644 (file)
@@ -652,7 +652,7 @@ struct xhci_hub *xhci_get_rhub(struct usb_hcd *hcd)
  * It will release and re-aquire the lock while calling ACPI
  * method.
  */
-void xhci_set_port_power(struct xhci_hcd *xhci, struct usb_hcd *hcd,
+static void xhci_set_port_power(struct xhci_hcd *xhci, struct usb_hcd *hcd,
                                u16 index, bool on, unsigned long *flags)
        __must_hold(&xhci->lock)
 {
@@ -1648,6 +1648,17 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
 
        status = bus_state->resuming_ports;
 
+       /*
+        * SS devices are only visible to roothub after link training completes.
+        * Keep polling roothubs for a grace period after xHC start
+        */
+       if (xhci->run_graceperiod) {
+               if (time_before(jiffies, xhci->run_graceperiod))
+                       status = 1;
+               else
+                       xhci->run_graceperiod = 0;
+       }
+
        mask = PORT_CSC | PORT_PEC | PORT_OCC | PORT_PLC | PORT_WRC | PORT_CEC;
 
        /* For each port, did anything change?  If so, set that bit in buf. */
index 06a6b19..579899e 100644 (file)
@@ -425,7 +425,6 @@ static int check_fs_bus_bw(struct mu3h_sch_ep_info *sch_ep, int offset)
 
 static int check_sch_tt(struct mu3h_sch_ep_info *sch_ep, u32 offset)
 {
-       u32 extra_cs_count;
        u32 start_ss, last_ss;
        u32 start_cs, last_cs;
 
@@ -461,18 +460,12 @@ static int check_sch_tt(struct mu3h_sch_ep_info *sch_ep, u32 offset)
                if (last_cs > 7)
                        return -ESCH_CS_OVERFLOW;
 
-               if (sch_ep->ep_type == ISOC_IN_EP)
-                       extra_cs_count = (last_cs == 7) ? 1 : 2;
-               else /*  ep_type : INTR IN / INTR OUT */
-                       extra_cs_count = 1;
-
-               cs_count += extra_cs_count;
                if (cs_count > 7)
                        cs_count = 7; /* HW limit */
 
                sch_ep->cs_count = cs_count;
-               /* one for ss, the other for idle */
-               sch_ep->num_budget_microframes = cs_count + 2;
+               /* ss, idle are ignored */
+               sch_ep->num_budget_microframes = cs_count;
 
                /*
                 * if interval=1, maxp >752, num_budge_micoframe is larger
@@ -771,8 +764,8 @@ int xhci_mtk_drop_ep(struct usb_hcd *hcd, struct usb_device *udev,
        if (ret)
                return ret;
 
-       if (ep->hcpriv)
-               drop_ep_quirk(hcd, udev, ep);
+       /* needn't check @ep->hcpriv, xhci_endpoint_disable set it NULL */
+       drop_ep_quirk(hcd, udev, ep);
 
        return 0;
 }
index 0448558..a8641b6 100644 (file)
@@ -398,12 +398,17 @@ static int xhci_plat_remove(struct platform_device *dev)
        pm_runtime_get_sync(&dev->dev);
        xhci->xhc_state |= XHCI_STATE_REMOVING;
 
-       usb_remove_hcd(shared_hcd);
-       xhci->shared_hcd = NULL;
+       if (shared_hcd) {
+               usb_remove_hcd(shared_hcd);
+               xhci->shared_hcd = NULL;
+       }
+
        usb_phy_shutdown(hcd->usb_phy);
 
        usb_remove_hcd(hcd);
-       usb_put_hcd(shared_hcd);
+
+       if (shared_hcd)
+               usb_put_hcd(shared_hcd);
 
        clk_disable_unprepare(clk);
        clk_disable_unprepare(reg_clk);
index 65858f6..3864928 100644 (file)
@@ -151,9 +151,11 @@ int xhci_start(struct xhci_hcd *xhci)
                xhci_err(xhci, "Host took too long to start, "
                                "waited %u microseconds.\n",
                                XHCI_MAX_HALT_USEC);
-       if (!ret)
+       if (!ret) {
                /* clear state flags. Including dying, halted or removing */
                xhci->xhc_state = 0;
+               xhci->run_graceperiod = jiffies + msecs_to_jiffies(500);
+       }
 
        return ret;
 }
@@ -791,8 +793,6 @@ static void xhci_stop(struct usb_hcd *hcd)
 void xhci_shutdown(struct usb_hcd *hcd)
 {
        struct xhci_hcd *xhci = hcd_to_xhci(hcd);
-       unsigned long flags;
-       int i;
 
        if (xhci->quirks & XHCI_SPURIOUS_REBOOT)
                usb_disable_xhci_ports(to_pci_dev(hcd->self.sysdev));
@@ -808,21 +808,12 @@ void xhci_shutdown(struct usb_hcd *hcd)
                del_timer_sync(&xhci->shared_hcd->rh_timer);
        }
 
-       spin_lock_irqsave(&xhci->lock, flags);
+       spin_lock_irq(&xhci->lock);
        xhci_halt(xhci);
-
-       /* Power off USB2 ports*/
-       for (i = 0; i < xhci->usb2_rhub.num_ports; i++)
-               xhci_set_port_power(xhci, xhci->main_hcd, i, false, &flags);
-
-       /* Power off USB3 ports*/
-       for (i = 0; i < xhci->usb3_rhub.num_ports; i++)
-               xhci_set_port_power(xhci, xhci->shared_hcd, i, false, &flags);
-
        /* Workaround for spurious wakeups at shutdown with HSW */
        if (xhci->quirks & XHCI_SPURIOUS_WAKEUP)
                xhci_reset(xhci, XHCI_RESET_SHORT_USEC);
-       spin_unlock_irqrestore(&xhci->lock, flags);
+       spin_unlock_irq(&xhci->lock);
 
        xhci_cleanup_msix(xhci);
 
index 1960b47..7caa0db 100644 (file)
@@ -1826,7 +1826,7 @@ struct xhci_hcd {
 
        /* Host controller watchdog timer structures */
        unsigned int            xhc_state;
-
+       unsigned long           run_graceperiod;
        u32                     command;
        struct s3_save          s3;
 /* Host controller is dying - not responding to commands. "I'm not dead yet!"
@@ -2196,8 +2196,6 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,
 int xhci_hub_status_data(struct usb_hcd *hcd, char *buf);
 int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1);
 struct xhci_hub *xhci_get_rhub(struct usb_hcd *hcd);
-void xhci_set_port_power(struct xhci_hcd *xhci, struct usb_hcd *hcd, u16 index,
-                        bool on, unsigned long *flags);
 
 void xhci_hc_died(struct xhci_hcd *xhci);
 
index d1df153..d63c639 100644 (file)
@@ -71,10 +71,7 @@ static int onboard_hub_power_off(struct onboard_hub *hub)
 {
        int err;
 
-       if (hub->reset_gpio) {
-               gpiod_set_value_cansleep(hub->reset_gpio, 1);
-               fsleep(hub->pdata->reset_us);
-       }
+       gpiod_set_value_cansleep(hub->reset_gpio, 1);
 
        err = regulator_disable(hub->vdd);
        if (err) {
index f906dfd..6c8f776 100644 (file)
@@ -86,7 +86,7 @@ config USB_MUSB_TUSB6010
        tristate "TUSB6010"
        depends on HAS_IOMEM
        depends on ARCH_OMAP2PLUS || COMPILE_TEST
-       depends on NOP_USB_XCEIV = USB_MUSB_HDRC # both built-in or both modules
+       depends on NOP_USB_XCEIV!=m || USB_MUSB_HDRC=m
 
 config USB_MUSB_OMAP2PLUS
        tristate "OMAP2430 and onwards"
index 2798fca..af01a46 100644 (file)
@@ -97,7 +97,10 @@ struct ch341_private {
        u8 mcr;
        u8 msr;
        u8 lcr;
+
        unsigned long quirks;
+       u8 version;
+
        unsigned long break_end;
 };
 
@@ -250,8 +253,12 @@ static int ch341_set_baudrate_lcr(struct usb_device *dev,
        /*
         * CH341A buffers data until a full endpoint-size packet (32 bytes)
         * has been received unless bit 7 is set.
+        *
+        * At least one device with version 0x27 appears to have this bit
+        * inverted.
         */
-       val |= BIT(7);
+       if (priv->version > 0x27)
+               val |= BIT(7);
 
        r = ch341_control_out(dev, CH341_REQ_WRITE_REG,
                              CH341_REG_DIVISOR << 8 | CH341_REG_PRESCALER,
@@ -265,6 +272,9 @@ static int ch341_set_baudrate_lcr(struct usb_device *dev,
         * (stop bits, parity and word length). Version 0x30 and above use
         * CH341_REG_LCR only and CH341_REG_LCR2 is always set to zero.
         */
+       if (priv->version < 0x30)
+               return 0;
+
        r = ch341_control_out(dev, CH341_REQ_WRITE_REG,
                              CH341_REG_LCR2 << 8 | CH341_REG_LCR, lcr);
        if (r)
@@ -308,7 +318,9 @@ static int ch341_configure(struct usb_device *dev, struct ch341_private *priv)
        r = ch341_control_in(dev, CH341_REQ_READ_VERSION, 0, 0, buffer, size);
        if (r)
                return r;
-       dev_dbg(&dev->dev, "Chip version: 0x%02x\n", buffer[0]);
+
+       priv->version = buffer[0];
+       dev_dbg(&dev->dev, "Chip version: 0x%02x\n", priv->version);
 
        r = ch341_control_out(dev, CH341_REQ_SERIAL_INIT, 0, 0);
        if (r < 0)
index c374620..a34957c 100644 (file)
@@ -130,6 +130,7 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x10C4, 0x83AA) }, /* Mark-10 Digital Force Gauge */
        { USB_DEVICE(0x10C4, 0x83D8) }, /* DekTec DTA Plus VHF/UHF Booster/Attenuator */
        { USB_DEVICE(0x10C4, 0x8411) }, /* Kyocera GPS Module */
+       { USB_DEVICE(0x10C4, 0x8414) }, /* Decagon USB Cable Adapter */
        { USB_DEVICE(0x10C4, 0x8418) }, /* IRZ Automation Teleport SG-10 GSM/GPRS Modem */
        { USB_DEVICE(0x10C4, 0x846E) }, /* BEI USB Sensor Interface (VCP) */
        { USB_DEVICE(0x10C4, 0x8470) }, /* Juniper Networks BX Series System Console */
index d5a3986..52d59be 100644 (file)
@@ -1045,6 +1045,8 @@ static const struct usb_device_id id_table_combined[] = {
        /* IDS GmbH devices */
        { USB_DEVICE(IDS_VID, IDS_SI31A_PID) },
        { USB_DEVICE(IDS_VID, IDS_CM31A_PID) },
+       /* Omron devices */
+       { USB_DEVICE(OMRON_VID, OMRON_CS1W_CIF31_PID) },
        /* U-Blox devices */
        { USB_DEVICE(UBLOX_VID, UBLOX_C099F9P_ZED_PID) },
        { USB_DEVICE(UBLOX_VID, UBLOX_C099F9P_ODIN_PID) },
index 4e92c16..31c8cca 100644 (file)
 #define INFINEON_TRIBOARD_TC2X7_PID    0x0043 /* DAS JTAG TriBoard TC2X7 V1.0 */
 
 /*
+ * Omron corporation (https://www.omron.com)
+ */
+ #define OMRON_VID                     0x0590
+ #define OMRON_CS1W_CIF31_PID          0x00b2
+
+/*
  * Acton Research Corp.
  */
 #define ACTON_VID              0x0647  /* Vendor ID */
index de59fa9..a5e8374 100644 (file)
@@ -253,6 +253,7 @@ static void option_instat_callback(struct urb *urb);
 #define QUECTEL_PRODUCT_BG96                   0x0296
 #define QUECTEL_PRODUCT_EP06                   0x0306
 #define QUECTEL_PRODUCT_EM05G                  0x030a
+#define QUECTEL_PRODUCT_EM060K                 0x030b
 #define QUECTEL_PRODUCT_EM12                   0x0512
 #define QUECTEL_PRODUCT_RM500Q                 0x0800
 #define QUECTEL_PRODUCT_EC200S_CN              0x6002
@@ -438,6 +439,8 @@ static void option_instat_callback(struct urb *urb);
 #define CINTERION_PRODUCT_MV31_2_RMNET         0x00b9
 #define CINTERION_PRODUCT_MV32_WA              0x00f1
 #define CINTERION_PRODUCT_MV32_WB              0x00f2
+#define CINTERION_PRODUCT_MV32_WA_RMNET                0x00f3
+#define CINTERION_PRODUCT_MV32_WB_RMNET                0x00f4
 
 /* Olivetti products */
 #define OLIVETTI_VENDOR_ID                     0x0b3c
@@ -573,6 +576,10 @@ static void option_instat_callback(struct urb *urb);
 #define WETELECOM_PRODUCT_6802                 0x6802
 #define WETELECOM_PRODUCT_WMD300               0x6803
 
+/* OPPO products */
+#define OPPO_VENDOR_ID                         0x22d9
+#define OPPO_PRODUCT_R11                       0x276c
+
 
 /* Device flags */
 
@@ -1138,6 +1145,9 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06, 0xff, 0, 0) },
        { USB_DEVICE_INTERFACE_CLASS(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM05G, 0xff),
          .driver_info = RSVD(6) | ZLP },
+       { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM060K, 0xff, 0x00, 0x40) },
+       { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM060K, 0xff, 0xff, 0x30) },
+       { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM060K, 0xff, 0xff, 0x40) },
        { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM12, 0xff, 0xff, 0xff),
          .driver_info = RSVD(1) | RSVD(2) | RSVD(3) | RSVD(4) | NUMEP2 },
        { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM12, 0xff, 0, 0) },
@@ -1993,8 +2003,12 @@ static const struct usb_device_id option_ids[] = {
          .driver_info = RSVD(0)},
        { USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_MV32_WA, 0xff),
          .driver_info = RSVD(3)},
+       { USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_MV32_WA_RMNET, 0xff),
+         .driver_info = RSVD(0) },
        { USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_MV32_WB, 0xff),
          .driver_info = RSVD(3)},
+       { USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_MV32_WB_RMNET, 0xff),
+         .driver_info = RSVD(0) },
        { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100),
          .driver_info = RSVD(4) },
        { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD120),
@@ -2155,6 +2169,7 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1404, 0xff) },                   /* GosunCn GM500 RNDIS */
        { USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1405, 0xff) },                   /* GosunCn GM500 MBIM */
        { USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1406, 0xff) },                   /* GosunCn GM500 ECM/NCM */
+       { USB_DEVICE_AND_INTERFACE_INFO(OPPO_VENDOR_ID, OPPO_PRODUCT_R11, 0xff, 0xff, 0x30) },
        { } /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, option_ids);
index 1a05e3d..4993227 100644 (file)
@@ -2294,6 +2294,13 @@ UNUSUAL_DEV( 0x1e74, 0x4621, 0x0000, 0x0000,
                USB_SC_DEVICE, USB_PR_DEVICE, NULL,
                US_FL_BULK_IGNORE_TAG | US_FL_MAX_SECTORS_64 ),
 
+/* Reported by Witold Lipieta <witold.lipieta@thaumatec.com> */
+UNUSUAL_DEV( 0x1fc9, 0x0117, 0x0100, 0x0100,
+               "NXP Semiconductors",
+               "PN7462AU",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_IGNORE_RESIDUE ),
+
 /* Supplied with some Castlewood ORB removable drives */
 UNUSUAL_DEV(  0x2027, 0xa001, 0x0000, 0x9999,
                "Double-H Technology",
index 4051c8c..23ab3b0 100644 (file)
@@ -62,6 +62,13 @@ UNUSUAL_DEV(0x0984, 0x0301, 0x0128, 0x0128,
                USB_SC_DEVICE, USB_PR_DEVICE, NULL,
                US_FL_IGNORE_UAS),
 
+/* Reported-by: Tom Hu <huxiaoying@kylinos.cn> */
+UNUSUAL_DEV(0x0b05, 0x1932, 0x0000, 0x9999,
+               "ASUS",
+               "External HDD",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_IGNORE_UAS),
+
 /* Reported-by: David Webb <djw@noc.ac.uk> */
 UNUSUAL_DEV(0x0bc2, 0x331a, 0x0000, 0x9999,
                "Seagate",
index c1d8c23..de66a29 100644 (file)
@@ -99,8 +99,8 @@ static int dp_altmode_configure(struct dp_altmode *dp, u8 con)
        case DP_STATUS_CON_UFP_D:
        case DP_STATUS_CON_BOTH: /* NOTE: First acting as DP source */
                conf |= DP_CONF_UFP_U_AS_UFP_D;
-               pin_assign = DP_CAP_DFP_D_PIN_ASSIGN(dp->alt->vdo) &
-                            DP_CAP_UFP_D_PIN_ASSIGN(dp->port->vdo);
+               pin_assign = DP_CAP_PIN_ASSIGN_UFP_D(dp->alt->vdo) &
+                                DP_CAP_PIN_ASSIGN_DFP_D(dp->port->vdo);
                break;
        default:
                break;
index ebc29ec..bd5e5dd 100644 (file)
@@ -2346,6 +2346,7 @@ static void __exit typec_exit(void)
        ida_destroy(&typec_index_ida);
        bus_unregister(&typec_bus);
        class_unregister(&typec_mux_class);
+       class_unregister(&retimer_class);
 }
 module_exit(typec_exit);
 
index 47b733f..a8e273f 100644 (file)
@@ -571,9 +571,11 @@ err_unregister_switch:
 
 static int is_memory(struct acpi_resource *res, void *data)
 {
-       struct resource r;
+       struct resource_win win = {};
+       struct resource *r = &win.res;
 
-       return !acpi_dev_resource_memory(res, &r);
+       return !(acpi_dev_resource_memory(res, r) ||
+                acpi_dev_resource_address_space(res, &win));
 }
 
 /* IOM ACPI IDs and IOM_PORT_STATUS_OFFSET */
@@ -583,6 +585,9 @@ static const struct acpi_device_id iom_acpi_ids[] = {
 
        /* AlderLake */
        { "INTC1079", 0x160, },
+
+       /* Meteor Lake */
+       { "INTC107A", 0x160, },
        {}
 };
 
index ea5a917..904c7b4 100644 (file)
@@ -6320,6 +6320,13 @@ static int tcpm_psy_set_prop(struct power_supply *psy,
        struct tcpm_port *port = power_supply_get_drvdata(psy);
        int ret;
 
+       /*
+        * All the properties below are related to USB PD. The check needs to be
+        * property specific when a non-pd related property is added.
+        */
+       if (!port->pd_supported)
+               return -EOPNOTSUPP;
+
        switch (psp) {
        case POWER_SUPPLY_PROP_ONLINE:
                ret = tcpm_psy_set_online(port, val);
index 1aea464..7f2624f 100644 (file)
@@ -1200,32 +1200,6 @@ out_unlock:
        return ret;
 }
 
-static void ucsi_unregister_connectors(struct ucsi *ucsi)
-{
-       struct ucsi_connector *con;
-       int i;
-
-       if (!ucsi->connector)
-               return;
-
-       for (i = 0; i < ucsi->cap.num_connectors; i++) {
-               con = &ucsi->connector[i];
-
-               if (!con->wq)
-                       break;
-
-               cancel_work_sync(&con->work);
-               ucsi_unregister_partner(con);
-               ucsi_unregister_altmodes(con, UCSI_RECIPIENT_CON);
-               ucsi_unregister_port_psy(con);
-               destroy_workqueue(con->wq);
-               typec_unregister_port(con->port);
-       }
-
-       kfree(ucsi->connector);
-       ucsi->connector = NULL;
-}
-
 /**
  * ucsi_init - Initialize UCSI interface
  * @ucsi: UCSI to be initialized
@@ -1234,6 +1208,7 @@ static void ucsi_unregister_connectors(struct ucsi *ucsi)
  */
 static int ucsi_init(struct ucsi *ucsi)
 {
+       struct ucsi_connector *con;
        u64 command;
        int ret;
        int i;
@@ -1264,7 +1239,7 @@ static int ucsi_init(struct ucsi *ucsi)
        }
 
        /* Allocate the connectors. Released in ucsi_unregister() */
-       ucsi->connector = kcalloc(ucsi->cap.num_connectors,
+       ucsi->connector = kcalloc(ucsi->cap.num_connectors + 1,
                                  sizeof(*ucsi->connector), GFP_KERNEL);
        if (!ucsi->connector) {
                ret = -ENOMEM;
@@ -1288,7 +1263,15 @@ static int ucsi_init(struct ucsi *ucsi)
        return 0;
 
 err_unregister:
-       ucsi_unregister_connectors(ucsi);
+       for (con = ucsi->connector; con->port; con++) {
+               ucsi_unregister_partner(con);
+               ucsi_unregister_altmodes(con, UCSI_RECIPIENT_CON);
+               ucsi_unregister_port_psy(con);
+               if (con->wq)
+                       destroy_workqueue(con->wq);
+               typec_unregister_port(con->port);
+               con->port = NULL;
+       }
 
 err_reset:
        memset(&ucsi->cap, 0, sizeof(ucsi->cap));
@@ -1402,6 +1385,7 @@ EXPORT_SYMBOL_GPL(ucsi_register);
 void ucsi_unregister(struct ucsi *ucsi)
 {
        u64 cmd = UCSI_SET_NOTIFICATION_ENABLE;
+       int i;
 
        /* Make sure that we are not in the middle of driver initialization */
        cancel_delayed_work_sync(&ucsi->work);
@@ -1409,7 +1393,18 @@ void ucsi_unregister(struct ucsi *ucsi)
        /* Disable notifications */
        ucsi->ops->async_write(ucsi, UCSI_CONTROL, &cmd, sizeof(cmd));
 
-       ucsi_unregister_connectors(ucsi);
+       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)
+                       destroy_workqueue(ucsi->connector[i].wq);
+               typec_unregister_port(ucsi->connector[i].port);
+       }
+
+       kfree(ucsi->connector);
 }
 EXPORT_SYMBOL_GPL(ucsi_unregister);
 
index e163aa9..0cbdcd1 100644 (file)
@@ -151,7 +151,10 @@ int vfio_pci_zdev_open_device(struct vfio_pci_core_device *vdev)
        if (!vdev->vdev.kvm)
                return 0;
 
-       return kvm_s390_pci_register_kvm(zdev, vdev->vdev.kvm);
+       if (zpci_kvm_hook.kvm_register)
+               return zpci_kvm_hook.kvm_register(zdev, vdev->vdev.kvm);
+
+       return -ENOENT;
 }
 
 void vfio_pci_zdev_close_device(struct vfio_pci_core_device *vdev)
@@ -161,5 +164,6 @@ void vfio_pci_zdev_close_device(struct vfio_pci_core_device *vdev)
        if (!zdev || !vdev->vdev.kvm)
                return;
 
-       kvm_s390_pci_unregister_kvm(zdev);
+       if (zpci_kvm_hook.kvm_unregister)
+               zpci_kvm_hook.kvm_unregister(zdev);
 }
index db516c9..8706482 100644 (file)
@@ -558,6 +558,18 @@ static int vaddr_get_pfns(struct mm_struct *mm, unsigned long vaddr,
        ret = pin_user_pages_remote(mm, vaddr, npages, flags | FOLL_LONGTERM,
                                    pages, NULL, NULL);
        if (ret > 0) {
+               int i;
+
+               /*
+                * The zero page is always resident, we don't need to pin it
+                * and it falls into our invalid/reserved test so we don't
+                * unpin in put_pfn().  Unpin all zero pages in the batch here.
+                */
+               for (i = 0 ; i < ret; i++) {
+                       if (unlikely(is_zero_pfn(page_to_pfn(pages[i]))))
+                               unpin_user_page(pages[i]);
+               }
+
                *pfn = page_to_pfn(pages[0]);
                goto done;
        }
index bd4dc97..db568f6 100644 (file)
@@ -290,7 +290,7 @@ static char default_sti_path[21] __read_mostly;
 static int __init sti_setup(char *str)
 {
        if (str)
-               strlcpy (default_sti_path, str, sizeof (default_sti_path));
+               strscpy(default_sti_path, str, sizeof(default_sti_path));
        
        return 1;
 }
index a3e6fae..14eb718 100644 (file)
@@ -3891,7 +3891,7 @@ static int __init atyfb_setup(char *options)
                         && (!strncmp(this_opt, "Mach64:", 7))) {
                        static unsigned char m64_num;
                        static char mach64_str[80];
-                       strlcpy(mach64_str, this_opt + 7, sizeof(mach64_str));
+                       strscpy(mach64_str, this_opt + 7, sizeof(mach64_str));
                        if (!store_video_par(mach64_str, m64_num)) {
                                m64_num++;
                                mach64_count = m64_num;
index 6851f47..a14a8d7 100644 (file)
@@ -1980,7 +1980,7 @@ static int radeon_set_fbinfo(struct radeonfb_info *rinfo)
        info->screen_base = rinfo->fb_base;
        info->screen_size = rinfo->mapped_vram;
        /* Fill fix common fields */
-       strlcpy(info->fix.id, rinfo->name, sizeof(info->fix.id));
+       strscpy(info->fix.id, rinfo->name, sizeof(info->fix.id));
         info->fix.smem_start = rinfo->fb_base_phys;
         info->fix.smem_len = rinfo->video_ram;
         info->fix.type = FB_TYPE_PACKED_PIXELS;
@@ -2094,34 +2094,34 @@ static void radeon_identify_vram(struct radeonfb_info *rinfo)
        u32 tmp;
 
        /* framebuffer size */
-        if ((rinfo->family == CHIP_FAMILY_RS100) ||
+       if ((rinfo->family == CHIP_FAMILY_RS100) ||
             (rinfo->family == CHIP_FAMILY_RS200) ||
             (rinfo->family == CHIP_FAMILY_RS300) ||
             (rinfo->family == CHIP_FAMILY_RC410) ||
             (rinfo->family == CHIP_FAMILY_RS400) ||
            (rinfo->family == CHIP_FAMILY_RS480) ) {
-          u32 tom = INREG(NB_TOM);
-          tmp = ((((tom >> 16) - (tom & 0xffff) + 1) << 6) * 1024);
-
-               radeon_fifo_wait(6);
-          OUTREG(MC_FB_LOCATION, tom);
-          OUTREG(DISPLAY_BASE_ADDR, (tom & 0xffff) << 16);
-          OUTREG(CRTC2_DISPLAY_BASE_ADDR, (tom & 0xffff) << 16);
-          OUTREG(OV0_BASE_ADDR, (tom & 0xffff) << 16);
-
-          /* This is supposed to fix the crtc2 noise problem. */
-          OUTREG(GRPH2_BUFFER_CNTL, INREG(GRPH2_BUFFER_CNTL) & ~0x7f0000);
-
-          if ((rinfo->family == CHIP_FAMILY_RS100) ||
-              (rinfo->family == CHIP_FAMILY_RS200)) {
-             /* This is to workaround the asic bug for RMX, some versions
-                of BIOS doesn't have this register initialized correctly.
-             */
-             OUTREGP(CRTC_MORE_CNTL, CRTC_H_CUTOFF_ACTIVE_EN,
-                     ~CRTC_H_CUTOFF_ACTIVE_EN);
-          }
-        } else {
-          tmp = INREG(CNFG_MEMSIZE);
+               u32 tom = INREG(NB_TOM);
+
+               tmp = ((((tom >> 16) - (tom & 0xffff) + 1) << 6) * 1024);
+               radeon_fifo_wait(6);
+               OUTREG(MC_FB_LOCATION, tom);
+               OUTREG(DISPLAY_BASE_ADDR, (tom & 0xffff) << 16);
+               OUTREG(CRTC2_DISPLAY_BASE_ADDR, (tom & 0xffff) << 16);
+               OUTREG(OV0_BASE_ADDR, (tom & 0xffff) << 16);
+
+               /* This is supposed to fix the crtc2 noise problem. */
+               OUTREG(GRPH2_BUFFER_CNTL, INREG(GRPH2_BUFFER_CNTL) & ~0x7f0000);
+
+               if ((rinfo->family == CHIP_FAMILY_RS100) ||
+                   (rinfo->family == CHIP_FAMILY_RS200)) {
+                       /* This is to workaround the asic bug for RMX, some versions
+                        * of BIOS doesn't have this register initialized correctly.
+                        */
+                       OUTREGP(CRTC_MORE_CNTL, CRTC_H_CUTOFF_ACTIVE_EN,
+                               ~CRTC_H_CUTOFF_ACTIVE_EN);
+               }
+       } else {
+               tmp = INREG(CNFG_MEMSIZE);
         }
 
        /* mem size is bits [28:0], mask off the rest */
index e7702fe..6403ae0 100644 (file)
@@ -182,7 +182,7 @@ static int bw2_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
 
 static void bw2_init_fix(struct fb_info *info, int linebytes)
 {
-       strlcpy(info->fix.id, "bwtwo", sizeof(info->fix.id));
+       strscpy(info->fix.id, "bwtwo", sizeof(info->fix.id));
 
        info->fix.type = FB_TYPE_PACKED_PIXELS;
        info->fix.visual = FB_VISUAL_MONO01;
index 393894a..2b00a9d 100644 (file)
@@ -430,6 +430,7 @@ static int chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent)
  err_release_fb:
        framebuffer_release(p);
  err_disable:
+       pci_disable_device(dp);
  err_out:
        return rc;
 }
index a41a758..2a9fa06 100644 (file)
@@ -1999,7 +1999,7 @@ static int cirrusfb_set_fbinfo(struct fb_info *info)
        }
 
        /* Fill fix common fields */
-       strlcpy(info->fix.id, cirrusfb_board_info[cinfo->btype].name,
+       strscpy(info->fix.id, cirrusfb_board_info[cinfo->btype].name,
                sizeof(info->fix.id));
 
        /* monochrome: only 1 memory plane */
index 771ce1f..a1061c2 100644 (file)
@@ -326,7 +326,7 @@ static int clps711x_fb_probe(struct platform_device *pdev)
        info->var.vmode = FB_VMODE_NONINTERLACED;
        info->fix.type = FB_TYPE_PACKED_PIXELS;
        info->fix.accel = FB_ACCEL_NONE;
-       strlcpy(info->fix.id, CLPS711X_FB_NAME, sizeof(info->fix.id));
+       strscpy(info->fix.id, CLPS711X_FB_NAME, sizeof(info->fix.id));
        fb_videomode_to_var(&info->var, &cfb->mode);
 
        ret = fb_alloc_cmap(&info->cmap, BIT(CLPS711X_FB_BPP_MAX), 0);
index cf9ac4d..098b62f 100644 (file)
@@ -412,7 +412,7 @@ static int __init fb_console_setup(char *this_opt)
 
        while ((options = strsep(&this_opt, ",")) != NULL) {
                if (!strncmp(options, "font:", 5)) {
-                       strlcpy(fontname, options + 5, sizeof(fontname));
+                       strscpy(fontname, options + 5, sizeof(fontname));
                        continue;
                }
                
@@ -2401,15 +2401,21 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount,
        struct fb_info *info = fbcon_info_from_console(vc->vc_num);
        struct fbcon_ops *ops = info->fbcon_par;
        struct fbcon_display *p = &fb_display[vc->vc_num];
-       int resize;
+       int resize, ret, old_userfont, old_width, old_height, old_charcount;
        char *old_data = NULL;
 
        resize = (w != vc->vc_font.width) || (h != vc->vc_font.height);
        if (p->userfont)
                old_data = vc->vc_font.data;
        vc->vc_font.data = (void *)(p->fontdata = data);
+       old_userfont = p->userfont;
        if ((p->userfont = userfont))
                REFCOUNT(data)++;
+
+       old_width = vc->vc_font.width;
+       old_height = vc->vc_font.height;
+       old_charcount = vc->vc_font.charcount;
+
        vc->vc_font.width = w;
        vc->vc_font.height = h;
        vc->vc_font.charcount = charcount;
@@ -2425,7 +2431,9 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount,
                rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
                cols /= w;
                rows /= h;
-               vc_resize(vc, cols, rows);
+               ret = vc_resize(vc, cols, rows);
+               if (ret)
+                       goto err_out;
        } else if (con_is_visible(vc)
                   && vc->vc_mode == KD_TEXT) {
                fbcon_clear_margins(vc, 0);
@@ -2435,6 +2443,21 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount,
        if (old_data && (--REFCOUNT(old_data) == 0))
                kfree(old_data - FONT_EXTRA_WORDS * sizeof(int));
        return 0;
+
+err_out:
+       p->fontdata = old_data;
+       vc->vc_font.data = (void *)old_data;
+
+       if (userfont) {
+               p->userfont = old_userfont;
+               REFCOUNT(data)--;
+       }
+
+       vc->vc_font.width = old_width;
+       vc->vc_font.height = old_height;
+       vc->vc_font.charcount = old_charcount;
+
+       return ret;
 }
 
 /*
index c2a60b1..4d7f638 100644 (file)
@@ -84,6 +84,10 @@ void framebuffer_release(struct fb_info *info)
        if (WARN_ON(refcount_read(&info->count)))
                return;
 
+#if IS_ENABLED(CONFIG_FB_BACKLIGHT)
+       mutex_destroy(&info->bl_curve_mutex);
+#endif
+
        kfree(info->apertures);
        kfree(info);
 }
index d45355b..8f041f9 100644 (file)
@@ -1134,7 +1134,7 @@ int cyber2000fb_attach(struct cyberpro_info *info, int idx)
                info->fb_size         = int_cfb_info->fb.fix.smem_len;
                info->info            = int_cfb_info;
 
-               strlcpy(info->dev_name, int_cfb_info->fb.fix.id,
+               strscpy(info->dev_name, int_cfb_info->fb.fix.id,
                        sizeof(info->dev_name));
        }
 
@@ -1229,7 +1229,7 @@ static int cyber2000fb_ddc_getsda(void *data)
 
 static int cyber2000fb_setup_ddc_bus(struct cfb_info *cfb)
 {
-       strlcpy(cfb->ddc_adapter.name, cfb->fb.fix.id,
+       strscpy(cfb->ddc_adapter.name, cfb->fb.fix.id,
                sizeof(cfb->ddc_adapter.name));
        cfb->ddc_adapter.owner          = THIS_MODULE;
        cfb->ddc_adapter.class          = I2C_CLASS_DDC;
@@ -1304,7 +1304,7 @@ static int cyber2000fb_i2c_getscl(void *data)
 
 static int cyber2000fb_i2c_register(struct cfb_info *cfb)
 {
-       strlcpy(cfb->i2c_adapter.name, cfb->fb.fix.id,
+       strscpy(cfb->i2c_adapter.name, cfb->fb.fix.id,
                sizeof(cfb->i2c_adapter.name));
        cfb->i2c_adapter.owner = THIS_MODULE;
        cfb->i2c_adapter.algo_data = &cfb->i2c_algo;
@@ -1500,7 +1500,7 @@ static int cyber2000fb_setup(char *options)
                if (strncmp(opt, "font:", 5) == 0) {
                        static char default_font_storage[40];
 
-                       strlcpy(default_font_storage, opt + 5,
+                       strscpy(default_font_storage, opt + 5,
                                sizeof(default_font_storage));
                        default_font = default_font_storage;
                        continue;
index b3d580e..7cba396 100644 (file)
@@ -883,7 +883,7 @@ static void ffb_init_fix(struct fb_info *info)
        } else
                ffb_type_name = "Elite 3D";
 
-       strlcpy(info->fix.id, ffb_type_name, sizeof(info->fix.id));
+       strscpy(info->fix.id, ffb_type_name, sizeof(info->fix.id));
 
        info->fix.type = FB_TYPE_PACKED_PIXELS;
        info->fix.visual = FB_VISUAL_TRUECOLOR;
index 5d34d89..e41204e 100644 (file)
@@ -410,13 +410,13 @@ static void __init gx1fb_setup(char *options)
                        continue;
 
                if (!strncmp(this_opt, "mode:", 5))
-                       strlcpy(mode_option, this_opt + 5, sizeof(mode_option));
+                       strscpy(mode_option, this_opt + 5, sizeof(mode_option));
                else if (!strncmp(this_opt, "crt:", 4))
                        crt_option = !!simple_strtoul(this_opt + 4, NULL, 0);
                else if (!strncmp(this_opt, "panel:", 6))
-                       strlcpy(panel_option, this_opt + 6, sizeof(panel_option));
+                       strscpy(panel_option, this_opt + 6, sizeof(panel_option));
                else
-                       strlcpy(mode_option, this_opt, sizeof(mode_option));
+                       strscpy(mode_option, this_opt, sizeof(mode_option));
        }
 }
 #endif
index e5475ae..94588b8 100644 (file)
@@ -650,7 +650,7 @@ static int gxt4500_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        cardtype = ent->driver_data;
        par->refclk_ps = cardinfo[cardtype].refclk_ps;
        info->fix = gxt4500_fix;
-       strlcpy(info->fix.id, cardinfo[cardtype].cardname,
+       strscpy(info->fix.id, cardinfo[cardtype].cardname,
                sizeof(info->fix.id));
        info->pseudo_palette = par->pseudo_palette;
 
index 886c564..b58b445 100644 (file)
 #define SYNTHVID_DEPTH_WIN8 32
 #define SYNTHVID_FB_SIZE_WIN8 (8 * 1024 * 1024)
 
-#define PCI_VENDOR_ID_MICROSOFT 0x1414
-#define PCI_DEVICE_ID_HYPERV_VIDEO 0x5353
-
-
 enum pipe_msg_type {
        PIPE_MSG_INVALID,
        PIPE_MSG_DATA,
index 7f09a0d..bd30d83 100644 (file)
@@ -159,7 +159,7 @@ static int i740fb_setup_ddc_bus(struct fb_info *info)
 {
        struct i740fb_par *par = info->par;
 
-       strlcpy(par->ddc_adapter.name, info->fix.id,
+       strscpy(par->ddc_adapter.name, info->fix.id,
                sizeof(par->ddc_adapter.name));
        par->ddc_adapter.owner          = THIS_MODULE;
        par->ddc_adapter.class          = I2C_CLASS_DDC;
index d97d745..94f3bc6 100644 (file)
@@ -681,7 +681,7 @@ static int imxfb_init_fbinfo(struct platform_device *pdev)
 
        fbi->devtype = pdev->id_entry->driver_data;
 
-       strlcpy(info->fix.id, IMX_NAME, sizeof(info->fix.id));
+       strscpy(info->fix.id, IMX_NAME, sizeof(info->fix.id));
 
        info->fix.type                  = FB_TYPE_PACKED_PIXELS;
        info->fix.type_aux              = 0;
index 236521b..68bba26 100644 (file)
@@ -2383,9 +2383,9 @@ static int __init matroxfb_setup(char *options) {
                else if (!strncmp(this_opt, "mem:", 4))
                        mem = simple_strtoul(this_opt+4, NULL, 0);
                else if (!strncmp(this_opt, "mode:", 5))
-                       strlcpy(videomode, this_opt+5, sizeof(videomode));
+                       strscpy(videomode, this_opt + 5, sizeof(videomode));
                else if (!strncmp(this_opt, "outputs:", 8))
-                       strlcpy(outputs, this_opt+8, sizeof(outputs));
+                       strscpy(outputs, this_opt + 8, sizeof(outputs));
                else if (!strncmp(this_opt, "dfp:", 4)) {
                        dfp_type = simple_strtoul(this_opt+4, NULL, 0);
                        dfp = 1;
@@ -2455,7 +2455,7 @@ static int __init matroxfb_setup(char *options) {
                        else if (!strcmp(this_opt, "dfp"))
                                dfp = value;
                        else {
-                               strlcpy(videomode, this_opt, sizeof(videomode));
+                               strscpy(videomode, this_opt, sizeof(videomode));
                        }
                }
        }
index dfb4ddc..17cda57 100644 (file)
@@ -1642,15 +1642,13 @@ static int omapfb_do_probe(struct platform_device *pdev,
                goto cleanup;
        }
        fbdev->int_irq = platform_get_irq(pdev, 0);
-       if (!fbdev->int_irq) {
-               dev_err(&pdev->dev, "unable to get irq\n");
+       if (fbdev->int_irq < 0) {
                r = ENXIO;
                goto cleanup;
        }
 
        fbdev->ext_irq = platform_get_irq(pdev, 1);
-       if (!fbdev->ext_irq) {
-               dev_err(&pdev->dev, "unable to get irq\n");
+       if (fbdev->ext_irq < 0) {
                r = ENXIO;
                goto cleanup;
        }
index afa688e..5ccddcf 100644 (file)
@@ -1331,7 +1331,7 @@ static void clear_fb_info(struct fb_info *fbi)
 {
        memset(&fbi->var, 0, sizeof(fbi->var));
        memset(&fbi->fix, 0, sizeof(fbi->fix));
-       strlcpy(fbi->fix.id, MODULE_NAME, sizeof(fbi->fix.id));
+       strscpy(fbi->fix.id, MODULE_NAME, sizeof(fbi->fix.id));
 }
 
 static int omapfb_free_all_fbmem(struct omapfb2_device *fbdev)
index d3be2c6..8fd79de 100644 (file)
@@ -617,6 +617,11 @@ static int pm2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
                return -EINVAL;
        }
 
+       if (!var->pixclock) {
+               DPRINTK("pixclock is zero\n");
+               return -EINVAL;
+       }
+
        if (PICOS2KHZ(var->pixclock) > PM2_MAX_PIXCLOCK) {
                DPRINTK("pixclock too high (%ldKHz)\n",
                        PICOS2KHZ(var->pixclock));
index e943300..d5d0bbd 100644 (file)
@@ -640,7 +640,7 @@ static int pxa168fb_probe(struct platform_device *pdev)
        info->flags = FBINFO_DEFAULT | FBINFO_PARTIAL_PAN_OK |
                      FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN;
        info->node = -1;
-       strlcpy(info->fix.id, mi->id, 16);
+       strscpy(info->fix.id, mi->id, 16);
        info->fix.type = FB_TYPE_PACKED_PIXELS;
        info->fix.type_aux = 0;
        info->fix.xpanstep = 0;
index 66cfc3e..696ac54 100644 (file)
@@ -2042,7 +2042,7 @@ static int __init pxafb_setup_options(void)
                return -ENODEV;
 
        if (options)
-               strlcpy(g_options, options, sizeof(g_options));
+               strscpy(g_options, options, sizeof(g_options));
 
        return 0;
 }
index 5069f6f..67b63a7 100644 (file)
@@ -248,7 +248,7 @@ static int s3fb_setup_ddc_bus(struct fb_info *info)
 {
        struct s3fb_info *par = info->par;
 
-       strlcpy(par->ddc_adapter.name, info->fix.id,
+       strscpy(par->ddc_adapter.name, info->fix.id,
                sizeof(par->ddc_adapter.name));
        par->ddc_adapter.owner          = THIS_MODULE;
        par->ddc_adapter.class          = I2C_CLASS_DDC;
index cf2a90e..e770b4a 100644 (file)
@@ -355,7 +355,7 @@ static int simplefb_regulators_get(struct simplefb_par *par,
                if (!p || p == prop->name)
                        continue;
 
-               strlcpy(name, prop->name,
+               strscpy(name, prop->name,
                        strlen(prop->name) - strlen(SUPPLY_SUFFIX) + 1);
                regulator = devm_regulator_get_optional(&pdev->dev, name);
                if (IS_ERR(regulator)) {
index f28fd69..c9e7742 100644 (file)
@@ -649,37 +649,37 @@ sisfb_validate_mode(struct sis_video_info *ivideo, int myindex, u32 vbflags)
        u16 xres=0, yres, myres;
 
 #ifdef CONFIG_FB_SIS_300
-       if(ivideo->sisvga_engine == SIS_300_VGA) {
-               if(!(sisbios_mode[myindex].chipset & MD_SIS300))
+       if (ivideo->sisvga_engine == SIS_300_VGA) {
+               if (!(sisbios_mode[myindex].chipset & MD_SIS300))
                        return -1 ;
        }
 #endif
 #ifdef CONFIG_FB_SIS_315
-       if(ivideo->sisvga_engine == SIS_315_VGA) {
-               if(!(sisbios_mode[myindex].chipset & MD_SIS315))
+       if (ivideo->sisvga_engine == SIS_315_VGA) {
+               if (!(sisbios_mode[myindex].chipset & MD_SIS315))
                        return -1;
        }
 #endif
 
        myres = sisbios_mode[myindex].yres;
 
-       switch(vbflags & VB_DISPTYPE_DISP2) {
+       switch (vbflags & VB_DISPTYPE_DISP2) {
 
        case CRT2_LCD:
                xres = ivideo->lcdxres; yres = ivideo->lcdyres;
 
-               if((ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL848) &&
-                  (ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL856)) {
-                       if(sisbios_mode[myindex].xres > xres)
+               if ((ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL848) &&
+                   (ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL856)) {
+                       if (sisbios_mode[myindex].xres > xres)
                                return -1;
-                       if(myres > yres)
+                       if (myres > yres)
                                return -1;
                }
 
-               if(ivideo->sisfb_fstn) {
-                       if(sisbios_mode[myindex].xres == 320) {
-                               if(myres == 240) {
-                                       switch(sisbios_mode[myindex].mode_no[1]) {
+               if (ivideo->sisfb_fstn) {
+                       if (sisbios_mode[myindex].xres == 320) {
+                               if (myres == 240) {
+                                       switch (sisbios_mode[myindex].mode_no[1]) {
                                                case 0x50: myindex = MODE_FSTN_8;  break;
                                                case 0x56: myindex = MODE_FSTN_16; break;
                                                case 0x53: return -1;
@@ -688,7 +688,7 @@ sisfb_validate_mode(struct sis_video_info *ivideo, int myindex, u32 vbflags)
                        }
                }
 
-               if(SiS_GetModeID_LCD(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
+               if (SiS_GetModeID_LCD(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
                                sisbios_mode[myindex].yres, 0, ivideo->sisfb_fstn,
                                ivideo->SiS_Pr.SiS_CustomT, xres, yres, ivideo->vbflags2) < 0x14) {
                        return -1;
@@ -696,14 +696,14 @@ sisfb_validate_mode(struct sis_video_info *ivideo, int myindex, u32 vbflags)
                break;
 
        case CRT2_TV:
-               if(SiS_GetModeID_TV(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
+               if (SiS_GetModeID_TV(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
                                sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
                        return -1;
                }
                break;
 
        case CRT2_VGA:
-               if(SiS_GetModeID_VGA2(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
+               if (SiS_GetModeID_VGA2(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
                                sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
                        return -1;
                }
@@ -1872,7 +1872,7 @@ sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
 
        memset(fix, 0, sizeof(struct fb_fix_screeninfo));
 
-       strlcpy(fix->id, ivideo->myid, sizeof(fix->id));
+       strscpy(fix->id, ivideo->myid, sizeof(fix->id));
 
        mutex_lock(&info->mm_lock);
        fix->smem_start  = ivideo->video_base + ivideo->video_offset;
@@ -2204,82 +2204,88 @@ static bool sisfb_test_DDC1(struct sis_video_info *ivideo)
 
 static void sisfb_sense_crt1(struct sis_video_info *ivideo)
 {
-    bool mustwait = false;
-    u8  sr1F, cr17;
+       bool mustwait = false;
+       u8  sr1F, cr17;
 #ifdef CONFIG_FB_SIS_315
-    u8  cr63=0;
+       u8  cr63 = 0;
 #endif
-    u16 temp = 0xffff;
-    int i;
+       u16 temp = 0xffff;
+       int i;
+
+       sr1F = SiS_GetReg(SISSR, 0x1F);
+       SiS_SetRegOR(SISSR, 0x1F, 0x04);
+       SiS_SetRegAND(SISSR, 0x1F, 0x3F);
 
-    sr1F = SiS_GetReg(SISSR, 0x1F);
-    SiS_SetRegOR(SISSR, 0x1F, 0x04);
-    SiS_SetRegAND(SISSR, 0x1F, 0x3F);
-    if(sr1F & 0xc0) mustwait = true;
+       if (sr1F & 0xc0)
+               mustwait = true;
 
 #ifdef CONFIG_FB_SIS_315
-    if(ivideo->sisvga_engine == SIS_315_VGA) {
-       cr63 = SiS_GetReg(SISCR, ivideo->SiS_Pr.SiS_MyCR63);
-       cr63 &= 0x40;
-       SiS_SetRegAND(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xBF);
-    }
+       if (ivideo->sisvga_engine == SIS_315_VGA) {
+               cr63 = SiS_GetReg(SISCR, ivideo->SiS_Pr.SiS_MyCR63);
+               cr63 &= 0x40;
+               SiS_SetRegAND(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xBF);
+       }
 #endif
 
-    cr17 = SiS_GetReg(SISCR, 0x17);
-    cr17 &= 0x80;
-    if(!cr17) {
-       SiS_SetRegOR(SISCR, 0x17, 0x80);
-       mustwait = true;
-       SiS_SetReg(SISSR, 0x00, 0x01);
-       SiS_SetReg(SISSR, 0x00, 0x03);
-    }
+       cr17 = SiS_GetReg(SISCR, 0x17);
+       cr17 &= 0x80;
 
-    if(mustwait) {
-       for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
-    }
+       if (!cr17) {
+               SiS_SetRegOR(SISCR, 0x17, 0x80);
+               mustwait = true;
+               SiS_SetReg(SISSR, 0x00, 0x01);
+               SiS_SetReg(SISSR, 0x00, 0x03);
+       }
 
+       if (mustwait) {
+               for (i = 0; i < 10; i++)
+                       sisfbwaitretracecrt1(ivideo);
+       }
 #ifdef CONFIG_FB_SIS_315
-    if(ivideo->chip >= SIS_330) {
-       SiS_SetRegAND(SISCR, 0x32, ~0x20);
-       if(ivideo->chip >= SIS_340) {
-          SiS_SetReg(SISCR, 0x57, 0x4a);
-       } else {
-          SiS_SetReg(SISCR, 0x57, 0x5f);
-       }
-       SiS_SetRegOR(SISCR, 0x53, 0x02);
-       while ((SiS_GetRegByte(SISINPSTAT)) & 0x01)    break;
-       while (!((SiS_GetRegByte(SISINPSTAT)) & 0x01)) break;
-       if ((SiS_GetRegByte(SISMISCW)) & 0x10) temp = 1;
-       SiS_SetRegAND(SISCR, 0x53, 0xfd);
-       SiS_SetRegAND(SISCR, 0x57, 0x00);
-    }
+       if (ivideo->chip >= SIS_330) {
+               SiS_SetRegAND(SISCR, 0x32, ~0x20);
+               if (ivideo->chip >= SIS_340)
+                       SiS_SetReg(SISCR, 0x57, 0x4a);
+               else
+                       SiS_SetReg(SISCR, 0x57, 0x5f);
+
+               SiS_SetRegOR(SISCR, 0x53, 0x02);
+               while ((SiS_GetRegByte(SISINPSTAT)) & 0x01)
+                       break;
+               while (!((SiS_GetRegByte(SISINPSTAT)) & 0x01))
+                       break;
+               if ((SiS_GetRegByte(SISMISCW)) & 0x10)
+                       temp = 1;
+
+               SiS_SetRegAND(SISCR, 0x53, 0xfd);
+               SiS_SetRegAND(SISCR, 0x57, 0x00);
+       }
 #endif
 
-    if(temp == 0xffff) {
-       i = 3;
-       do {
-         temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
-               ivideo->sisvga_engine, 0, 0, NULL, ivideo->vbflags2);
-       } while(((temp == 0) || (temp == 0xffff)) && i--);
+       if (temp == 0xffff) {
+               i = 3;
 
-       if((temp == 0) || (temp == 0xffff)) {
-          if(sisfb_test_DDC1(ivideo)) temp = 1;
-       }
-    }
+               do {
+                       temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
+                       ivideo->sisvga_engine, 0, 0, NULL, ivideo->vbflags2);
+               } while (((temp == 0) || (temp == 0xffff)) && i--);
 
-    if((temp) && (temp != 0xffff)) {
-       SiS_SetRegOR(SISCR, 0x32, 0x20);
-    }
+               if ((temp == 0) || (temp == 0xffff)) {
+                       if (sisfb_test_DDC1(ivideo))
+                               temp = 1;
+               }
+       }
+
+       if ((temp) && (temp != 0xffff))
+               SiS_SetRegOR(SISCR, 0x32, 0x20);
 
 #ifdef CONFIG_FB_SIS_315
-    if(ivideo->sisvga_engine == SIS_315_VGA) {
-       SiS_SetRegANDOR(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xBF, cr63);
-    }
+       if (ivideo->sisvga_engine == SIS_315_VGA)
+               SiS_SetRegANDOR(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xBF, cr63);
 #endif
 
-    SiS_SetRegANDOR(SISCR, 0x17, 0x7F, cr17);
-
-    SiS_SetReg(SISSR, 0x1F, sr1F);
+       SiS_SetRegANDOR(SISCR, 0x17, 0x7F, cr17);
+       SiS_SetReg(SISSR, 0x1F, sr1F);
 }
 
 /* Determine and detect attached devices on SiS30x */
@@ -2293,25 +2299,25 @@ static void SiS_SenseLCD(struct sis_video_info *ivideo)
        ivideo->SiS_Pr.PanelSelfDetected = false;
 
        /* LCD detection only for TMDS bridges */
-       if(!(ivideo->vbflags2 & VB2_SISTMDSBRIDGE))
+       if (!(ivideo->vbflags2 & VB2_SISTMDSBRIDGE))
                return;
-       if(ivideo->vbflags2 & VB2_30xBDH)
+       if (ivideo->vbflags2 & VB2_30xBDH)
                return;
 
        /* If LCD already set up by BIOS, skip it */
        reg = SiS_GetReg(SISCR, 0x32);
-       if(reg & 0x08)
+       if (reg & 0x08)
                return;
 
        realcrtno = 1;
-       if(ivideo->SiS_Pr.DDCPortMixup)
+       if (ivideo->SiS_Pr.DDCPortMixup)
                realcrtno = 0;
 
        /* Check DDC capabilities */
        temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
                                realcrtno, 0, &buffer[0], ivideo->vbflags2);
 
-       if((!temp) || (temp == 0xffff) || (!(temp & 0x02)))
+       if ((!temp) || (temp == 0xffff) || (!(temp & 0x02)))
                return;
 
        /* Read DDC data */
@@ -2320,17 +2326,17 @@ static void SiS_SenseLCD(struct sis_video_info *ivideo)
                temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
                                ivideo->sisvga_engine, realcrtno, 1,
                                &buffer[0], ivideo->vbflags2);
-       } while((temp) && i--);
+       } while ((temp) && i--);
 
-       if(temp)
+       if (temp)
                return;
 
        /* No digital device */
-       if(!(buffer[0x14] & 0x80))
+       if (!(buffer[0x14] & 0x80))
                return;
 
        /* First detailed timing preferred timing? */
-       if(!(buffer[0x18] & 0x02))
+       if (!(buffer[0x18] & 0x02))
                return;
 
        xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4);
@@ -2338,26 +2344,26 @@ static void SiS_SenseLCD(struct sis_video_info *ivideo)
 
        switch(xres) {
                case 1024:
-                       if(yres == 768)
+                       if (yres == 768)
                                paneltype = 0x02;
                        break;
                case 1280:
-                       if(yres == 1024)
+                       if (yres == 1024)
                                paneltype = 0x03;
                        break;
                case 1600:
-                       if((yres == 1200) && (ivideo->vbflags2 & VB2_30xC))
+                       if ((yres == 1200) && (ivideo->vbflags2 & VB2_30xC))
                                paneltype = 0x0b;
                        break;
        }
 
-       if(!paneltype)
+       if (!paneltype)
                return;
 
-       if(buffer[0x23])
+       if (buffer[0x23])
                cr37 |= 0x10;
 
-       if((buffer[0x47] & 0x18) == 0x18)
+       if ((buffer[0x47] & 0x18) == 0x18)
                cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20);
        else
                cr37 |= 0xc0;
@@ -2372,31 +2378,34 @@ static void SiS_SenseLCD(struct sis_video_info *ivideo)
 
 static int SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
 {
-    int temp, mytest, result, i, j;
-
-    for(j = 0; j < 10; j++) {
-       result = 0;
-       for(i = 0; i < 3; i++) {
-          mytest = test;
-          SiS_SetReg(SISPART4, 0x11, (type & 0x00ff));
-          temp = (type >> 8) | (mytest & 0x00ff);
-         SiS_SetRegANDOR(SISPART4, 0x10, 0xe0, temp);
-          SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
-          mytest >>= 8;
-          mytest &= 0x7f;
-          temp = SiS_GetReg(SISPART4, 0x03);
-          temp ^= 0x0e;
-          temp &= mytest;
-          if(temp == mytest) result++;
+       int temp, mytest, result, i, j;
+
+       for (j = 0; j < 10; j++) {
+               result = 0;
+               for (i = 0; i < 3; i++) {
+                       mytest = test;
+                       SiS_SetReg(SISPART4, 0x11, (type & 0x00ff));
+                       temp = (type >> 8) | (mytest & 0x00ff);
+                       SiS_SetRegANDOR(SISPART4, 0x10, 0xe0, temp);
+                       SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
+                       mytest >>= 8;
+                       mytest &= 0x7f;
+                       temp = SiS_GetReg(SISPART4, 0x03);
+                       temp ^= 0x0e;
+                       temp &= mytest;
+                       if (temp == mytest)
+                               result++;
 #if 1
-         SiS_SetReg(SISPART4, 0x11, 0x00);
-         SiS_SetRegAND(SISPART4, 0x10, 0xe0);
-         SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
+                       SiS_SetReg(SISPART4, 0x11, 0x00);
+                       SiS_SetRegAND(SISPART4, 0x10, 0xe0);
+                       SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
 #endif
-       }
-       if((result == 0) || (result >= 2)) break;
-    }
-    return result;
+               }
+
+               if ((result == 0) || (result >= 2))
+                       break;
+       }
+       return result;
 }
 
 static void SiS_Sense30x(struct sis_video_info *ivideo)
@@ -4262,18 +4271,17 @@ static int sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration,
        unsigned int k, RankCapacity, PageCapacity, BankNumHigh, BankNumMid;
        unsigned int PhysicalAdrOtherPage, PhysicalAdrHigh, PhysicalAdrHalfPage;
 
-        for(k = 0; k < ARRAY_SIZE(SiS_DRAMType); k++) {
-
+       for (k = 0; k < ARRAY_SIZE(SiS_DRAMType); k++) {
                RankCapacity = buswidth * SiS_DRAMType[k][3];
 
-               if(RankCapacity != PseudoRankCapacity)
+               if (RankCapacity != PseudoRankCapacity)
                        continue;
 
-               if((SiS_DRAMType[k][2] + SiS_DRAMType[k][0]) > PseudoAdrPinCount)
+               if ((SiS_DRAMType[k][2] + SiS_DRAMType[k][0]) > PseudoAdrPinCount)
                        continue;
 
                BankNumHigh = RankCapacity * 16 * iteration - 1;
-               if(iteration == 3) {             /* Rank No */
+               if (iteration == 3) {             /* Rank No */
                        BankNumMid  = RankCapacity * 16 - 1;
                } else {
                        BankNumMid  = RankCapacity * 16 * iteration / 2 - 1;
@@ -4287,18 +4295,22 @@ static int sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration,
                SiS_SetRegAND(SISSR, 0x15, 0xFB); /* Test */
                SiS_SetRegOR(SISSR, 0x15, 0x04);  /* Test */
                sr14 = (SiS_DRAMType[k][3] * buswidth) - 1;
-               if(buswidth == 4)      sr14 |= 0x80;
-               else if(buswidth == 2) sr14 |= 0x40;
+
+               if (buswidth == 4)
+                       sr14 |= 0x80;
+               else if (buswidth == 2)
+                       sr14 |= 0x40;
+
                SiS_SetReg(SISSR, 0x13, SiS_DRAMType[k][4]);
                SiS_SetReg(SISSR, 0x14, sr14);
 
                BankNumHigh <<= 16;
                BankNumMid <<= 16;
 
-               if((BankNumHigh + PhysicalAdrHigh      >= mapsize) ||
-                  (BankNumMid  + PhysicalAdrHigh      >= mapsize) ||
-                  (BankNumHigh + PhysicalAdrHalfPage  >= mapsize) ||
-                  (BankNumHigh + PhysicalAdrOtherPage >= mapsize))
+               if ((BankNumHigh + PhysicalAdrHigh >= mapsize) ||
+                   (BankNumMid  + PhysicalAdrHigh >= mapsize) ||
+                   (BankNumHigh + PhysicalAdrHalfPage  >= mapsize) ||
+                   (BankNumHigh + PhysicalAdrOtherPage >= mapsize))
                        continue;
 
                /* Write data */
@@ -4312,7 +4324,7 @@ static int sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration,
                                (FBAddr + BankNumHigh + PhysicalAdrOtherPage));
 
                /* Read data */
-               if(readw(FBAddr + BankNumHigh + PhysicalAdrHigh) == PhysicalAdrHigh)
+               if (readw(FBAddr + BankNumHigh + PhysicalAdrHigh) == PhysicalAdrHigh)
                        return 1;
        }
 
@@ -5867,7 +5879,7 @@ static int sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                        ivideo->cardnumber++;
        }
 
-       strlcpy(ivideo->myid, chipinfo->chip_name, sizeof(ivideo->myid));
+       strscpy(ivideo->myid, chipinfo->chip_name, sizeof(ivideo->myid));
 
        ivideo->warncount = 0;
        ivideo->chip_id = pdev->device;
@@ -6150,24 +6162,20 @@ static int sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 #endif
 
 #ifdef CONFIG_FB_SIS_315
-               if(ivideo->sisvga_engine == SIS_315_VGA) {
+               if (ivideo->sisvga_engine == SIS_315_VGA) {
                        int result = 1;
-               /*      if((ivideo->chip == SIS_315H)   ||
-                          (ivideo->chip == SIS_315)    ||
-                          (ivideo->chip == SIS_315PRO) ||
-                          (ivideo->chip == SIS_330)) {
-                               sisfb_post_sis315330(pdev);
-                       } else */ if(ivideo->chip == XGI_20) {
+
+                       if (ivideo->chip == XGI_20) {
                                result = sisfb_post_xgi(pdev);
                                ivideo->sisfb_can_post = 1;
-                       } else if((ivideo->chip == XGI_40) && ivideo->haveXGIROM) {
+                       } else if ((ivideo->chip == XGI_40) && ivideo->haveXGIROM) {
                                result = sisfb_post_xgi(pdev);
                                ivideo->sisfb_can_post = 1;
                        } else {
                                printk(KERN_INFO "sisfb: Card is not "
                                        "POSTed and sisfb can't do this either.\n");
                        }
-                       if(!result) {
+                       if (!result) {
                                printk(KERN_ERR "sisfb: Failed to POST card\n");
                                ret = -ENODEV;
                                goto error_3;
index 6a52eba..fce6cfb 100644 (file)
@@ -1719,7 +1719,7 @@ static int sm501fb_init_fb(struct fb_info *fb, enum sm501_controller head,
                enable = 0;
        }
 
-       strlcpy(fb->fix.id, fbname, sizeof(fb->fix.id));
+       strscpy(fb->fix.id, fbname, sizeof(fb->fix.id));
 
        memcpy(&par->ops,
               (head == HEAD_CRT) ? &sm501fb_ops_crt : &sm501fb_ops_pnl,
index 5c76565..52e4ed9 100644 (file)
@@ -450,7 +450,7 @@ static int ssd1307fb_init(struct ssd1307fb_par *par)
        if (ret < 0)
                return ret;
 
-       /* Set Set Area Color Mode ON/OFF & Low Power Display Mode */
+       /* Set Area Color Mode ON/OFF & Low Power Display Mode */
        if (par->area_color_enable || par->low_power) {
                u32 mode;
 
index 27d4b0a..cd4d640 100644 (file)
@@ -1382,7 +1382,7 @@ static int sstfb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                goto fail;
        }
        sst_get_memsize(info, &fix->smem_len);
-       strlcpy(fix->id, spec->name, sizeof(fix->id));
+       strscpy(fix->id, spec->name, sizeof(fix->id));
 
        printk(KERN_INFO "%s (revision %d) with %s dac\n",
                fix->id, par->revision, par->dac_sw.name);
index 15b0795..490bd9a 100644 (file)
@@ -80,7 +80,7 @@ static int gfb_set_fbinfo(struct gfb_info *gp)
        info->pseudo_palette = gp->pseudo_palette;
 
        /* Fill fix common fields */
-       strlcpy(info->fix.id, "gfb", sizeof(info->fix.id));
+       strscpy(info->fix.id, "gfb", sizeof(info->fix.id));
         info->fix.smem_start = gp->fb_base_phys;
         info->fix.smem_len = gp->fb_size;
         info->fix.type = FB_TYPE_PACKED_PIXELS;
index 1d3bacd..1279b02 100644 (file)
@@ -84,7 +84,7 @@ static int s3d_set_fbinfo(struct s3d_info *sp)
        info->pseudo_palette = sp->pseudo_palette;
 
        /* Fill fix common fields */
-       strlcpy(info->fix.id, "s3d", sizeof(info->fix.id));
+       strscpy(info->fix.id, "s3d", sizeof(info->fix.id));
         info->fix.smem_start = sp->fb_base_phys;
         info->fix.smem_len = sp->fb_size;
         info->fix.type = FB_TYPE_PACKED_PIXELS;
index 9daf17b..f7b4636 100644 (file)
@@ -207,7 +207,7 @@ static int e3d_set_fbinfo(struct e3d_info *ep)
        info->pseudo_palette = ep->pseudo_palette;
 
        /* Fill fix common fields */
-       strlcpy(info->fix.id, "e3d", sizeof(info->fix.id));
+       strscpy(info->fix.id, "e3d", sizeof(info->fix.id));
         info->fix.smem_start = ep->fb_base_phys;
         info->fix.smem_len = ep->fb_size;
         info->fix.type = FB_TYPE_PACKED_PIXELS;
index 1638a40..01d87f5 100644 (file)
@@ -333,7 +333,7 @@ tcx_init_fix(struct fb_info *info, int linebytes)
        else
                tcx_name = "TCX24";
 
-       strlcpy(info->fix.id, tcx_name, sizeof(info->fix.id));
+       strscpy(info->fix.id, tcx_name, sizeof(info->fix.id));
 
        info->fix.type = FB_TYPE_PACKED_PIXELS;
        info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
index 67e37a6..8a8122f 100644 (file)
@@ -1264,7 +1264,7 @@ static int tdfxfb_setup_ddc_bus(struct tdfxfb_i2c_chan *chan, const char *name,
 {
        int rc;
 
-       strlcpy(chan->adapter.name, name, sizeof(chan->adapter.name));
+       strscpy(chan->adapter.name, name, sizeof(chan->adapter.name));
        chan->adapter.owner             = THIS_MODULE;
        chan->adapter.class             = I2C_CLASS_DDC;
        chan->adapter.algo_data         = &chan->algo;
@@ -1293,7 +1293,7 @@ static int tdfxfb_setup_i2c_bus(struct tdfxfb_i2c_chan *chan, const char *name,
 {
        int rc;
 
-       strlcpy(chan->adapter.name, name, sizeof(chan->adapter.name));
+       strscpy(chan->adapter.name, name, sizeof(chan->adapter.name));
        chan->adapter.owner             = THIS_MODULE;
        chan->adapter.algo_data         = &chan->algo;
        chan->adapter.dev.parent        = dev;
index ae0cf55..1fff5fd 100644 (file)
@@ -1344,7 +1344,7 @@ tgafb_init_fix(struct fb_info *info)
                memory_size = 16777216;
        }
 
-       strlcpy(info->fix.id, tga_type_name, sizeof(info->fix.id));
+       strscpy(info->fix.id, tga_type_name, sizeof(info->fix.id));
 
        info->fix.type = FB_TYPE_PACKED_PIXELS;
        info->fix.type_aux = 0;
index 319131b..cda0954 100644 (file)
@@ -270,7 +270,7 @@ static int tridentfb_setup_ddc_bus(struct fb_info *info)
 {
        struct tridentfb_par *par = info->par;
 
-       strlcpy(par->ddc_adapter.name, info->fix.id,
+       strscpy(par->ddc_adapter.name, info->fix.id,
                sizeof(par->ddc_adapter.name));
        par->ddc_adapter.owner          = THIS_MODULE;
        par->ddc_adapter.class          = I2C_CLASS_DDC;
index ce91add..dc4d25c 100644 (file)
@@ -17,7 +17,7 @@ config NITRO_ENCLAVES
 
 config NITRO_ENCLAVES_MISC_DEV_TEST
        bool "Tests for the misc device functionality of the Nitro Enclaves" if !KUNIT_ALL_TESTS
-       depends on NITRO_ENCLAVES && KUNIT
+       depends on NITRO_ENCLAVES && KUNIT=y
        default KUNIT_ALL_TESTS
        help
          Enable KUnit tests for the misc device functionality of the Nitro
index c492a57..3ff746e 100644 (file)
@@ -360,7 +360,7 @@ static void vm_synchronize_cbs(struct virtio_device *vdev)
 
 static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, unsigned int index,
                                  void (*callback)(struct virtqueue *vq),
-                                 const char *name, u32 size, bool ctx)
+                                 const char *name, bool ctx)
 {
        struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
        struct virtio_mmio_vq_info *info;
@@ -395,11 +395,8 @@ static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, unsigned int in
                goto error_new_virtqueue;
        }
 
-       if (!size || size > num)
-               size = num;
-
        /* Create the vring */
-       vq = vring_create_virtqueue(index, size, VIRTIO_MMIO_VRING_ALIGN, vdev,
+       vq = vring_create_virtqueue(index, num, VIRTIO_MMIO_VRING_ALIGN, vdev,
                                 true, true, ctx, vm_notify, callback, name);
        if (!vq) {
                err = -ENOMEM;
@@ -477,7 +474,6 @@ static int vm_find_vqs(struct virtio_device *vdev, unsigned int nvqs,
                       struct virtqueue *vqs[],
                       vq_callback_t *callbacks[],
                       const char * const names[],
-                      u32 sizes[],
                       const bool *ctx,
                       struct irq_affinity *desc)
 {
@@ -503,7 +499,6 @@ static int vm_find_vqs(struct virtio_device *vdev, unsigned int nvqs,
                }
 
                vqs[i] = vm_setup_vq(vdev, queue_idx++, callbacks[i], names[i],
-                                    sizes ? sizes[i] : 0,
                                     ctx ? ctx[i] : false);
                if (IS_ERR(vqs[i])) {
                        vm_del_vqs(vdev);
index 00ad476..ad258a9 100644 (file)
@@ -174,7 +174,6 @@ error:
 static struct virtqueue *vp_setup_vq(struct virtio_device *vdev, unsigned int index,
                                     void (*callback)(struct virtqueue *vq),
                                     const char *name,
-                                    u32 size,
                                     bool ctx,
                                     u16 msix_vec)
 {
@@ -187,7 +186,7 @@ static struct virtqueue *vp_setup_vq(struct virtio_device *vdev, unsigned int in
        if (!info)
                return ERR_PTR(-ENOMEM);
 
-       vq = vp_dev->setup_vq(vp_dev, info, index, callback, name, size, ctx,
+       vq = vp_dev->setup_vq(vp_dev, info, index, callback, name, ctx,
                              msix_vec);
        if (IS_ERR(vq))
                goto out_info;
@@ -284,7 +283,7 @@ void vp_del_vqs(struct virtio_device *vdev)
 
 static int vp_find_vqs_msix(struct virtio_device *vdev, unsigned int nvqs,
                struct virtqueue *vqs[], vq_callback_t *callbacks[],
-               const char * const names[], u32 sizes[], bool per_vq_vectors,
+               const char * const names[], bool per_vq_vectors,
                const bool *ctx,
                struct irq_affinity *desc)
 {
@@ -327,8 +326,8 @@ static int vp_find_vqs_msix(struct virtio_device *vdev, unsigned int nvqs,
                else
                        msix_vec = VP_MSIX_VQ_VECTOR;
                vqs[i] = vp_setup_vq(vdev, queue_idx++, callbacks[i], names[i],
-                                    sizes ? sizes[i] : 0,
-                                    ctx ? ctx[i] : false, msix_vec);
+                                    ctx ? ctx[i] : false,
+                                    msix_vec);
                if (IS_ERR(vqs[i])) {
                        err = PTR_ERR(vqs[i]);
                        goto error_find;
@@ -358,7 +357,7 @@ error_find:
 
 static int vp_find_vqs_intx(struct virtio_device *vdev, unsigned int nvqs,
                struct virtqueue *vqs[], vq_callback_t *callbacks[],
-               const char * const names[], u32 sizes[], const bool *ctx)
+               const char * const names[], const bool *ctx)
 {
        struct virtio_pci_device *vp_dev = to_vp_device(vdev);
        int i, err, queue_idx = 0;
@@ -380,7 +379,6 @@ static int vp_find_vqs_intx(struct virtio_device *vdev, unsigned int nvqs,
                        continue;
                }
                vqs[i] = vp_setup_vq(vdev, queue_idx++, callbacks[i], names[i],
-                                    sizes ? sizes[i] : 0,
                                     ctx ? ctx[i] : false,
                                     VIRTIO_MSI_NO_VECTOR);
                if (IS_ERR(vqs[i])) {
@@ -398,21 +396,21 @@ out_del_vqs:
 /* the config->find_vqs() implementation */
 int vp_find_vqs(struct virtio_device *vdev, unsigned int nvqs,
                struct virtqueue *vqs[], vq_callback_t *callbacks[],
-               const char * const names[], u32 sizes[], const bool *ctx,
+               const char * const names[], const bool *ctx,
                struct irq_affinity *desc)
 {
        int err;
 
        /* Try MSI-X with one vector per queue. */
-       err = vp_find_vqs_msix(vdev, nvqs, vqs, callbacks, names, sizes, true, ctx, desc);
+       err = vp_find_vqs_msix(vdev, nvqs, vqs, callbacks, names, true, ctx, desc);
        if (!err)
                return 0;
        /* Fallback: MSI-X with one vector for config, one shared for queues. */
-       err = vp_find_vqs_msix(vdev, nvqs, vqs, callbacks, names, sizes, false, ctx, desc);
+       err = vp_find_vqs_msix(vdev, nvqs, vqs, callbacks, names, false, ctx, desc);
        if (!err)
                return 0;
        /* Finally fall back to regular interrupts. */
-       return vp_find_vqs_intx(vdev, nvqs, vqs, callbacks, names, sizes, ctx);
+       return vp_find_vqs_intx(vdev, nvqs, vqs, callbacks, names, ctx);
 }
 
 const char *vp_bus_name(struct virtio_device *vdev)
index c044837..23112d8 100644 (file)
@@ -80,7 +80,6 @@ struct virtio_pci_device {
                                      unsigned int idx,
                                      void (*callback)(struct virtqueue *vq),
                                      const char *name,
-                                     u32 size,
                                      bool ctx,
                                      u16 msix_vec);
        void (*del_vq)(struct virtio_pci_vq_info *info);
@@ -111,7 +110,7 @@ void vp_del_vqs(struct virtio_device *vdev);
 /* the config->find_vqs() implementation */
 int vp_find_vqs(struct virtio_device *vdev, unsigned int nvqs,
                struct virtqueue *vqs[], vq_callback_t *callbacks[],
-               const char * const names[], u32 sizes[], const bool *ctx,
+               const char * const names[], const bool *ctx,
                struct irq_affinity *desc);
 const char *vp_bus_name(struct virtio_device *vdev);
 
index d75e5c4..2257f1b 100644 (file)
@@ -112,7 +112,6 @@ static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev,
                                  unsigned int index,
                                  void (*callback)(struct virtqueue *vq),
                                  const char *name,
-                                 u32 size,
                                  bool ctx,
                                  u16 msix_vec)
 {
@@ -126,13 +125,10 @@ static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev,
        if (!num || vp_legacy_get_queue_enable(&vp_dev->ldev, index))
                return ERR_PTR(-ENOENT);
 
-       if (!size || size > num)
-               size = num;
-
        info->msix_vector = msix_vec;
 
        /* create the vring */
-       vq = vring_create_virtqueue(index, size,
+       vq = vring_create_virtqueue(index, num,
                                    VIRTIO_PCI_VRING_ALIGN, &vp_dev->vdev,
                                    true, false, ctx,
                                    vp_notify, callback, name);
index f7965c5..c3b9f27 100644 (file)
@@ -293,7 +293,6 @@ static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev,
                                  unsigned int index,
                                  void (*callback)(struct virtqueue *vq),
                                  const char *name,
-                                 u32 size,
                                  bool ctx,
                                  u16 msix_vec)
 {
@@ -311,18 +310,15 @@ static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev,
        if (!num || vp_modern_get_queue_enable(mdev, index))
                return ERR_PTR(-ENOENT);
 
-       if (!size || size > num)
-               size = num;
-
-       if (size & (size - 1)) {
-               dev_warn(&vp_dev->pci_dev->dev, "bad queue size %u", size);
+       if (num & (num - 1)) {
+               dev_warn(&vp_dev->pci_dev->dev, "bad queue size %u", num);
                return ERR_PTR(-EINVAL);
        }
 
        info->msix_vector = msix_vec;
 
        /* create the vring */
-       vq = vring_create_virtqueue(index, size,
+       vq = vring_create_virtqueue(index, num,
                                    SMP_CACHE_BYTES, &vp_dev->vdev,
                                    true, true, ctx,
                                    vp_notify, callback, name);
@@ -351,15 +347,12 @@ err:
 static int vp_modern_find_vqs(struct virtio_device *vdev, unsigned int nvqs,
                              struct virtqueue *vqs[],
                              vq_callback_t *callbacks[],
-                             const char * const names[],
-                             u32 sizes[],
-                             const bool *ctx,
+                             const char * const names[], const bool *ctx,
                              struct irq_affinity *desc)
 {
        struct virtio_pci_device *vp_dev = to_vp_device(vdev);
        struct virtqueue *vq;
-       int rc = vp_find_vqs(vdev, nvqs, vqs, callbacks, names, sizes, ctx,
-                            desc);
+       int rc = vp_find_vqs(vdev, nvqs, vqs, callbacks, names, ctx, desc);
 
        if (rc)
                return rc;
index d66c8e6..4620e9d 100644 (file)
@@ -2426,6 +2426,14 @@ static inline bool more_used(const struct vring_virtqueue *vq)
        return vq->packed_ring ? more_used_packed(vq) : more_used_split(vq);
 }
 
+/**
+ * vring_interrupt - notify a virtqueue on an interrupt
+ * @irq: the IRQ number (ignored)
+ * @_vq: the struct virtqueue to notify
+ *
+ * Calls the callback function of @_vq to process the virtqueue
+ * notification.
+ */
 irqreturn_t vring_interrupt(int irq, void *_vq)
 {
        struct vring_virtqueue *vq = to_vvq(_vq);
index 9bc4d11..9670cc7 100644 (file)
@@ -131,7 +131,7 @@ static irqreturn_t virtio_vdpa_virtqueue_cb(void *private)
 static struct virtqueue *
 virtio_vdpa_setup_vq(struct virtio_device *vdev, unsigned int index,
                     void (*callback)(struct virtqueue *vq),
-                    const char *name, u32 size, bool ctx)
+                    const char *name, bool ctx)
 {
        struct virtio_vdpa_device *vd_dev = to_virtio_vdpa_device(vdev);
        struct vdpa_device *vdpa = vd_get_vdpa(vdev);
@@ -168,17 +168,14 @@ virtio_vdpa_setup_vq(struct virtio_device *vdev, unsigned int index,
                goto error_new_virtqueue;
        }
 
-       if (!size || size > max_num)
-               size = max_num;
-
        if (ops->get_vq_num_min)
                min_num = ops->get_vq_num_min(vdpa);
 
-       may_reduce_num = (size == min_num) ? false : true;
+       may_reduce_num = (max_num == min_num) ? false : true;
 
        /* Create the vring */
        align = ops->get_vq_align(vdpa);
-       vq = vring_create_virtqueue(index, size, align, vdev,
+       vq = vring_create_virtqueue(index, max_num, align, vdev,
                                    true, may_reduce_num, ctx,
                                    virtio_vdpa_notify, callback, name);
        if (!vq) {
@@ -272,7 +269,6 @@ static int virtio_vdpa_find_vqs(struct virtio_device *vdev, unsigned int nvqs,
                                struct virtqueue *vqs[],
                                vq_callback_t *callbacks[],
                                const char * const names[],
-                               u32 sizes[],
                                const bool *ctx,
                                struct irq_affinity *desc)
 {
@@ -288,9 +284,9 @@ static int virtio_vdpa_find_vqs(struct virtio_device *vdev, unsigned int nvqs,
                        continue;
                }
 
-               vqs[i] = virtio_vdpa_setup_vq(vdev, queue_idx++, callbacks[i],
-                                                 names[i], sizes ? sizes[i] : 0,
-                                                 ctx ? ctx[i] : false);
+               vqs[i] = virtio_vdpa_setup_vq(vdev, queue_idx++,
+                                             callbacks[i], names[i], ctx ?
+                                             ctx[i] : false);
                if (IS_ERR(vqs[i])) {
                        err = PTR_ERR(vqs[i]);
                        goto err_setup_vq;
index 738029d..e1ec725 100644 (file)
@@ -1047,6 +1047,9 @@ int gnttab_dma_alloc_pages(struct gnttab_dma_alloc_args *args)
        size_t size;
        int i, ret;
 
+       if (args->nr_pages < 0 || args->nr_pages > (INT_MAX >> PAGE_SHIFT))
+               return -ENOMEM;
+
        size = args->nr_pages << PAGE_SHIFT;
        if (args->coherent)
                args->vaddr = dma_alloc_coherent(args->dev, size,
index 3369734..e88e8f6 100644 (file)
@@ -581,27 +581,30 @@ static int lock_pages(
        struct privcmd_dm_op_buf kbufs[], unsigned int num,
        struct page *pages[], unsigned int nr_pages, unsigned int *pinned)
 {
-       unsigned int i;
+       unsigned int i, off = 0;
 
-       for (i = 0; i < num; i++) {
+       for (i = 0; i < num; ) {
                unsigned int requested;
                int page_count;
 
                requested = DIV_ROUND_UP(
                        offset_in_page(kbufs[i].uptr) + kbufs[i].size,
-                       PAGE_SIZE);
+                       PAGE_SIZE) - off;
                if (requested > nr_pages)
                        return -ENOSPC;
 
                page_count = pin_user_pages_fast(
-                       (unsigned long) kbufs[i].uptr,
+                       (unsigned long)kbufs[i].uptr + off * PAGE_SIZE,
                        requested, FOLL_WRITE, pages);
-               if (page_count < 0)
-                       return page_count;
+               if (page_count <= 0)
+                       return page_count ? : -EFAULT;
 
                *pinned += page_count;
                nr_pages -= page_count;
                pages += page_count;
+
+               off = (requested == page_count) ? 0 : off + page_count;
+               i += !off;
        }
 
        return 0;
@@ -677,10 +680,8 @@ static long privcmd_ioctl_dm_op(struct file *file, void __user *udata)
        }
 
        rc = lock_pages(kbufs, kdata.num, pages, nr_pages, &pinned);
-       if (rc < 0) {
-               nr_pages = pinned;
+       if (rc < 0)
                goto out;
-       }
 
        for (i = 0; i < kdata.num; i++) {
                set_xen_guest_handle(xbufs[i].h, kbufs[i].uptr);
@@ -692,7 +693,7 @@ static long privcmd_ioctl_dm_op(struct file *file, void __user *udata)
        xen_preemptible_hcall_end();
 
 out:
-       unlock_pages(pages, nr_pages);
+       unlock_pages(pages, pinned);
        kfree(xbufs);
        kfree(pages);
        kfree(kbufs);
index 7a0c93a..d3dcda3 100644 (file)
@@ -1121,7 +1121,7 @@ static void scsiback_do_1lun_hotplug(struct vscsibk_info *info, int op,
                                "%s: writing %s", __func__, state);
                return;
        }
-       strlcpy(phy, val, VSCSI_NAMELEN);
+       strscpy(phy, val, VSCSI_NAMELEN);
        kfree(val);
 
        /* virtual SCSI device */
index 07b010a..f44d5a6 100644 (file)
@@ -40,7 +40,7 @@ static int frontend_bus_id(char bus_id[XEN_BUS_ID_SIZE], const char *nodename)
                return -EINVAL;
        }
 
-       strlcpy(bus_id, nodename + 1, XEN_BUS_ID_SIZE);
+       strscpy(bus_id, nodename + 1, XEN_BUS_ID_SIZE);
        if (!strchr(bus_id, '/')) {
                pr_warn("bus_id %s no slash\n", bus_id);
                return -EINVAL;
index c4210a3..bbcc5af 100644 (file)
@@ -76,7 +76,7 @@ void afs_lock_op_done(struct afs_call *call)
        if (call->error == 0) {
                spin_lock(&vnode->lock);
                trace_afs_flock_ev(vnode, NULL, afs_flock_timestamp, 0);
-               vnode->locked_at = call->reply_time;
+               vnode->locked_at = call->issue_time;
                afs_schedule_lock_extension(vnode);
                spin_unlock(&vnode->lock);
        }
index 4943413..7d37f63 100644 (file)
@@ -131,7 +131,7 @@ bad:
 
 static time64_t xdr_decode_expiry(struct afs_call *call, u32 expiry)
 {
-       return ktime_divns(call->reply_time, NSEC_PER_SEC) + expiry;
+       return ktime_divns(call->issue_time, NSEC_PER_SEC) + expiry;
 }
 
 static void xdr_decode_AFSCallBack(const __be32 **_bp,
index 64ad554..723d162 100644 (file)
@@ -137,7 +137,6 @@ struct afs_call {
        bool                    need_attention; /* T if RxRPC poked us */
        bool                    async;          /* T if asynchronous */
        bool                    upgrade;        /* T to request service upgrade */
-       bool                    have_reply_time; /* T if have got reply_time */
        bool                    intr;           /* T if interruptible */
        bool                    unmarshalling_error; /* T if an unmarshalling error occurred */
        u16                     service_id;     /* Actual service ID (after upgrade) */
@@ -151,7 +150,7 @@ struct afs_call {
                } __attribute__((packed));
                __be64          tmp64;
        };
-       ktime_t                 reply_time;     /* Time of first reply packet */
+       ktime_t                 issue_time;     /* Time of issue of operation */
 };
 
 struct afs_call_type {
index 933e67f..805328c 100644 (file)
@@ -69,6 +69,7 @@ int afs_abort_to_error(u32 abort_code)
                /* Unified AFS error table */
        case UAEPERM:                   return -EPERM;
        case UAENOENT:                  return -ENOENT;
+       case UAEAGAIN:                  return -EAGAIN;
        case UAEACCES:                  return -EACCES;
        case UAEBUSY:                   return -EBUSY;
        case UAEEXIST:                  return -EEXIST;
index d5c4785..eccc3cd 100644 (file)
@@ -351,6 +351,7 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp)
        if (call->max_lifespan)
                rxrpc_kernel_set_max_life(call->net->socket, rxcall,
                                          call->max_lifespan);
+       call->issue_time = ktime_get_real();
 
        /* send the request */
        iov[0].iov_base = call->request;
@@ -501,12 +502,6 @@ static void afs_deliver_to_call(struct afs_call *call)
                        return;
                }
 
-               if (!call->have_reply_time &&
-                   rxrpc_kernel_get_reply_time(call->net->socket,
-                                               call->rxcall,
-                                               &call->reply_time))
-                       call->have_reply_time = true;
-
                ret = call->type->deliver(call);
                state = READ_ONCE(call->state);
                if (ret == 0 && call->unmarshalling_error)
index fdc7d67..11571cc 100644 (file)
@@ -232,8 +232,7 @@ static void xdr_decode_YFSCallBack(const __be32 **_bp,
        struct afs_callback *cb = &scb->callback;
        ktime_t cb_expiry;
 
-       cb_expiry = call->reply_time;
-       cb_expiry = ktime_add(cb_expiry, xdr_to_u64(x->expiration_time) * 100);
+       cb_expiry = ktime_add(call->issue_time, xdr_to_u64(x->expiration_time) * 100);
        cb->expires_at  = ktime_divns(cb_expiry, NSEC_PER_SEC);
        scb->have_cb    = true;
        *_bp += xdr_size(x);
index c3aecfb..e0375ba 100644 (file)
@@ -440,39 +440,26 @@ void btrfs_wait_block_group_cache_progress(struct btrfs_block_group *cache,
        btrfs_put_caching_control(caching_ctl);
 }
 
-int btrfs_wait_block_group_cache_done(struct btrfs_block_group *cache)
+static int btrfs_caching_ctl_wait_done(struct btrfs_block_group *cache,
+                                      struct btrfs_caching_control *caching_ctl)
+{
+       wait_event(caching_ctl->wait, btrfs_block_group_done(cache));
+       return cache->cached == BTRFS_CACHE_ERROR ? -EIO : 0;
+}
+
+static int btrfs_wait_block_group_cache_done(struct btrfs_block_group *cache)
 {
        struct btrfs_caching_control *caching_ctl;
-       int ret = 0;
+       int ret;
 
        caching_ctl = btrfs_get_caching_control(cache);
        if (!caching_ctl)
                return (cache->cached == BTRFS_CACHE_ERROR) ? -EIO : 0;
-
-       wait_event(caching_ctl->wait, btrfs_block_group_done(cache));
-       if (cache->cached == BTRFS_CACHE_ERROR)
-               ret = -EIO;
+       ret = btrfs_caching_ctl_wait_done(cache, caching_ctl);
        btrfs_put_caching_control(caching_ctl);
        return ret;
 }
 
-static bool space_cache_v1_done(struct btrfs_block_group *cache)
-{
-       bool ret;
-
-       spin_lock(&cache->lock);
-       ret = cache->cached != BTRFS_CACHE_FAST;
-       spin_unlock(&cache->lock);
-
-       return ret;
-}
-
-void btrfs_wait_space_cache_v1_finished(struct btrfs_block_group *cache,
-                               struct btrfs_caching_control *caching_ctl)
-{
-       wait_event(caching_ctl->wait, space_cache_v1_done(cache));
-}
-
 #ifdef CONFIG_BTRFS_DEBUG
 static void fragment_free_space(struct btrfs_block_group *block_group)
 {
@@ -750,9 +737,8 @@ done:
        btrfs_put_block_group(block_group);
 }
 
-int btrfs_cache_block_group(struct btrfs_block_group *cache, int load_cache_only)
+int btrfs_cache_block_group(struct btrfs_block_group *cache, bool wait)
 {
-       DEFINE_WAIT(wait);
        struct btrfs_fs_info *fs_info = cache->fs_info;
        struct btrfs_caching_control *caching_ctl = NULL;
        int ret = 0;
@@ -785,10 +771,7 @@ int btrfs_cache_block_group(struct btrfs_block_group *cache, int load_cache_only
        }
        WARN_ON(cache->caching_ctl);
        cache->caching_ctl = caching_ctl;
-       if (btrfs_test_opt(fs_info, SPACE_CACHE))
-               cache->cached = BTRFS_CACHE_FAST;
-       else
-               cache->cached = BTRFS_CACHE_STARTED;
+       cache->cached = BTRFS_CACHE_STARTED;
        cache->has_caching_ctl = 1;
        spin_unlock(&cache->lock);
 
@@ -801,8 +784,8 @@ int btrfs_cache_block_group(struct btrfs_block_group *cache, int load_cache_only
 
        btrfs_queue_work(fs_info->caching_workers, &caching_ctl->work);
 out:
-       if (load_cache_only && caching_ctl)
-               btrfs_wait_space_cache_v1_finished(cache, caching_ctl);
+       if (wait && caching_ctl)
+               ret = btrfs_caching_ctl_wait_done(cache, caching_ctl);
        if (caching_ctl)
                btrfs_put_caching_control(caching_ctl);
 
@@ -1640,9 +1623,11 @@ void btrfs_reclaim_bgs_work(struct work_struct *work)
                                div64_u64(zone_unusable * 100, bg->length));
                trace_btrfs_reclaim_block_group(bg);
                ret = btrfs_relocate_chunk(fs_info, bg->start);
-               if (ret)
+               if (ret) {
+                       btrfs_dec_block_group_ro(bg);
                        btrfs_err(fs_info, "error relocating chunk %llu",
                                  bg->start);
+               }
 
 next:
                btrfs_put_block_group(bg);
@@ -3310,7 +3295,7 @@ int btrfs_update_block_group(struct btrfs_trans_handle *trans,
                 * space back to the block group, otherwise we will leak space.
                 */
                if (!alloc && !btrfs_block_group_done(cache))
-                       btrfs_cache_block_group(cache, 1);
+                       btrfs_cache_block_group(cache, true);
 
                byte_in_group = bytenr - cache->start;
                WARN_ON(byte_in_group > cache->length);
index 35e0e86..6b3cdc4 100644 (file)
@@ -263,9 +263,7 @@ void btrfs_dec_nocow_writers(struct btrfs_block_group *bg);
 void btrfs_wait_nocow_writers(struct btrfs_block_group *bg);
 void btrfs_wait_block_group_cache_progress(struct btrfs_block_group *cache,
                                           u64 num_bytes);
-int btrfs_wait_block_group_cache_done(struct btrfs_block_group *cache);
-int btrfs_cache_block_group(struct btrfs_block_group *cache,
-                           int load_cache_only);
+int btrfs_cache_block_group(struct btrfs_block_group *cache, bool wait);
 void btrfs_put_caching_control(struct btrfs_caching_control *ctl);
 struct btrfs_caching_control *btrfs_get_caching_control(
                struct btrfs_block_group *cache);
index 6e55603..ebfa35f 100644 (file)
@@ -2075,6 +2075,9 @@ cow_done:
 
                if (!p->skip_locking) {
                        level = btrfs_header_level(b);
+
+                       btrfs_maybe_reset_lockdep_class(root, b);
+
                        if (level <= write_lock_level) {
                                btrfs_tree_lock(b);
                                p->locks[level] = BTRFS_WRITE_LOCK;
index 4db85b9..df8c99c 100644 (file)
@@ -505,7 +505,6 @@ struct btrfs_free_cluster {
 enum btrfs_caching_type {
        BTRFS_CACHE_NO,
        BTRFS_CACHE_STARTED,
-       BTRFS_CACHE_FAST,
        BTRFS_CACHE_FINISHED,
        BTRFS_CACHE_ERROR,
 };
@@ -1089,8 +1088,6 @@ struct btrfs_fs_info {
 
        spinlock_t zone_active_bgs_lock;
        struct list_head zone_active_bgs;
-       /* Waiters when BTRFS_FS_NEED_ZONE_FINISH is set */
-       wait_queue_head_t zone_finish_wait;
 
        /* Updates are not protected by any lock */
        struct btrfs_commit_stats commit_stats;
@@ -1173,6 +1170,8 @@ enum {
        BTRFS_ROOT_ORPHAN_CLEANUP,
        /* This root has a drop operation that was started previously. */
        BTRFS_ROOT_UNFINISHED_DROP,
+       /* This reloc root needs to have its buffers lockdep class reset. */
+       BTRFS_ROOT_RESET_LOCKDEP_CLASS,
 };
 
 static inline void btrfs_wake_unfinished_drop(struct btrfs_fs_info *fs_info)
index f43196a..41cddd3 100644 (file)
@@ -165,7 +165,7 @@ no_valid_dev_replace_entry_found:
                 */
                if (btrfs_find_device(fs_info->fs_devices, &args)) {
                        btrfs_err(fs_info,
-                       "replace devid present without an active replace item");
+"replace without active item, run 'device scan --forget' on the target device");
                        ret = -EUCLEAN;
                } else {
                        dev_replace->srcdev = NULL;
@@ -1129,8 +1129,7 @@ int btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info)
                up_write(&dev_replace->rwsem);
 
                /* Scrub for replace must not be running in suspended state */
-               ret = btrfs_scrub_cancel(fs_info);
-               ASSERT(ret != -ENOTCONN);
+               btrfs_scrub_cancel(fs_info);
 
                trans = btrfs_start_transaction(root, 0);
                if (IS_ERR(trans)) {
index 4c3166f..2633137 100644 (file)
@@ -87,88 +87,6 @@ struct async_submit_bio {
 };
 
 /*
- * Lockdep class keys for extent_buffer->lock's in this root.  For a given
- * eb, the lockdep key is determined by the btrfs_root it belongs to and
- * the level the eb occupies in the tree.
- *
- * Different roots are used for different purposes and may nest inside each
- * other and they require separate keysets.  As lockdep keys should be
- * static, assign keysets according to the purpose of the root as indicated
- * by btrfs_root->root_key.objectid.  This ensures that all special purpose
- * roots have separate keysets.
- *
- * Lock-nesting across peer nodes is always done with the immediate parent
- * node locked thus preventing deadlock.  As lockdep doesn't know this, use
- * subclass to avoid triggering lockdep warning in such cases.
- *
- * The key is set by the readpage_end_io_hook after the buffer has passed
- * csum validation but before the pages are unlocked.  It is also set by
- * btrfs_init_new_buffer on freshly allocated blocks.
- *
- * We also add a check to make sure the highest level of the tree is the
- * same as our lockdep setup here.  If BTRFS_MAX_LEVEL changes, this code
- * needs update as well.
- */
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-# if BTRFS_MAX_LEVEL != 8
-#  error
-# endif
-
-#define DEFINE_LEVEL(stem, level)                                      \
-       .names[level] = "btrfs-" stem "-0" #level,
-
-#define DEFINE_NAME(stem)                                              \
-       DEFINE_LEVEL(stem, 0)                                           \
-       DEFINE_LEVEL(stem, 1)                                           \
-       DEFINE_LEVEL(stem, 2)                                           \
-       DEFINE_LEVEL(stem, 3)                                           \
-       DEFINE_LEVEL(stem, 4)                                           \
-       DEFINE_LEVEL(stem, 5)                                           \
-       DEFINE_LEVEL(stem, 6)                                           \
-       DEFINE_LEVEL(stem, 7)
-
-static struct btrfs_lockdep_keyset {
-       u64                     id;             /* root objectid */
-       /* Longest entry: btrfs-free-space-00 */
-       char                    names[BTRFS_MAX_LEVEL][20];
-       struct lock_class_key   keys[BTRFS_MAX_LEVEL];
-} btrfs_lockdep_keysets[] = {
-       { .id = BTRFS_ROOT_TREE_OBJECTID,       DEFINE_NAME("root")     },
-       { .id = BTRFS_EXTENT_TREE_OBJECTID,     DEFINE_NAME("extent")   },
-       { .id = BTRFS_CHUNK_TREE_OBJECTID,      DEFINE_NAME("chunk")    },
-       { .id = BTRFS_DEV_TREE_OBJECTID,        DEFINE_NAME("dev")      },
-       { .id = BTRFS_CSUM_TREE_OBJECTID,       DEFINE_NAME("csum")     },
-       { .id = BTRFS_QUOTA_TREE_OBJECTID,      DEFINE_NAME("quota")    },
-       { .id = BTRFS_TREE_LOG_OBJECTID,        DEFINE_NAME("log")      },
-       { .id = BTRFS_TREE_RELOC_OBJECTID,      DEFINE_NAME("treloc")   },
-       { .id = BTRFS_DATA_RELOC_TREE_OBJECTID, DEFINE_NAME("dreloc")   },
-       { .id = BTRFS_UUID_TREE_OBJECTID,       DEFINE_NAME("uuid")     },
-       { .id = BTRFS_FREE_SPACE_TREE_OBJECTID, DEFINE_NAME("free-space") },
-       { .id = 0,                              DEFINE_NAME("tree")     },
-};
-
-#undef DEFINE_LEVEL
-#undef DEFINE_NAME
-
-void btrfs_set_buffer_lockdep_class(u64 objectid, struct extent_buffer *eb,
-                                   int level)
-{
-       struct btrfs_lockdep_keyset *ks;
-
-       BUG_ON(level >= ARRAY_SIZE(ks->keys));
-
-       /* find the matching keyset, id 0 is the default entry */
-       for (ks = btrfs_lockdep_keysets; ks->id; ks++)
-               if (ks->id == objectid)
-                       break;
-
-       lockdep_set_class_and_name(&eb->lock,
-                                  &ks->keys[level], ks->names[level]);
-}
-
-#endif
-
-/*
  * Compute the csum of a btree block and store the result to provided buffer.
  */
 static void csum_tree_block(struct extent_buffer *buf, u8 *result)
@@ -3150,7 +3068,6 @@ void btrfs_init_fs_info(struct btrfs_fs_info *fs_info)
        init_waitqueue_head(&fs_info->transaction_blocked_wait);
        init_waitqueue_head(&fs_info->async_submit_wait);
        init_waitqueue_head(&fs_info->delayed_iputs_wait);
-       init_waitqueue_head(&fs_info->zone_finish_wait);
 
        /* Usable values until the real ones are cached from the superblock */
        fs_info->nodesize = 4096;
@@ -4558,6 +4475,17 @@ void __cold close_ctree(struct btrfs_fs_info *fs_info)
        set_bit(BTRFS_FS_CLOSING_START, &fs_info->flags);
 
        /*
+        * If we had UNFINISHED_DROPS we could still be processing them, so
+        * clear that bit and wake up relocation so it can stop.
+        * We must do this before stopping the block group reclaim task, because
+        * at btrfs_relocate_block_group() we wait for this bit, and after the
+        * wait we stop with -EINTR if btrfs_fs_closing() returns non-zero - we
+        * have just set BTRFS_FS_CLOSING_START, so btrfs_fs_closing() will
+        * return 1.
+        */
+       btrfs_wake_unfinished_drop(fs_info);
+
+       /*
         * We may have the reclaim task running and relocating a data block group,
         * in which case it may create delayed iputs. So stop it before we park
         * the cleaner kthread otherwise we can get new delayed iputs after
@@ -4575,12 +4503,6 @@ void __cold close_ctree(struct btrfs_fs_info *fs_info)
         */
        kthread_park(fs_info->cleaner_kthread);
 
-       /*
-        * If we had UNFINISHED_DROPS we could still be processing them, so
-        * clear that bit and wake up relocation so it can stop.
-        */
-       btrfs_wake_unfinished_drop(fs_info);
-
        /* wait for the qgroup rescan worker to stop */
        btrfs_qgroup_wait_for_completion(fs_info, false);
 
@@ -4603,6 +4525,31 @@ void __cold close_ctree(struct btrfs_fs_info *fs_info)
        /* clear out the rbtree of defraggable inodes */
        btrfs_cleanup_defrag_inodes(fs_info);
 
+       /*
+        * After we parked the cleaner kthread, ordered extents may have
+        * completed and created new delayed iputs. If one of the async reclaim
+        * tasks is running and in the RUN_DELAYED_IPUTS flush state, then we
+        * can hang forever trying to stop it, because if a delayed iput is
+        * added after it ran btrfs_run_delayed_iputs() and before it called
+        * btrfs_wait_on_delayed_iputs(), it will hang forever since there is
+        * no one else to run iputs.
+        *
+        * So wait for all ongoing ordered extents to complete and then run
+        * delayed iputs. This works because once we reach this point no one
+        * can either create new ordered extents nor create delayed iputs
+        * through some other means.
+        *
+        * Also note that btrfs_wait_ordered_roots() is not safe here, because
+        * it waits for BTRFS_ORDERED_COMPLETE to be set on an ordered extent,
+        * but the delayed iput for the respective inode is made only when doing
+        * the final btrfs_put_ordered_extent() (which must happen at
+        * btrfs_finish_ordered_io() when we are unmounting).
+        */
+       btrfs_flush_workqueue(fs_info->endio_write_workers);
+       /* Ordered extents for free space inodes. */
+       btrfs_flush_workqueue(fs_info->endio_freespace_worker);
+       btrfs_run_delayed_iputs(fs_info);
+
        cancel_work_sync(&fs_info->async_reclaim_work);
        cancel_work_sync(&fs_info->async_data_reclaim_work);
        cancel_work_sync(&fs_info->preempt_reclaim_work);
index 8993b42..47ad8e0 100644 (file)
@@ -137,14 +137,4 @@ int btrfs_get_num_tolerated_disk_barrier_failures(u64 flags);
 int btrfs_get_free_objectid(struct btrfs_root *root, u64 *objectid);
 int btrfs_init_root_free_objectid(struct btrfs_root *root);
 
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-void btrfs_set_buffer_lockdep_class(u64 objectid,
-                                   struct extent_buffer *eb, int level);
-#else
-static inline void btrfs_set_buffer_lockdep_class(u64 objectid,
-                                       struct extent_buffer *eb, int level)
-{
-}
-#endif
-
 #endif
index ea3ec1e..6914cd8 100644 (file)
@@ -2551,17 +2551,10 @@ int btrfs_pin_extent_for_log_replay(struct btrfs_trans_handle *trans,
                return -EINVAL;
 
        /*
-        * pull in the free space cache (if any) so that our pin
-        * removes the free space from the cache.  We have load_only set
-        * to one because the slow code to read in the free extents does check
-        * the pinned extents.
+        * Fully cache the free space first so that our pin removes the free space
+        * from the cache.
         */
-       btrfs_cache_block_group(cache, 1);
-       /*
-        * Make sure we wait until the cache is completely built in case it is
-        * missing or is invalid and therefore needs to be rebuilt.
-        */
-       ret = btrfs_wait_block_group_cache_done(cache);
+       ret = btrfs_cache_block_group(cache, true);
        if (ret)
                goto out;
 
@@ -2584,12 +2577,7 @@ static int __exclude_logged_extent(struct btrfs_fs_info *fs_info,
        if (!block_group)
                return -EINVAL;
 
-       btrfs_cache_block_group(block_group, 1);
-       /*
-        * Make sure we wait until the cache is completely built in case it is
-        * missing or is invalid and therefore needs to be rebuilt.
-        */
-       ret = btrfs_wait_block_group_cache_done(block_group);
+       ret = btrfs_cache_block_group(block_group, true);
        if (ret)
                goto out;
 
@@ -4399,7 +4387,7 @@ have_block_group:
                ffe_ctl->cached = btrfs_block_group_done(block_group);
                if (unlikely(!ffe_ctl->cached)) {
                        ffe_ctl->have_caching_bg = true;
-                       ret = btrfs_cache_block_group(block_group, 0);
+                       ret = btrfs_cache_block_group(block_group, false);
 
                        /*
                         * If we get ENOMEM here or something else we want to
@@ -4867,6 +4855,7 @@ btrfs_init_new_buffer(struct btrfs_trans_handle *trans, struct btrfs_root *root,
 {
        struct btrfs_fs_info *fs_info = root->fs_info;
        struct extent_buffer *buf;
+       u64 lockdep_owner = owner;
 
        buf = btrfs_find_create_tree_block(fs_info, bytenr, owner, level);
        if (IS_ERR(buf))
@@ -4886,11 +4875,26 @@ btrfs_init_new_buffer(struct btrfs_trans_handle *trans, struct btrfs_root *root,
        }
 
        /*
+        * The reloc trees are just snapshots, so we need them to appear to be
+        * just like any other fs tree WRT lockdep.
+        *
+        * The exception however is in replace_path() in relocation, where we
+        * hold the lock on the original fs root and then search for the reloc
+        * root.  At that point we need to make sure any reloc root buffers are
+        * set to the BTRFS_TREE_RELOC_OBJECTID lockdep class in order to make
+        * lockdep happy.
+        */
+       if (lockdep_owner == BTRFS_TREE_RELOC_OBJECTID &&
+           !test_bit(BTRFS_ROOT_RESET_LOCKDEP_CLASS, &root->state))
+               lockdep_owner = BTRFS_FS_TREE_OBJECTID;
+
+       /*
         * This needs to stay, because we could allocate a freed block from an
         * old tree into a new tree, so we need to make sure this new block is
         * set to the appropriate level and owner.
         */
-       btrfs_set_buffer_lockdep_class(owner, buf, level);
+       btrfs_set_buffer_lockdep_class(lockdep_owner, buf, level);
+
        __btrfs_tree_lock(buf, nest);
        btrfs_clean_tree_block(buf);
        clear_bit(EXTENT_BUFFER_STALE, &buf->bflags);
@@ -6153,13 +6157,7 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range)
 
                if (end - start >= range->minlen) {
                        if (!btrfs_block_group_done(cache)) {
-                               ret = btrfs_cache_block_group(cache, 0);
-                               if (ret) {
-                                       bg_failed++;
-                                       bg_ret = ret;
-                                       continue;
-                               }
-                               ret = btrfs_wait_block_group_cache_done(cache);
+                               ret = btrfs_cache_block_group(cache, true);
                                if (ret) {
                                        bg_failed++;
                                        bg_ret = ret;
index bfae67c..cf4f19e 100644 (file)
@@ -3233,7 +3233,7 @@ static int btrfs_bio_add_page(struct btrfs_bio_ctrl *bio_ctrl,
        u32 bio_size = bio->bi_iter.bi_size;
        u32 real_size;
        const sector_t sector = disk_bytenr >> SECTOR_SHIFT;
-       bool contig;
+       bool contig = false;
        int ret;
 
        ASSERT(bio);
@@ -3242,10 +3242,35 @@ static int btrfs_bio_add_page(struct btrfs_bio_ctrl *bio_ctrl,
        if (bio_ctrl->compress_type != compress_type)
                return 0;
 
-       if (bio_ctrl->compress_type != BTRFS_COMPRESS_NONE)
+
+       if (bio->bi_iter.bi_size == 0) {
+               /* We can always add a page into an empty bio. */
+               contig = true;
+       } else if (bio_ctrl->compress_type == BTRFS_COMPRESS_NONE) {
+               struct bio_vec *bvec = bio_last_bvec_all(bio);
+
+               /*
+                * The contig check requires the following conditions to be met:
+                * 1) The pages are belonging to the same inode
+                *    This is implied by the call chain.
+                *
+                * 2) The range has adjacent logical bytenr
+                *
+                * 3) The range has adjacent file offset
+                *    This is required for the usage of btrfs_bio->file_offset.
+                */
+               if (bio_end_sector(bio) == sector &&
+                   page_offset(bvec->bv_page) + bvec->bv_offset +
+                   bvec->bv_len == page_offset(page) + pg_offset)
+                       contig = true;
+       } else {
+               /*
+                * For compression, all IO should have its logical bytenr
+                * set to the starting bytenr of the compressed extent.
+                */
                contig = bio->bi_iter.bi_sector == sector;
-       else
-               contig = bio_end_sector(bio) == sector;
+       }
+
        if (!contig)
                return 0;
 
@@ -6140,6 +6165,7 @@ struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info,
        struct extent_buffer *exists = NULL;
        struct page *p;
        struct address_space *mapping = fs_info->btree_inode->i_mapping;
+       u64 lockdep_owner = owner_root;
        int uptodate = 1;
        int ret;
 
@@ -6164,7 +6190,15 @@ struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info,
        eb = __alloc_extent_buffer(fs_info, start, len);
        if (!eb)
                return ERR_PTR(-ENOMEM);
-       btrfs_set_buffer_lockdep_class(owner_root, eb, level);
+
+       /*
+        * The reloc trees are just snapshots, so we need them to appear to be
+        * just like any other fs tree WRT lockdep.
+        */
+       if (lockdep_owner == BTRFS_TREE_RELOC_OBJECTID)
+               lockdep_owner = BTRFS_FS_TREE_OBJECTID;
+
+       btrfs_set_buffer_lockdep_class(lockdep_owner, eb, level);
 
        num_pages = num_extent_pages(eb);
        for (i = 0; i < num_pages; i++, index++) {
index 66c8221..5a3f6e0 100644 (file)
@@ -2482,6 +2482,7 @@ static int fill_holes(struct btrfs_trans_handle *trans,
                btrfs_set_file_extent_num_bytes(leaf, fi, num_bytes);
                btrfs_set_file_extent_ram_bytes(leaf, fi, num_bytes);
                btrfs_set_file_extent_offset(leaf, fi, 0);
+               btrfs_set_file_extent_generation(leaf, fi, trans->transid);
                btrfs_mark_buffer_dirty(leaf);
                goto out;
        }
@@ -2498,6 +2499,7 @@ static int fill_holes(struct btrfs_trans_handle *trans,
                btrfs_set_file_extent_num_bytes(leaf, fi, num_bytes);
                btrfs_set_file_extent_ram_bytes(leaf, fi, num_bytes);
                btrfs_set_file_extent_offset(leaf, fi, 0);
+               btrfs_set_file_extent_generation(leaf, fi, trans->transid);
                btrfs_mark_buffer_dirty(leaf);
                goto out;
        }
index f0c97d2..1372210 100644 (file)
@@ -1644,10 +1644,9 @@ static noinline int run_delalloc_zoned(struct btrfs_inode *inode,
                        done_offset = end;
 
                if (done_offset == start) {
-                       struct btrfs_fs_info *info = inode->root->fs_info;
-
-                       wait_var_event(&info->zone_finish_wait,
-                                      !test_bit(BTRFS_FS_NEED_ZONE_FINISH, &info->flags));
+                       wait_on_bit_io(&inode->root->fs_info->flags,
+                                      BTRFS_FS_NEED_ZONE_FINISH,
+                                      TASK_UNINTERRUPTIBLE);
                        continue;
                }
 
@@ -7694,6 +7693,20 @@ static int btrfs_dio_iomap_begin(struct inode *inode, loff_t start,
        bool unlock_extents = false;
 
        /*
+        * We could potentially fault if we have a buffer > PAGE_SIZE, and if
+        * we're NOWAIT we may submit a bio for a partial range and return
+        * EIOCBQUEUED, which would result in an errant short read.
+        *
+        * The best way to handle this would be to allow for partial completions
+        * of iocb's, so we could submit the partial bio, return and fault in
+        * the rest of the pages, and then submit the io for the rest of the
+        * range.  However we don't have that currently, so simply return
+        * -EAGAIN at this point so that the normal path is used.
+        */
+       if (!write && (flags & IOMAP_NOWAIT) && length > PAGE_SIZE)
+               return -EAGAIN;
+
+       /*
         * Cap the size of reads to that usually seen in buffered I/O as we need
         * to allocate a contiguous array for the checksums.
         */
index 33461b4..9063072 100644 (file)
 #include "locking.h"
 
 /*
+ * Lockdep class keys for extent_buffer->lock's in this root.  For a given
+ * eb, the lockdep key is determined by the btrfs_root it belongs to and
+ * the level the eb occupies in the tree.
+ *
+ * Different roots are used for different purposes and may nest inside each
+ * other and they require separate keysets.  As lockdep keys should be
+ * static, assign keysets according to the purpose of the root as indicated
+ * by btrfs_root->root_key.objectid.  This ensures that all special purpose
+ * roots have separate keysets.
+ *
+ * Lock-nesting across peer nodes is always done with the immediate parent
+ * node locked thus preventing deadlock.  As lockdep doesn't know this, use
+ * subclass to avoid triggering lockdep warning in such cases.
+ *
+ * The key is set by the readpage_end_io_hook after the buffer has passed
+ * csum validation but before the pages are unlocked.  It is also set by
+ * btrfs_init_new_buffer on freshly allocated blocks.
+ *
+ * We also add a check to make sure the highest level of the tree is the
+ * same as our lockdep setup here.  If BTRFS_MAX_LEVEL changes, this code
+ * needs update as well.
+ */
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+#if BTRFS_MAX_LEVEL != 8
+#error
+#endif
+
+#define DEFINE_LEVEL(stem, level)                                      \
+       .names[level] = "btrfs-" stem "-0" #level,
+
+#define DEFINE_NAME(stem)                                              \
+       DEFINE_LEVEL(stem, 0)                                           \
+       DEFINE_LEVEL(stem, 1)                                           \
+       DEFINE_LEVEL(stem, 2)                                           \
+       DEFINE_LEVEL(stem, 3)                                           \
+       DEFINE_LEVEL(stem, 4)                                           \
+       DEFINE_LEVEL(stem, 5)                                           \
+       DEFINE_LEVEL(stem, 6)                                           \
+       DEFINE_LEVEL(stem, 7)
+
+static struct btrfs_lockdep_keyset {
+       u64                     id;             /* root objectid */
+       /* Longest entry: btrfs-free-space-00 */
+       char                    names[BTRFS_MAX_LEVEL][20];
+       struct lock_class_key   keys[BTRFS_MAX_LEVEL];
+} btrfs_lockdep_keysets[] = {
+       { .id = BTRFS_ROOT_TREE_OBJECTID,       DEFINE_NAME("root")     },
+       { .id = BTRFS_EXTENT_TREE_OBJECTID,     DEFINE_NAME("extent")   },
+       { .id = BTRFS_CHUNK_TREE_OBJECTID,      DEFINE_NAME("chunk")    },
+       { .id = BTRFS_DEV_TREE_OBJECTID,        DEFINE_NAME("dev")      },
+       { .id = BTRFS_CSUM_TREE_OBJECTID,       DEFINE_NAME("csum")     },
+       { .id = BTRFS_QUOTA_TREE_OBJECTID,      DEFINE_NAME("quota")    },
+       { .id = BTRFS_TREE_LOG_OBJECTID,        DEFINE_NAME("log")      },
+       { .id = BTRFS_TREE_RELOC_OBJECTID,      DEFINE_NAME("treloc")   },
+       { .id = BTRFS_DATA_RELOC_TREE_OBJECTID, DEFINE_NAME("dreloc")   },
+       { .id = BTRFS_UUID_TREE_OBJECTID,       DEFINE_NAME("uuid")     },
+       { .id = BTRFS_FREE_SPACE_TREE_OBJECTID, DEFINE_NAME("free-space") },
+       { .id = 0,                              DEFINE_NAME("tree")     },
+};
+
+#undef DEFINE_LEVEL
+#undef DEFINE_NAME
+
+void btrfs_set_buffer_lockdep_class(u64 objectid, struct extent_buffer *eb, int level)
+{
+       struct btrfs_lockdep_keyset *ks;
+
+       BUG_ON(level >= ARRAY_SIZE(ks->keys));
+
+       /* Find the matching keyset, id 0 is the default entry */
+       for (ks = btrfs_lockdep_keysets; ks->id; ks++)
+               if (ks->id == objectid)
+                       break;
+
+       lockdep_set_class_and_name(&eb->lock, &ks->keys[level], ks->names[level]);
+}
+
+void btrfs_maybe_reset_lockdep_class(struct btrfs_root *root, struct extent_buffer *eb)
+{
+       if (test_bit(BTRFS_ROOT_RESET_LOCKDEP_CLASS, &root->state))
+               btrfs_set_buffer_lockdep_class(root->root_key.objectid,
+                                              eb, btrfs_header_level(eb));
+}
+
+#endif
+
+/*
  * Extent buffer locking
  * =====================
  *
@@ -164,6 +251,8 @@ struct extent_buffer *btrfs_lock_root_node(struct btrfs_root *root)
 
        while (1) {
                eb = btrfs_root_node(root);
+
+               btrfs_maybe_reset_lockdep_class(root, eb);
                btrfs_tree_lock(eb);
                if (eb == root->node)
                        break;
@@ -185,6 +274,8 @@ struct extent_buffer *btrfs_read_lock_root_node(struct btrfs_root *root)
 
        while (1) {
                eb = btrfs_root_node(root);
+
+               btrfs_maybe_reset_lockdep_class(root, eb);
                btrfs_tree_read_lock(eb);
                if (eb == root->node)
                        break;
index bbc4553..ab268be 100644 (file)
@@ -131,4 +131,18 @@ void btrfs_drew_write_unlock(struct btrfs_drew_lock *lock);
 void btrfs_drew_read_lock(struct btrfs_drew_lock *lock);
 void btrfs_drew_read_unlock(struct btrfs_drew_lock *lock);
 
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+void btrfs_set_buffer_lockdep_class(u64 objectid, struct extent_buffer *eb, int level);
+void btrfs_maybe_reset_lockdep_class(struct btrfs_root *root, struct extent_buffer *eb);
+#else
+static inline void btrfs_set_buffer_lockdep_class(u64 objectid,
+                                       struct extent_buffer *eb, int level)
+{
+}
+static inline void btrfs_maybe_reset_lockdep_class(struct btrfs_root *root,
+                                                  struct extent_buffer *eb)
+{
+}
+#endif
+
 #endif
index a6dc827..45c02ab 100644 (file)
@@ -1326,7 +1326,9 @@ again:
                btrfs_release_path(path);
 
                path->lowest_level = level;
+               set_bit(BTRFS_ROOT_RESET_LOCKDEP_CLASS, &src->state);
                ret = btrfs_search_slot(trans, src, &key, path, 0, 1);
+               clear_bit(BTRFS_ROOT_RESET_LOCKDEP_CLASS, &src->state);
                path->lowest_level = 0;
                if (ret) {
                        if (ret > 0)
@@ -3573,7 +3575,12 @@ int prepare_to_relocate(struct reloc_control *rc)
                 */
                return PTR_ERR(trans);
        }
-       return btrfs_commit_transaction(trans);
+
+       ret = btrfs_commit_transaction(trans);
+       if (ret)
+               unset_reloc_control(rc);
+
+       return ret;
 }
 
 static noinline_for_stack int relocate_block_group(struct reloc_control *rc)
index a64b26b..d647cb2 100644 (file)
@@ -349,9 +349,10 @@ int btrfs_del_root_ref(struct btrfs_trans_handle *trans, u64 root_id,
        key.offset = ref_id;
 again:
        ret = btrfs_search_slot(trans, tree_root, &key, path, -1, 1);
-       if (ret < 0)
+       if (ret < 0) {
+               err = ret;
                goto out;
-       if (ret == 0) {
+       } else if (ret == 0) {
                leaf = path->nodes[0];
                ref = btrfs_item_ptr(leaf, path->slots[0],
                                     struct btrfs_root_ref);
index d0cbeb7..435559b 100644 (file)
@@ -199,7 +199,7 @@ static u64 calc_chunk_size(const struct btrfs_fs_info *fs_info, u64 flags)
        ASSERT(flags & BTRFS_BLOCK_GROUP_TYPE_MASK);
 
        if (flags & BTRFS_BLOCK_GROUP_DATA)
-               return SZ_1G;
+               return BTRFS_MAX_DATA_CHUNK_SIZE;
        else if (flags & BTRFS_BLOCK_GROUP_SYSTEM)
                return SZ_32M;
 
index 9e0e0ae..43f905a 100644 (file)
@@ -1233,7 +1233,8 @@ static void extent_err(const struct extent_buffer *eb, int slot,
 }
 
 static int check_extent_item(struct extent_buffer *leaf,
-                            struct btrfs_key *key, int slot)
+                            struct btrfs_key *key, int slot,
+                            struct btrfs_key *prev_key)
 {
        struct btrfs_fs_info *fs_info = leaf->fs_info;
        struct btrfs_extent_item *ei;
@@ -1453,6 +1454,26 @@ static int check_extent_item(struct extent_buffer *leaf,
                           total_refs, inline_refs);
                return -EUCLEAN;
        }
+
+       if ((prev_key->type == BTRFS_EXTENT_ITEM_KEY) ||
+           (prev_key->type == BTRFS_METADATA_ITEM_KEY)) {
+               u64 prev_end = prev_key->objectid;
+
+               if (prev_key->type == BTRFS_METADATA_ITEM_KEY)
+                       prev_end += fs_info->nodesize;
+               else
+                       prev_end += prev_key->offset;
+
+               if (unlikely(prev_end > key->objectid)) {
+                       extent_err(leaf, slot,
+       "previous extent [%llu %u %llu] overlaps current extent [%llu %u %llu]",
+                                  prev_key->objectid, prev_key->type,
+                                  prev_key->offset, key->objectid, key->type,
+                                  key->offset);
+                       return -EUCLEAN;
+               }
+       }
+
        return 0;
 }
 
@@ -1621,7 +1642,7 @@ static int check_leaf_item(struct extent_buffer *leaf,
                break;
        case BTRFS_EXTENT_ITEM_KEY:
        case BTRFS_METADATA_ITEM_KEY:
-               ret = check_extent_item(leaf, key, slot);
+               ret = check_extent_item(leaf, key, slot, prev_key);
                break;
        case BTRFS_TREE_BLOCK_REF_KEY:
        case BTRFS_SHARED_DATA_REF_KEY:
index dcf75a8..9205c4a 100644 (file)
@@ -1146,7 +1146,9 @@ again:
        extref = btrfs_lookup_inode_extref(NULL, root, path, name, namelen,
                                           inode_objectid, parent_objectid, 0,
                                           0);
-       if (!IS_ERR_OR_NULL(extref)) {
+       if (IS_ERR(extref)) {
+               return PTR_ERR(extref);
+       } else if (extref) {
                u32 item_size;
                u32 cur_offset = 0;
                unsigned long base;
@@ -1457,7 +1459,7 @@ static int add_link(struct btrfs_trans_handle *trans,
         * on the inode will not free it. We will fixup the link count later.
         */
        if (other_inode->i_nlink == 0)
-               inc_nlink(other_inode);
+               set_nlink(other_inode, 1);
 add_link:
        ret = btrfs_add_link(trans, BTRFS_I(dir), BTRFS_I(inode),
                             name, namelen, 0, ref_index);
@@ -1600,7 +1602,7 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
                                 * free it. We will fixup the link count later.
                                 */
                                if (!ret && inode->i_nlink == 0)
-                                       inc_nlink(inode);
+                                       set_nlink(inode, 1);
                        }
                        if (ret < 0)
                                goto out;
index 2729015..f63ff91 100644 (file)
@@ -2345,8 +2345,11 @@ int btrfs_get_dev_args_from_path(struct btrfs_fs_info *fs_info,
 
        ret = btrfs_get_bdev_and_sb(path, FMODE_READ, fs_info->bdev_holder, 0,
                                    &bdev, &disk_super);
-       if (ret)
+       if (ret) {
+               btrfs_put_dev_args_from_path(args);
                return ret;
+       }
+
        args->devid = btrfs_stack_device_id(&disk_super->dev_item);
        memcpy(args->uuid, disk_super->dev_item.uuid, BTRFS_UUID_SIZE);
        if (btrfs_fs_incompat(fs_info, METADATA_UUID))
@@ -5264,6 +5267,9 @@ static int decide_stripe_size_regular(struct alloc_chunk_ctl *ctl,
                                       ctl->stripe_size);
        }
 
+       /* Stripe size should not go beyond 1G. */
+       ctl->stripe_size = min_t(u64, ctl->stripe_size, SZ_1G);
+
        /* Align to BTRFS_STRIPE_LEN */
        ctl->stripe_size = round_down(ctl->stripe_size, BTRFS_STRIPE_LEN);
        ctl->chunk_size = ctl->stripe_size * data_stripes;
index 7421abc..5bb8d8c 100644 (file)
@@ -371,6 +371,9 @@ static int btrfs_xattr_handler_set(const struct xattr_handler *handler,
                                   const char *name, const void *buffer,
                                   size_t size, int flags)
 {
+       if (btrfs_root_readonly(BTRFS_I(inode)->root))
+               return -EROFS;
+
        name = xattr_full_name(handler, name);
        return btrfs_setxattr_trans(inode, name, buffer, size, flags);
 }
index b150b07..73c6929 100644 (file)
@@ -421,10 +421,19 @@ int btrfs_get_dev_zone_info(struct btrfs_device *device, bool populate_cache)
         * since btrfs adds the pages one by one to a bio, and btrfs cannot
         * increase the metadata reservation even if it increases the number of
         * extents, it is safe to stick with the limit.
+        *
+        * With the zoned emulation, we can have non-zoned device on the zoned
+        * mode. In this case, we don't have a valid max zone append size. So,
+        * use max_segments * PAGE_SIZE as the pseudo max_zone_append_size.
         */
-       zone_info->max_zone_append_size =
-               min_t(u64, (u64)bdev_max_zone_append_sectors(bdev) << SECTOR_SHIFT,
-                     (u64)bdev_max_segments(bdev) << PAGE_SHIFT);
+       if (bdev_is_zoned(bdev)) {
+               zone_info->max_zone_append_size = min_t(u64,
+                       (u64)bdev_max_zone_append_sectors(bdev) << SECTOR_SHIFT,
+                       (u64)bdev_max_segments(bdev) << PAGE_SHIFT);
+       } else {
+               zone_info->max_zone_append_size =
+                       (u64)bdev_max_segments(bdev) << PAGE_SHIFT;
+       }
        if (!IS_ALIGNED(nr_sectors, zone_sectors))
                zone_info->nr_zones++;
 
@@ -1178,7 +1187,7 @@ int btrfs_ensure_empty_zones(struct btrfs_device *device, u64 start, u64 size)
  * offset.
  */
 static int calculate_alloc_pointer(struct btrfs_block_group *cache,
-                                  u64 *offset_ret)
+                                  u64 *offset_ret, bool new)
 {
        struct btrfs_fs_info *fs_info = cache->fs_info;
        struct btrfs_root *root;
@@ -1188,6 +1197,21 @@ static int calculate_alloc_pointer(struct btrfs_block_group *cache,
        int ret;
        u64 length;
 
+       /*
+        * Avoid  tree lookups for a new block group, there's no use for it.
+        * It must always be 0.
+        *
+        * Also, we have a lock chain of extent buffer lock -> chunk mutex.
+        * For new a block group, this function is called from
+        * btrfs_make_block_group() which is already taking the chunk mutex.
+        * Thus, we cannot call calculate_alloc_pointer() which takes extent
+        * buffer locks to avoid deadlock.
+        */
+       if (new) {
+               *offset_ret = 0;
+               return 0;
+       }
+
        path = btrfs_alloc_path();
        if (!path)
                return -ENOMEM;
@@ -1323,6 +1347,13 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new)
                else
                        num_conventional++;
 
+               /*
+                * Consider a zone as active if we can allow any number of
+                * active zones.
+                */
+               if (!device->zone_info->max_active_zones)
+                       __set_bit(i, active);
+
                if (!is_sequential) {
                        alloc_offsets[i] = WP_CONVENTIONAL;
                        continue;
@@ -1389,45 +1420,23 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new)
                        __set_bit(i, active);
                        break;
                }
-
-               /*
-                * Consider a zone as active if we can allow any number of
-                * active zones.
-                */
-               if (!device->zone_info->max_active_zones)
-                       __set_bit(i, active);
        }
 
        if (num_sequential > 0)
                cache->seq_zone = true;
 
        if (num_conventional > 0) {
-               /*
-                * Avoid calling calculate_alloc_pointer() for new BG. It
-                * is no use for new BG. It must be always 0.
-                *
-                * Also, we have a lock chain of extent buffer lock ->
-                * chunk mutex.  For new BG, this function is called from
-                * btrfs_make_block_group() which is already taking the
-                * chunk mutex. Thus, we cannot call
-                * calculate_alloc_pointer() which takes extent buffer
-                * locks to avoid deadlock.
-                */
-
                /* Zone capacity is always zone size in emulation */
                cache->zone_capacity = cache->length;
-               if (new) {
-                       cache->alloc_offset = 0;
-                       goto out;
-               }
-               ret = calculate_alloc_pointer(cache, &last_alloc);
-               if (ret || map->num_stripes == num_conventional) {
-                       if (!ret)
-                               cache->alloc_offset = last_alloc;
-                       else
-                               btrfs_err(fs_info,
+               ret = calculate_alloc_pointer(cache, &last_alloc, new);
+               if (ret) {
+                       btrfs_err(fs_info,
                        "zoned: failed to determine allocation offset of bg %llu",
-                                         cache->start);
+                                 cache->start);
+                       goto out;
+               } else if (map->num_stripes == num_conventional) {
+                       cache->alloc_offset = last_alloc;
+                       cache->zone_is_active = 1;
                        goto out;
                }
        }
@@ -1495,13 +1504,6 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new)
                goto out;
        }
 
-       if (cache->zone_is_active) {
-               btrfs_get_block_group(cache);
-               spin_lock(&fs_info->zone_active_bgs_lock);
-               list_add_tail(&cache->active_bg_list, &fs_info->zone_active_bgs);
-               spin_unlock(&fs_info->zone_active_bgs_lock);
-       }
-
 out:
        if (cache->alloc_offset > fs_info->zone_size) {
                btrfs_err(fs_info,
@@ -1526,10 +1528,16 @@ out:
                ret = -EIO;
        }
 
-       if (!ret)
+       if (!ret) {
                cache->meta_write_pointer = cache->alloc_offset + cache->start;
-
-       if (ret) {
+               if (cache->zone_is_active) {
+                       btrfs_get_block_group(cache);
+                       spin_lock(&fs_info->zone_active_bgs_lock);
+                       list_add_tail(&cache->active_bg_list,
+                                     &fs_info->zone_active_bgs);
+                       spin_unlock(&fs_info->zone_active_bgs_lock);
+               }
+       } else {
                kfree(cache->physical_map);
                cache->physical_map = NULL;
        }
@@ -1910,10 +1918,44 @@ out_unlock:
        return ret;
 }
 
+static void wait_eb_writebacks(struct btrfs_block_group *block_group)
+{
+       struct btrfs_fs_info *fs_info = block_group->fs_info;
+       const u64 end = block_group->start + block_group->length;
+       struct radix_tree_iter iter;
+       struct extent_buffer *eb;
+       void __rcu **slot;
+
+       rcu_read_lock();
+       radix_tree_for_each_slot(slot, &fs_info->buffer_radix, &iter,
+                                block_group->start >> fs_info->sectorsize_bits) {
+               eb = radix_tree_deref_slot(slot);
+               if (!eb)
+                       continue;
+               if (radix_tree_deref_retry(eb)) {
+                       slot = radix_tree_iter_retry(&iter);
+                       continue;
+               }
+
+               if (eb->start < block_group->start)
+                       continue;
+               if (eb->start >= end)
+                       break;
+
+               slot = radix_tree_iter_resume(slot, &iter);
+               rcu_read_unlock();
+               wait_on_extent_buffer_writeback(eb);
+               rcu_read_lock();
+       }
+       rcu_read_unlock();
+}
+
 static int do_zone_finish(struct btrfs_block_group *block_group, bool fully_written)
 {
        struct btrfs_fs_info *fs_info = block_group->fs_info;
        struct map_lookup *map;
+       const bool is_metadata = (block_group->flags &
+                       (BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_SYSTEM));
        int ret = 0;
        int i;
 
@@ -1924,8 +1966,7 @@ static int do_zone_finish(struct btrfs_block_group *block_group, bool fully_writ
        }
 
        /* Check if we have unwritten allocated space */
-       if ((block_group->flags &
-            (BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_SYSTEM)) &&
+       if (is_metadata &&
            block_group->start + block_group->alloc_offset > block_group->meta_write_pointer) {
                spin_unlock(&block_group->lock);
                return -EAGAIN;
@@ -1950,6 +1991,9 @@ static int do_zone_finish(struct btrfs_block_group *block_group, bool fully_writ
                /* No need to wait for NOCOW writers. Zoned mode does not allow that */
                btrfs_wait_ordered_roots(fs_info, U64_MAX, block_group->start,
                                         block_group->length);
+               /* Wait for extent buffers to be written. */
+               if (is_metadata)
+                       wait_eb_writebacks(block_group);
 
                spin_lock(&block_group->lock);
 
@@ -2007,8 +2051,7 @@ static int do_zone_finish(struct btrfs_block_group *block_group, bool fully_writ
        /* For active_bg_list */
        btrfs_put_block_group(block_group);
 
-       clear_bit(BTRFS_FS_NEED_ZONE_FINISH, &fs_info->flags);
-       wake_up_all(&fs_info->zone_finish_wait);
+       clear_and_wake_up_bit(BTRFS_FS_NEED_ZONE_FINISH, &fs_info->flags);
 
        return 0;
 }
index 6cba2c6..2ad58c4 100644 (file)
@@ -111,6 +111,7 @@ struct cachefiles_cache {
        char                            *tag;           /* cache binding tag */
        refcount_t                      unbind_pincount;/* refcount to do daemon unbind */
        struct xarray                   reqs;           /* xarray of pending on-demand requests */
+       unsigned long                   req_id_next;
        struct xarray                   ondemand_ids;   /* xarray for ondemand_id allocation */
        u32                             ondemand_id_next;
 };
index 1fee702..0254ed3 100644 (file)
@@ -158,9 +158,13 @@ int cachefiles_ondemand_copen(struct cachefiles_cache *cache, char *args)
 
        /* fail OPEN request if daemon reports an error */
        if (size < 0) {
-               if (!IS_ERR_VALUE(size))
-                       size = -EINVAL;
-               req->error = size;
+               if (!IS_ERR_VALUE(size)) {
+                       req->error = -EINVAL;
+                       ret = -EINVAL;
+               } else {
+                       req->error = size;
+                       ret = 0;
+               }
                goto out;
        }
 
@@ -238,14 +242,19 @@ ssize_t cachefiles_ondemand_daemon_read(struct cachefiles_cache *cache,
        unsigned long id = 0;
        size_t n;
        int ret = 0;
-       XA_STATE(xas, &cache->reqs, 0);
+       XA_STATE(xas, &cache->reqs, cache->req_id_next);
 
        /*
-        * Search for a request that has not ever been processed, to prevent
-        * requests from being processed repeatedly.
+        * Cyclically search for a request that has not ever been processed,
+        * to prevent requests from being processed repeatedly, and make
+        * request distribution fair.
         */
        xa_lock(&cache->reqs);
        req = xas_find_marked(&xas, UINT_MAX, CACHEFILES_REQ_NEW);
+       if (!req && cache->req_id_next > 0) {
+               xas_set(&xas, 0);
+               req = xas_find_marked(&xas, cache->req_id_next - 1, CACHEFILES_REQ_NEW);
+       }
        if (!req) {
                xa_unlock(&cache->reqs);
                return 0;
@@ -260,6 +269,7 @@ ssize_t cachefiles_ondemand_daemon_read(struct cachefiles_cache *cache,
        }
 
        xas_clear_mark(&xas, CACHEFILES_REQ_NEW);
+       cache->req_id_next = xas.xa_index + 1;
        xa_unlock(&cache->reqs);
 
        id = xas.xa_index;
index 11fd85d..c05477e 100644 (file)
@@ -42,7 +42,7 @@ void cifs_dump_detail(void *buf, struct TCP_Server_Info *server)
                 smb->Command, smb->Status.CifsError,
                 smb->Flags, smb->Flags2, smb->Mid, smb->Pid);
        cifs_dbg(VFS, "smb buf %p len %u\n", smb,
-                server->ops->calc_smb_size(smb, server));
+                server->ops->calc_smb_size(smb));
 #endif /* CONFIG_CIFS_DEBUG2 */
 }
 
index 8f7835c..46f5718 100644 (file)
@@ -32,10 +32,9 @@ int __cifs_calc_signature(struct smb_rqst *rqst,
        int rc;
        struct kvec *iov = rqst->rq_iov;
        int n_vec = rqst->rq_nvec;
-       int is_smb2 = server->vals->header_preamble_size == 0;
 
        /* iov[0] is actual data and not the rfc1002 length for SMB2+ */
-       if (is_smb2) {
+       if (!is_smb1(server)) {
                if (iov[0].iov_len <= 4)
                        return -EIO;
                i = 0;
index f54d8bf..8042d72 100644 (file)
@@ -1248,6 +1248,12 @@ ssize_t cifs_file_copychunk_range(unsigned int xid,
        lock_two_nondirectories(target_inode, src_inode);
 
        cifs_dbg(FYI, "about to flush pages\n");
+
+       rc = filemap_write_and_wait_range(src_inode->i_mapping, off,
+                                         off + len - 1);
+       if (rc)
+               goto out;
+
        /* should we flush first and last page first */
        truncate_inode_pages(&target_inode->i_data, 0);
 
index 81f4c15..5b4a7a3 100644 (file)
@@ -153,6 +153,6 @@ extern const struct export_operations cifs_export_ops;
 #endif /* CONFIG_CIFS_NFSD_EXPORT */
 
 /* when changing internal version - update following two lines at same time */
-#define SMB3_PRODUCT_BUILD 38
-#define CIFS_VERSION   "2.38"
+#define SMB3_PRODUCT_BUILD 39
+#define CIFS_VERSION   "2.39"
 #endif                         /* _CIFSFS_H */
index bc0ee2d..ae7f571 100644 (file)
@@ -417,7 +417,7 @@ struct smb_version_operations {
        int (*close_dir)(const unsigned int, struct cifs_tcon *,
                         struct cifs_fid *);
        /* calculate a size of SMB message */
-       unsigned int (*calc_smb_size)(void *buf, struct TCP_Server_Info *ptcpi);
+       unsigned int (*calc_smb_size)(void *buf);
        /* check for STATUS_PENDING and process the response if yes */
        bool (*is_status_pending)(char *buf, struct TCP_Server_Info *server);
        /* check for STATUS_NETWORK_SESSION_EXPIRED */
@@ -557,6 +557,8 @@ struct smb_version_values {
 
 #define HEADER_SIZE(server) (server->vals->header_size)
 #define MAX_HEADER_SIZE(server) (server->vals->max_header_size)
+#define HEADER_PREAMBLE_SIZE(server) (server->vals->header_preamble_size)
+#define MID_HEADER_SIZE(server) (HEADER_SIZE(server) - 1 - HEADER_PREAMBLE_SIZE(server))
 
 /**
  * CIFS superblock mount flags (mnt_cifs_flags) to consider when
@@ -750,6 +752,11 @@ struct TCP_Server_Info {
 #endif
 };
 
+static inline bool is_smb1(struct TCP_Server_Info *server)
+{
+       return HEADER_PREAMBLE_SIZE(server) != 0;
+}
+
 static inline void cifs_server_lock(struct TCP_Server_Info *server)
 {
        unsigned int nofs_flag = memalloc_nofs_save();
index 87a77a6..3bc94bc 100644 (file)
@@ -151,7 +151,7 @@ extern int cifs_get_writable_path(struct cifs_tcon *tcon, const char *name,
 extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool);
 extern int cifs_get_readable_path(struct cifs_tcon *tcon, const char *name,
                                  struct cifsFileInfo **ret_file);
-extern unsigned int smbCalcSize(void *buf, struct TCP_Server_Info *server);
+extern unsigned int smbCalcSize(void *buf);
 extern int decode_negTokenInit(unsigned char *security_blob, int length,
                        struct TCP_Server_Info *server);
 extern int cifs_convert_address(struct sockaddr *dst, const char *src, int len);
index 9e91a5a..56ec1b2 100644 (file)
@@ -59,7 +59,7 @@ static int __init cifs_root_setup(char *line)
                        pr_err("Root-CIFS: UNC path too long\n");
                        return 1;
                }
-               strlcpy(root_dev, line, len);
+               strscpy(root_dev, line, len);
                srvaddr = parse_srvaddr(&line[2], s);
                if (*s) {
                        int n = snprintf(root_opts,
index 9111c02..7ae6f2c 100644 (file)
@@ -702,9 +702,6 @@ cifs_readv_from_socket(struct TCP_Server_Info *server, struct msghdr *smb_msg)
        int length = 0;
        int total_read;
 
-       smb_msg->msg_control = NULL;
-       smb_msg->msg_controllen = 0;
-
        for (total_read = 0; msg_data_left(smb_msg); total_read += length) {
                try_to_freeze();
 
@@ -760,7 +757,7 @@ int
 cifs_read_from_socket(struct TCP_Server_Info *server, char *buf,
                      unsigned int to_read)
 {
-       struct msghdr smb_msg;
+       struct msghdr smb_msg = {};
        struct kvec iov = {.iov_base = buf, .iov_len = to_read};
        iov_iter_kvec(&smb_msg.msg_iter, READ, &iov, 1, to_read);
 
@@ -770,15 +767,13 @@ cifs_read_from_socket(struct TCP_Server_Info *server, char *buf,
 ssize_t
 cifs_discard_from_socket(struct TCP_Server_Info *server, size_t to_read)
 {
-       struct msghdr smb_msg;
+       struct msghdr smb_msg = {};
 
        /*
         *  iov_iter_discard already sets smb_msg.type and count and iov_offset
         *  and cifs_readv_from_socket sets msg_control and msg_controllen
         *  so little to initialize in struct msghdr
         */
-       smb_msg.msg_name = NULL;
-       smb_msg.msg_namelen = 0;
        iov_iter_discard(&smb_msg.msg_iter, READ, to_read);
 
        return cifs_readv_from_socket(server, &smb_msg);
@@ -788,7 +783,7 @@ int
 cifs_read_page_from_socket(struct TCP_Server_Info *server, struct page *page,
        unsigned int page_offset, unsigned int to_read)
 {
-       struct msghdr smb_msg;
+       struct msghdr smb_msg = {};
        struct bio_vec bv = {
                .bv_page = page, .bv_len = to_read, .bv_offset = page_offset};
        iov_iter_bvec(&smb_msg.msg_iter, READ, &bv, 1, to_read);
@@ -871,7 +866,7 @@ smb2_get_credits_from_hdr(char *buffer, struct TCP_Server_Info *server)
        /*
         * SMB1 does not use credits.
         */
-       if (server->vals->header_preamble_size)
+       if (is_smb1(server))
                return 0;
 
        return le16_to_cpu(shdr->CreditRequest);
@@ -1050,7 +1045,7 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 
        /* make sure this will fit in a large buffer */
        if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server) -
-               server->vals->header_preamble_size) {
+           HEADER_PREAMBLE_SIZE(server)) {
                cifs_server_dbg(VFS, "SMB response too long (%u bytes)\n", pdu_length);
                cifs_reconnect(server, true);
                return -ECONNABORTED;
@@ -1065,8 +1060,7 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 
        /* now read the rest */
        length = cifs_read_from_socket(server, buf + HEADER_SIZE(server) - 1,
-                                      pdu_length - HEADER_SIZE(server) + 1
-                                      + server->vals->header_preamble_size);
+                                      pdu_length - MID_HEADER_SIZE(server));
 
        if (length < 0)
                return length;
@@ -1122,7 +1116,7 @@ smb2_add_credits_from_hdr(char *buffer, struct TCP_Server_Info *server)
        /*
         * SMB1 does not use credits.
         */
-       if (server->vals->header_preamble_size)
+       if (is_smb1(server))
                return;
 
        if (shdr->CreditRequest) {
@@ -1180,10 +1174,10 @@ cifs_demultiplex_thread(void *p)
                if (length < 0)
                        continue;
 
-               if (server->vals->header_preamble_size == 0)
-                       server->total_read = 0;
-               else
+               if (is_smb1(server))
                        server->total_read = length;
+               else
+                       server->total_read = 0;
 
                /*
                 * The right amount was read from socket - 4 bytes,
@@ -1198,8 +1192,7 @@ next_pdu:
                server->pdu_size = pdu_length;
 
                /* make sure we have enough to get to the MID */
-               if (server->pdu_size < HEADER_SIZE(server) - 1 -
-                   server->vals->header_preamble_size) {
+               if (server->pdu_size < MID_HEADER_SIZE(server)) {
                        cifs_server_dbg(VFS, "SMB response too short (%u bytes)\n",
                                 server->pdu_size);
                        cifs_reconnect(server, true);
@@ -1208,9 +1201,8 @@ next_pdu:
 
                /* read down to the MID */
                length = cifs_read_from_socket(server,
-                            buf + server->vals->header_preamble_size,
-                            HEADER_SIZE(server) - 1
-                            - server->vals->header_preamble_size);
+                            buf + HEADER_PREAMBLE_SIZE(server),
+                            MID_HEADER_SIZE(server));
                if (length < 0)
                        continue;
                server->total_read += length;
@@ -2353,7 +2345,9 @@ cifs_put_tcon(struct cifs_tcon *tcon)
        ses = tcon->ses;
        cifs_dbg(FYI, "%s: tc_count=%d\n", __func__, tcon->tc_count);
        spin_lock(&cifs_tcp_ses_lock);
+       spin_lock(&tcon->tc_lock);
        if (--tcon->tc_count > 0) {
+               spin_unlock(&tcon->tc_lock);
                spin_unlock(&cifs_tcp_ses_lock);
                return;
        }
@@ -2362,6 +2356,7 @@ cifs_put_tcon(struct cifs_tcon *tcon)
        WARN_ON(tcon->tc_count < 0);
 
        list_del_init(&tcon->tcon_list);
+       spin_unlock(&tcon->tc_lock);
        spin_unlock(&cifs_tcp_ses_lock);
 
        /* cancel polling of interfaces */
@@ -3994,7 +3989,7 @@ CIFSTCon(const unsigned int xid, struct cifs_ses *ses,
                }
                bcc_ptr += length + 1;
                bytes_left -= (length + 1);
-               strlcpy(tcon->treeName, tree, sizeof(tcon->treeName));
+               strscpy(tcon->treeName, tree, sizeof(tcon->treeName));
 
                /* mostly informational -- no need to fail on error here */
                kfree(tcon->nativeFileSystem);
index fa738ad..6f38b13 100644 (file)
@@ -3575,6 +3575,9 @@ static ssize_t __cifs_writev(
 
 ssize_t cifs_direct_writev(struct kiocb *iocb, struct iov_iter *from)
 {
+       struct file *file = iocb->ki_filp;
+
+       cifs_revalidate_mapping(file->f_inode);
        return __cifs_writev(iocb, from, true);
 }
 
index 34d990f..87f60f7 100644 (file)
@@ -354,7 +354,7 @@ checkSMB(char *buf, unsigned int total_read, struct TCP_Server_Info *server)
        /* otherwise, there is enough to get to the BCC */
        if (check_smb_hdr(smb))
                return -EIO;
-       clc_len = smbCalcSize(smb, server);
+       clc_len = smbCalcSize(smb);
 
        if (4 + rfclen != total_read) {
                cifs_dbg(VFS, "Length read does not match RFC1001 length %d\n",
@@ -737,6 +737,8 @@ cifs_close_deferred_file(struct cifsInodeInfo *cifs_inode)
        list_for_each_entry(cfile, &cifs_inode->openFileList, flist) {
                if (delayed_work_pending(&cfile->deferred)) {
                        if (cancel_delayed_work(&cfile->deferred)) {
+                               cifs_del_deferred_close(cfile);
+
                                tmp_list = kmalloc(sizeof(struct file_list), GFP_ATOMIC);
                                if (tmp_list == NULL)
                                        break;
@@ -766,6 +768,8 @@ cifs_close_all_deferred_files(struct cifs_tcon *tcon)
        list_for_each_entry(cfile, &tcon->openFileList, tlist) {
                if (delayed_work_pending(&cfile->deferred)) {
                        if (cancel_delayed_work(&cfile->deferred)) {
+                               cifs_del_deferred_close(cfile);
+
                                tmp_list = kmalloc(sizeof(struct file_list), GFP_ATOMIC);
                                if (tmp_list == NULL)
                                        break;
@@ -799,6 +803,8 @@ cifs_close_deferred_file_under_dentry(struct cifs_tcon *tcon, const char *path)
                if (strstr(full_path, path)) {
                        if (delayed_work_pending(&cfile->deferred)) {
                                if (cancel_delayed_work(&cfile->deferred)) {
+                                       cifs_del_deferred_close(cfile);
+
                                        tmp_list = kmalloc(sizeof(struct file_list), GFP_ATOMIC);
                                        if (tmp_list == NULL)
                                                break;
index 28caae7..1b52e6a 100644 (file)
@@ -909,7 +909,7 @@ map_and_check_smb_error(struct mid_q_entry *mid, bool logErr)
  * portion, the number of word parameters and the data portion of the message
  */
 unsigned int
-smbCalcSize(void *buf, struct TCP_Server_Info *server)
+smbCalcSize(void *buf)
 {
        struct smb_hdr *ptr = buf;
        return (sizeof(struct smb_hdr) + (2 * ptr->WordCount) +
index 2eece8a..8e060c0 100644 (file)
@@ -806,8 +806,7 @@ find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos,
 
                end_of_smb = cfile->srch_inf.ntwrk_buf_start +
                        server->ops->calc_smb_size(
-                                       cfile->srch_inf.ntwrk_buf_start,
-                                       server);
+                                       cfile->srch_inf.ntwrk_buf_start);
 
                cur_ent = cfile->srch_inf.srch_entries_start;
                first_entry_in_buffer = cfile->srch_inf.index_of_last_entry
@@ -1161,8 +1160,7 @@ int cifs_readdir(struct file *file, struct dir_context *ctx)
        cifs_dbg(FYI, "loop through %d times filling dir for net buf %p\n",
                 num_to_fill, cifsFile->srch_inf.ntwrk_buf_start);
        max_len = tcon->ses->server->ops->calc_smb_size(
-                       cifsFile->srch_inf.ntwrk_buf_start,
-                       tcon->ses->server);
+                       cifsFile->srch_inf.ntwrk_buf_start);
        end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len;
 
        tmp_buf = kmalloc(UNICODE_NAME_MAX, GFP_KERNEL);
index f5dcc49..9dfd2dd 100644 (file)
@@ -61,7 +61,6 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
                nr_ioctl_req.Reserved = 0;
                rc = SMB2_ioctl(xid, oparms->tcon, fid->persistent_fid,
                        fid->volatile_fid, FSCTL_LMR_REQUEST_RESILIENCY,
-                       true /* is_fsctl */,
                        (char *)&nr_ioctl_req, sizeof(nr_ioctl_req),
                        CIFSMaxBufSize, NULL, NULL /* no return info */);
                if (rc == -EOPNOTSUPP) {
index 6a6ec6e..d73e567 100644 (file)
@@ -222,7 +222,7 @@ smb2_check_message(char *buf, unsigned int len, struct TCP_Server_Info *server)
                }
        }
 
-       calc_len = smb2_calc_size(buf, server);
+       calc_len = smb2_calc_size(buf);
 
        /* For SMB2_IOCTL, OutputOffset and OutputLength are optional, so might
         * be 0, and not a real miscalculation */
@@ -410,7 +410,7 @@ smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *shdr)
  * portion, the number of word parameters and the data portion of the message.
  */
 unsigned int
-smb2_calc_size(void *buf, struct TCP_Server_Info *srvr)
+smb2_calc_size(void *buf)
 {
        struct smb2_pdu *pdu = buf;
        struct smb2_hdr *shdr = &pdu->hdr;
index f406af5..421be43 100644 (file)
@@ -387,7 +387,7 @@ smb2_dump_detail(void *buf, struct TCP_Server_Info *server)
                 shdr->Command, shdr->Status, shdr->Flags, shdr->MessageId,
                 shdr->Id.SyncId.ProcessId);
        cifs_server_dbg(VFS, "smb buf %p len %u\n", buf,
-                server->ops->calc_smb_size(buf, server));
+                server->ops->calc_smb_size(buf));
 #endif
 }
 
@@ -681,7 +681,7 @@ SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon)
        struct cifs_ses *ses = tcon->ses;
 
        rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID,
-                       FSCTL_QUERY_NETWORK_INTERFACE_INFO, true /* is_fsctl */,
+                       FSCTL_QUERY_NETWORK_INTERFACE_INFO,
                        NULL /* no data input */, 0 /* no data input */,
                        CIFSMaxBufSize, (char **)&out_buf, &ret_data_len);
        if (rc == -EOPNOTSUPP) {
@@ -1323,9 +1323,8 @@ SMB2_request_res_key(const unsigned int xid, struct cifs_tcon *tcon,
        struct resume_key_req *res_key;
 
        rc = SMB2_ioctl(xid, tcon, persistent_fid, volatile_fid,
-                       FSCTL_SRV_REQUEST_RESUME_KEY, true /* is_fsctl */,
-                       NULL, 0 /* no input */, CIFSMaxBufSize,
-                       (char **)&res_key, &ret_data_len);
+                       FSCTL_SRV_REQUEST_RESUME_KEY, NULL, 0 /* no input */,
+                       CIFSMaxBufSize, (char **)&res_key, &ret_data_len);
 
        if (rc == -EOPNOTSUPP) {
                pr_warn_once("Server share %s does not support copy range\n", tcon->treeName);
@@ -1467,7 +1466,7 @@ smb2_ioctl_query_info(const unsigned int xid,
                rqst[1].rq_nvec = SMB2_IOCTL_IOV_SIZE;
 
                rc = SMB2_ioctl_init(tcon, server, &rqst[1], COMPOUND_FID, COMPOUND_FID,
-                                    qi.info_type, true, buffer, qi.output_buffer_length,
+                                    qi.info_type, buffer, qi.output_buffer_length,
                                     CIFSMaxBufSize - MAX_SMB2_CREATE_RESPONSE_SIZE -
                                     MAX_SMB2_CLOSE_RESPONSE_SIZE);
                free_req1_func = SMB2_ioctl_free;
@@ -1601,17 +1600,8 @@ smb2_copychunk_range(const unsigned int xid,
        int chunks_copied = 0;
        bool chunk_sizes_updated = false;
        ssize_t bytes_written, total_bytes_written = 0;
-       struct inode *inode;
 
        pcchunk = kmalloc(sizeof(struct copychunk_ioctl), GFP_KERNEL);
-
-       /*
-        * We need to flush all unwritten data before we can send the
-        * copychunk ioctl to the server.
-        */
-       inode = d_inode(trgtfile->dentry);
-       filemap_write_and_wait(inode->i_mapping);
-
        if (pcchunk == NULL)
                return -ENOMEM;
 
@@ -1643,9 +1633,8 @@ smb2_copychunk_range(const unsigned int xid,
                retbuf = NULL;
                rc = SMB2_ioctl(xid, tcon, trgtfile->fid.persistent_fid,
                        trgtfile->fid.volatile_fid, FSCTL_SRV_COPYCHUNK_WRITE,
-                       true /* is_fsctl */, (char *)pcchunk,
-                       sizeof(struct copychunk_ioctl), CIFSMaxBufSize,
-                       (char **)&retbuf, &ret_data_len);
+                       (char *)pcchunk, sizeof(struct copychunk_ioctl),
+                       CIFSMaxBufSize, (char **)&retbuf, &ret_data_len);
                if (rc == 0) {
                        if (ret_data_len !=
                                        sizeof(struct copychunk_ioctl_rsp)) {
@@ -1805,7 +1794,6 @@ static bool smb2_set_sparse(const unsigned int xid, struct cifs_tcon *tcon,
 
        rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
                        cfile->fid.volatile_fid, FSCTL_SET_SPARSE,
-                       true /* is_fctl */,
                        &setsparse, 1, CIFSMaxBufSize, NULL, NULL);
        if (rc) {
                tcon->broken_sparse_sup = true;
@@ -1888,7 +1876,6 @@ smb2_duplicate_extents(const unsigned int xid,
        rc = SMB2_ioctl(xid, tcon, trgtfile->fid.persistent_fid,
                        trgtfile->fid.volatile_fid,
                        FSCTL_DUPLICATE_EXTENTS_TO_FILE,
-                       true /* is_fsctl */,
                        (char *)&dup_ext_buf,
                        sizeof(struct duplicate_extents_to_file),
                        CIFSMaxBufSize, NULL,
@@ -1923,7 +1910,6 @@ smb3_set_integrity(const unsigned int xid, struct cifs_tcon *tcon,
        return SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
                        cfile->fid.volatile_fid,
                        FSCTL_SET_INTEGRITY_INFORMATION,
-                       true /* is_fsctl */,
                        (char *)&integr_info,
                        sizeof(struct fsctl_set_integrity_information_req),
                        CIFSMaxBufSize, NULL,
@@ -1976,7 +1962,6 @@ smb3_enum_snapshots(const unsigned int xid, struct cifs_tcon *tcon,
        rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
                        cfile->fid.volatile_fid,
                        FSCTL_SRV_ENUMERATE_SNAPSHOTS,
-                       true /* is_fsctl */,
                        NULL, 0 /* no input data */, max_response_size,
                        (char **)&retbuf,
                        &ret_data_len);
@@ -2699,7 +2684,6 @@ smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses,
        do {
                rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID,
                                FSCTL_DFS_GET_REFERRALS,
-                               true /* is_fsctl */,
                                (char *)dfs_req, dfs_req_size, CIFSMaxBufSize,
                                (char **)&dfs_rsp, &dfs_rsp_size);
                if (!is_retryable_error(rc))
@@ -2906,8 +2890,7 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
 
        rc = SMB2_ioctl_init(tcon, server,
                             &rqst[1], fid.persistent_fid,
-                            fid.volatile_fid, FSCTL_GET_REPARSE_POINT,
-                            true /* is_fctl */, NULL, 0,
+                            fid.volatile_fid, FSCTL_GET_REPARSE_POINT, NULL, 0,
                             CIFSMaxBufSize -
                             MAX_SMB2_CREATE_RESPONSE_SIZE -
                             MAX_SMB2_CLOSE_RESPONSE_SIZE);
@@ -3087,8 +3070,7 @@ smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon,
 
        rc = SMB2_ioctl_init(tcon, server,
                             &rqst[1], COMPOUND_FID,
-                            COMPOUND_FID, FSCTL_GET_REPARSE_POINT,
-                            true /* is_fctl */, NULL, 0,
+                            COMPOUND_FID, FSCTL_GET_REPARSE_POINT, NULL, 0,
                             CIFSMaxBufSize -
                             MAX_SMB2_CREATE_RESPONSE_SIZE -
                             MAX_SMB2_CLOSE_RESPONSE_SIZE);
@@ -3316,26 +3298,43 @@ get_smb2_acl(struct cifs_sb_info *cifs_sb,
        return pntsd;
 }
 
+static long smb3_zero_data(struct file *file, struct cifs_tcon *tcon,
+                            loff_t offset, loff_t len, unsigned int xid)
+{
+       struct cifsFileInfo *cfile = file->private_data;
+       struct file_zero_data_information fsctl_buf;
+
+       cifs_dbg(FYI, "Offset %lld len %lld\n", offset, len);
+
+       fsctl_buf.FileOffset = cpu_to_le64(offset);
+       fsctl_buf.BeyondFinalZero = cpu_to_le64(offset + len);
+
+       return SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
+                         cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA,
+                         (char *)&fsctl_buf,
+                         sizeof(struct file_zero_data_information),
+                         0, NULL, NULL);
+}
+
 static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
                            loff_t offset, loff_t len, bool keep_size)
 {
        struct cifs_ses *ses = tcon->ses;
-       struct inode *inode;
-       struct cifsInodeInfo *cifsi;
+       struct inode *inode = file_inode(file);
+       struct cifsInodeInfo *cifsi = CIFS_I(inode);
        struct cifsFileInfo *cfile = file->private_data;
-       struct file_zero_data_information fsctl_buf;
        long rc;
        unsigned int xid;
        __le64 eof;
 
        xid = get_xid();
 
-       inode = d_inode(cfile->dentry);
-       cifsi = CIFS_I(inode);
-
        trace_smb3_zero_enter(xid, cfile->fid.persistent_fid, tcon->tid,
                              ses->Suid, offset, len);
 
+       inode_lock(inode);
+       filemap_invalidate_lock(inode->i_mapping);
+
        /*
         * We zero the range through ioctl, so we need remove the page caches
         * first, otherwise the data may be inconsistent with the server.
@@ -3343,26 +3342,12 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
        truncate_pagecache_range(inode, offset, offset + len - 1);
 
        /* if file not oplocked can't be sure whether asking to extend size */
-       if (!CIFS_CACHE_READ(cifsi))
-               if (keep_size == false) {
-                       rc = -EOPNOTSUPP;
-                       trace_smb3_zero_err(xid, cfile->fid.persistent_fid,
-                               tcon->tid, ses->Suid, offset, len, rc);
-                       free_xid(xid);
-                       return rc;
-               }
-
-       cifs_dbg(FYI, "Offset %lld len %lld\n", offset, len);
-
-       fsctl_buf.FileOffset = cpu_to_le64(offset);
-       fsctl_buf.BeyondFinalZero = cpu_to_le64(offset + len);
+       rc = -EOPNOTSUPP;
+       if (keep_size == false && !CIFS_CACHE_READ(cifsi))
+               goto zero_range_exit;
 
-       rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
-                       cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA, true,
-                       (char *)&fsctl_buf,
-                       sizeof(struct file_zero_data_information),
-                       0, NULL, NULL);
-       if (rc)
+       rc = smb3_zero_data(file, tcon, offset, len, xid);
+       if (rc < 0)
                goto zero_range_exit;
 
        /*
@@ -3375,6 +3360,8 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
        }
 
  zero_range_exit:
+       filemap_invalidate_unlock(inode->i_mapping);
+       inode_unlock(inode);
        free_xid(xid);
        if (rc)
                trace_smb3_zero_err(xid, cfile->fid.persistent_fid, tcon->tid,
@@ -3388,7 +3375,7 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
 static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,
                            loff_t offset, loff_t len)
 {
-       struct inode *inode;
+       struct inode *inode = file_inode(file);
        struct cifsFileInfo *cfile = file->private_data;
        struct file_zero_data_information fsctl_buf;
        long rc;
@@ -3397,14 +3384,12 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,
 
        xid = get_xid();
 
-       inode = d_inode(cfile->dentry);
-
+       inode_lock(inode);
        /* Need to make file sparse, if not already, before freeing range. */
        /* Consider adding equivalent for compressed since it could also work */
        if (!smb2_set_sparse(xid, tcon, cfile, inode, set_sparse)) {
                rc = -EOPNOTSUPP;
-               free_xid(xid);
-               return rc;
+               goto out;
        }
 
        filemap_invalidate_lock(inode->i_mapping);
@@ -3421,11 +3406,13 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,
 
        rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
                        cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA,
-                       true /* is_fctl */, (char *)&fsctl_buf,
+                       (char *)&fsctl_buf,
                        sizeof(struct file_zero_data_information),
                        CIFSMaxBufSize, NULL, NULL);
-       free_xid(xid);
        filemap_invalidate_unlock(inode->i_mapping);
+out:
+       inode_unlock(inode);
+       free_xid(xid);
        return rc;
 }
 
@@ -3481,7 +3468,7 @@ static int smb3_simple_fallocate_range(unsigned int xid,
        in_data.length = cpu_to_le64(len);
        rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
                        cfile->fid.volatile_fid,
-                       FSCTL_QUERY_ALLOCATED_RANGES, true,
+                       FSCTL_QUERY_ALLOCATED_RANGES,
                        (char *)&in_data, sizeof(in_data),
                        1024 * sizeof(struct file_allocated_range_buffer),
                        (char **)&out_data, &out_data_len);
@@ -3682,39 +3669,50 @@ static long smb3_collapse_range(struct file *file, struct cifs_tcon *tcon,
 {
        int rc;
        unsigned int xid;
-       struct inode *inode;
+       struct inode *inode = file_inode(file);
        struct cifsFileInfo *cfile = file->private_data;
-       struct cifsInodeInfo *cifsi;
+       struct cifsInodeInfo *cifsi = CIFS_I(inode);
        __le64 eof;
+       loff_t old_eof;
 
        xid = get_xid();
 
-       inode = d_inode(cfile->dentry);
-       cifsi = CIFS_I(inode);
+       inode_lock(inode);
 
-       if (off >= i_size_read(inode) ||
-           off + len >= i_size_read(inode)) {
+       old_eof = i_size_read(inode);
+       if ((off >= old_eof) ||
+           off + len >= old_eof) {
                rc = -EINVAL;
                goto out;
        }
 
+       filemap_invalidate_lock(inode->i_mapping);
+       rc = filemap_write_and_wait_range(inode->i_mapping, off, old_eof - 1);
+       if (rc < 0)
+               goto out_2;
+
+       truncate_pagecache_range(inode, off, old_eof);
+
        rc = smb2_copychunk_range(xid, cfile, cfile, off + len,
-                                 i_size_read(inode) - off - len, off);
+                                 old_eof - off - len, off);
        if (rc < 0)
-               goto out;
+               goto out_2;
 
-       eof = cpu_to_le64(i_size_read(inode) - len);
+       eof = cpu_to_le64(old_eof - len);
        rc = SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid,
                          cfile->fid.volatile_fid, cfile->pid, &eof);
        if (rc < 0)
-               goto out;
+               goto out_2;
 
        rc = 0;
 
        cifsi->server_eof = i_size_read(inode) - len;
        truncate_setsize(inode, cifsi->server_eof);
        fscache_resize_cookie(cifs_inode_cookie(inode), cifsi->server_eof);
+out_2:
+       filemap_invalidate_unlock(inode->i_mapping);
  out:
+       inode_unlock(inode);
        free_xid(xid);
        return rc;
 }
@@ -3725,34 +3723,47 @@ static long smb3_insert_range(struct file *file, struct cifs_tcon *tcon,
        int rc;
        unsigned int xid;
        struct cifsFileInfo *cfile = file->private_data;
+       struct inode *inode = file_inode(file);
        __le64 eof;
-       __u64  count;
+       __u64  count, old_eof;
 
        xid = get_xid();
 
-       if (off >= i_size_read(file->f_inode)) {
+       inode_lock(inode);
+
+       old_eof = i_size_read(inode);
+       if (off >= old_eof) {
                rc = -EINVAL;
                goto out;
        }
 
-       count = i_size_read(file->f_inode) - off;
-       eof = cpu_to_le64(i_size_read(file->f_inode) + len);
+       count = old_eof - off;
+       eof = cpu_to_le64(old_eof + len);
+
+       filemap_invalidate_lock(inode->i_mapping);
+       rc = filemap_write_and_wait_range(inode->i_mapping, off, old_eof + len - 1);
+       if (rc < 0)
+               goto out_2;
+       truncate_pagecache_range(inode, off, old_eof);
 
        rc = SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid,
                          cfile->fid.volatile_fid, cfile->pid, &eof);
        if (rc < 0)
-               goto out;
+               goto out_2;
 
        rc = smb2_copychunk_range(xid, cfile, cfile, off, count, off + len);
        if (rc < 0)
-               goto out;
+               goto out_2;
 
-       rc = smb3_zero_range(file, tcon, off, len, 1);
+       rc = smb3_zero_data(file, tcon, off, len, xid);
        if (rc < 0)
-               goto out;
+               goto out_2;
 
        rc = 0;
+out_2:
+       filemap_invalidate_unlock(inode->i_mapping);
  out:
+       inode_unlock(inode);
        free_xid(xid);
        return rc;
 }
@@ -3802,7 +3813,7 @@ static loff_t smb3_llseek(struct file *file, struct cifs_tcon *tcon, loff_t offs
 
        rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
                        cfile->fid.volatile_fid,
-                       FSCTL_QUERY_ALLOCATED_RANGES, true,
+                       FSCTL_QUERY_ALLOCATED_RANGES,
                        (char *)&in_data, sizeof(in_data),
                        sizeof(struct file_allocated_range_buffer),
                        (char **)&out_data, &out_data_len);
@@ -3862,7 +3873,7 @@ static int smb3_fiemap(struct cifs_tcon *tcon,
 
        rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
                        cfile->fid.volatile_fid,
-                       FSCTL_QUERY_ALLOCATED_RANGES, true,
+                       FSCTL_QUERY_ALLOCATED_RANGES,
                        (char *)&in_data, sizeof(in_data),
                        1024 * sizeof(struct file_allocated_range_buffer),
                        (char **)&out_data, &out_data_len);
index 9b31ea9..6352ab3 100644 (file)
@@ -965,16 +965,17 @@ SMB2_negotiate(const unsigned int xid,
        } else if (rc != 0)
                goto neg_exit;
 
+       rc = -EIO;
        if (strcmp(server->vals->version_string,
                   SMB3ANY_VERSION_STRING) == 0) {
                if (rsp->DialectRevision == cpu_to_le16(SMB20_PROT_ID)) {
                        cifs_server_dbg(VFS,
                                "SMB2 dialect returned but not requested\n");
-                       return -EIO;
+                       goto neg_exit;
                } else if (rsp->DialectRevision == cpu_to_le16(SMB21_PROT_ID)) {
                        cifs_server_dbg(VFS,
                                "SMB2.1 dialect returned but not requested\n");
-                       return -EIO;
+                       goto neg_exit;
                } else if (rsp->DialectRevision == cpu_to_le16(SMB311_PROT_ID)) {
                        /* ops set to 3.0 by default for default so update */
                        server->ops = &smb311_operations;
@@ -985,7 +986,7 @@ SMB2_negotiate(const unsigned int xid,
                if (rsp->DialectRevision == cpu_to_le16(SMB20_PROT_ID)) {
                        cifs_server_dbg(VFS,
                                "SMB2 dialect returned but not requested\n");
-                       return -EIO;
+                       goto neg_exit;
                } else if (rsp->DialectRevision == cpu_to_le16(SMB21_PROT_ID)) {
                        /* ops set to 3.0 by default for default so update */
                        server->ops = &smb21_operations;
@@ -999,7 +1000,7 @@ SMB2_negotiate(const unsigned int xid,
                /* if requested single dialect ensure returned dialect matched */
                cifs_server_dbg(VFS, "Invalid 0x%x dialect returned: not requested\n",
                                le16_to_cpu(rsp->DialectRevision));
-               return -EIO;
+               goto neg_exit;
        }
 
        cifs_dbg(FYI, "mode 0x%x\n", rsp->SecurityMode);
@@ -1017,9 +1018,10 @@ SMB2_negotiate(const unsigned int xid,
        else {
                cifs_server_dbg(VFS, "Invalid dialect returned by server 0x%x\n",
                                le16_to_cpu(rsp->DialectRevision));
-               rc = -EIO;
                goto neg_exit;
        }
+
+       rc = 0;
        server->dialect = le16_to_cpu(rsp->DialectRevision);
 
        /*
@@ -1173,7 +1175,7 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
        }
 
        rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID,
-               FSCTL_VALIDATE_NEGOTIATE_INFO, true /* is_fsctl */,
+               FSCTL_VALIDATE_NEGOTIATE_INFO,
                (char *)pneg_inbuf, inbuflen, CIFSMaxBufSize,
                (char **)&pneg_rsp, &rsplen);
        if (rc == -EOPNOTSUPP) {
@@ -1928,7 +1930,7 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
        tcon->capabilities = rsp->Capabilities; /* we keep caps little endian */
        tcon->maximal_access = le32_to_cpu(rsp->MaximalAccess);
        tcon->tid = le32_to_cpu(rsp->hdr.Id.SyncId.TreeId);
-       strlcpy(tcon->treeName, tree, sizeof(tcon->treeName));
+       strscpy(tcon->treeName, tree, sizeof(tcon->treeName));
 
        if ((rsp->Capabilities & SMB2_SHARE_CAP_DFS) &&
            ((tcon->share_flags & SHI1005_FLAGS_DFS) == 0))
@@ -2572,19 +2574,15 @@ alloc_path_with_tree_prefix(__le16 **out_path, int *out_size, int *out_len,
 
        path_len = UniStrnlen((wchar_t *)path, PATH_MAX);
 
-       /*
-        * make room for one path separator between the treename and
-        * path
-        */
-       *out_len = treename_len + 1 + path_len;
+       /* make room for one path separator only if @path isn't empty */
+       *out_len = treename_len + (path[0] ? 1 : 0) + path_len;
 
        /*
-        * final path needs to be null-terminated UTF16 with a
-        * size aligned to 8
+        * final path needs to be 8-byte aligned as specified in
+        * MS-SMB2 2.2.13 SMB2 CREATE Request.
         */
-
-       *out_size = roundup((*out_len+1)*2, 8);
-       *out_path = kzalloc(*out_size, GFP_KERNEL);
+       *out_size = roundup(*out_len * sizeof(__le16), 8);
+       *out_path = kzalloc(*out_size + sizeof(__le16) /* null */, GFP_KERNEL);
        if (!*out_path)
                return -ENOMEM;
 
@@ -3056,7 +3054,7 @@ int
 SMB2_ioctl_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
                struct smb_rqst *rqst,
                u64 persistent_fid, u64 volatile_fid, u32 opcode,
-               bool is_fsctl, char *in_data, u32 indatalen,
+               char *in_data, u32 indatalen,
                __u32 max_response_size)
 {
        struct smb2_ioctl_req *req;
@@ -3131,10 +3129,8 @@ SMB2_ioctl_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
        req->hdr.CreditCharge =
                cpu_to_le16(DIV_ROUND_UP(max(indatalen, max_response_size),
                                         SMB2_MAX_BUFFER_SIZE));
-       if (is_fsctl)
-               req->Flags = cpu_to_le32(SMB2_0_IOCTL_IS_FSCTL);
-       else
-               req->Flags = 0;
+       /* always an FSCTL (for now) */
+       req->Flags = cpu_to_le32(SMB2_0_IOCTL_IS_FSCTL);
 
        /* validate negotiate request must be signed - see MS-SMB2 3.2.5.5 */
        if (opcode == FSCTL_VALIDATE_NEGOTIATE_INFO)
@@ -3161,9 +3157,9 @@ SMB2_ioctl_free(struct smb_rqst *rqst)
  */
 int
 SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
-          u64 volatile_fid, u32 opcode, bool is_fsctl,
-          char *in_data, u32 indatalen, u32 max_out_data_len,
-          char **out_data, u32 *plen /* returned data len */)
+          u64 volatile_fid, u32 opcode, char *in_data, u32 indatalen,
+          u32 max_out_data_len, char **out_data,
+          u32 *plen /* returned data len */)
 {
        struct smb_rqst rqst;
        struct smb2_ioctl_rsp *rsp = NULL;
@@ -3205,7 +3201,7 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
 
        rc = SMB2_ioctl_init(tcon, server,
                             &rqst, persistent_fid, volatile_fid, opcode,
-                            is_fsctl, in_data, indatalen, max_out_data_len);
+                            in_data, indatalen, max_out_data_len);
        if (rc)
                goto ioctl_exit;
 
@@ -3297,7 +3293,7 @@ SMB2_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
                        cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
 
        rc = SMB2_ioctl(xid, tcon, persistent_fid, volatile_fid,
-                       FSCTL_SET_COMPRESSION, true /* is_fsctl */,
+                       FSCTL_SET_COMPRESSION,
                        (char *)&fsctl_input /* data input */,
                        2 /* in data len */, CIFSMaxBufSize /* max out data */,
                        &ret_data /* out data */, NULL);
index 51c5bf4..3f740f2 100644 (file)
@@ -23,7 +23,7 @@ struct smb_rqst;
 extern int map_smb2_to_linux_error(char *buf, bool log_err);
 extern int smb2_check_message(char *buf, unsigned int length,
                              struct TCP_Server_Info *server);
-extern unsigned int smb2_calc_size(void *buf, struct TCP_Server_Info *server);
+extern unsigned int smb2_calc_size(void *buf);
 extern char *smb2_get_data_area_len(int *off, int *len,
                                    struct smb2_hdr *shdr);
 extern __le16 *cifs_convert_path_to_utf16(const char *from,
@@ -137,13 +137,13 @@ extern int SMB2_open_init(struct cifs_tcon *tcon,
 extern void SMB2_open_free(struct smb_rqst *rqst);
 extern int SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon,
                     u64 persistent_fid, u64 volatile_fid, u32 opcode,
-                    bool is_fsctl, char *in_data, u32 indatalen, u32 maxoutlen,
+                    char *in_data, u32 indatalen, u32 maxoutlen,
                     char **out_data, u32 *plen /* returned data len */);
 extern int SMB2_ioctl_init(struct cifs_tcon *tcon,
                           struct TCP_Server_Info *server,
                           struct smb_rqst *rqst,
                           u64 persistent_fid, u64 volatile_fid, u32 opcode,
-                          bool is_fsctl, char *in_data, u32 indatalen,
+                          char *in_data, u32 indatalen,
                           __u32 max_response_size);
 extern void SMB2_ioctl_free(struct smb_rqst *rqst);
 extern int SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon,
index de7aece..9a2753e 100644 (file)
@@ -194,10 +194,6 @@ smb_send_kvec(struct TCP_Server_Info *server, struct msghdr *smb_msg,
 
        *sent = 0;
 
-       smb_msg->msg_name = (struct sockaddr *) &server->dstaddr;
-       smb_msg->msg_namelen = sizeof(struct sockaddr);
-       smb_msg->msg_control = NULL;
-       smb_msg->msg_controllen = 0;
        if (server->noblocksnd)
                smb_msg->msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL;
        else
@@ -261,8 +257,8 @@ smb_rqst_len(struct TCP_Server_Info *server, struct smb_rqst *rqst)
        int nvec;
        unsigned long buflen = 0;
 
-       if (server->vals->header_preamble_size == 0 &&
-           rqst->rq_nvec >= 2 && rqst->rq_iov[0].iov_len == 4) {
+       if (!is_smb1(server) && rqst->rq_nvec >= 2 &&
+           rqst->rq_iov[0].iov_len == 4) {
                iov = &rqst->rq_iov[1];
                nvec = rqst->rq_nvec - 1;
        } else {
@@ -309,7 +305,7 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
        sigset_t mask, oldmask;
        size_t total_len = 0, sent, size;
        struct socket *ssocket = server->ssocket;
-       struct msghdr smb_msg;
+       struct msghdr smb_msg = {};
        __be32 rfc1002_marker;
 
        if (cifs_rdma_enabled(server)) {
@@ -346,7 +342,7 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
        sigprocmask(SIG_BLOCK, &mask, &oldmask);
 
        /* Generate a rfc1002 marker for SMB2+ */
-       if (server->vals->header_preamble_size == 0) {
+       if (!is_smb1(server)) {
                struct kvec hiov = {
                        .iov_base = &rfc1002_marker,
                        .iov_len  = 4
@@ -1238,7 +1234,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
                buf = (char *)midQ[i]->resp_buf;
                resp_iov[i].iov_base = buf;
                resp_iov[i].iov_len = midQ[i]->resp_buf_size +
-                       server->vals->header_preamble_size;
+                       HEADER_PREAMBLE_SIZE(server);
 
                if (midQ[i]->large_buf)
                        resp_buf_type[i] = CIFS_LARGE_BUFFER;
@@ -1643,7 +1639,7 @@ int
 cifs_discard_remaining_data(struct TCP_Server_Info *server)
 {
        unsigned int rfclen = server->pdu_size;
-       int remaining = rfclen + server->vals->header_preamble_size -
+       int remaining = rfclen + HEADER_PREAMBLE_SIZE(server) -
                server->total_read;
 
        while (remaining > 0) {
@@ -1689,8 +1685,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
        unsigned int data_offset, data_len;
        struct cifs_readdata *rdata = mid->callback_data;
        char *buf = server->smallbuf;
-       unsigned int buflen = server->pdu_size +
-               server->vals->header_preamble_size;
+       unsigned int buflen = server->pdu_size + HEADER_PREAMBLE_SIZE(server);
        bool use_rdma_mr = false;
 
        cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n",
@@ -1724,10 +1719,10 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 
        /* set up first two iov for signature check and to get credits */
        rdata->iov[0].iov_base = buf;
-       rdata->iov[0].iov_len = server->vals->header_preamble_size;
-       rdata->iov[1].iov_base = buf + server->vals->header_preamble_size;
+       rdata->iov[0].iov_len = HEADER_PREAMBLE_SIZE(server);
+       rdata->iov[1].iov_base = buf + HEADER_PREAMBLE_SIZE(server);
        rdata->iov[1].iov_len =
-               server->total_read - server->vals->header_preamble_size;
+               server->total_read - HEADER_PREAMBLE_SIZE(server);
        cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
                 rdata->iov[0].iov_base, rdata->iov[0].iov_len);
        cifs_dbg(FYI, "1: iov_base=%p iov_len=%zu\n",
@@ -1752,7 +1747,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
        }
 
        data_offset = server->ops->read_data_offset(buf) +
-               server->vals->header_preamble_size;
+               HEADER_PREAMBLE_SIZE(server);
        if (data_offset < server->total_read) {
                /*
                 * win2k8 sometimes sends an offset of 0 when the read
index c5dc32a..bb0c4d0 100644 (file)
@@ -2270,6 +2270,48 @@ bool d_same_name(const struct dentry *dentry, const struct dentry *parent,
 }
 EXPORT_SYMBOL_GPL(d_same_name);
 
+/*
+ * This is __d_lookup_rcu() when the parent dentry has
+ * DCACHE_OP_COMPARE, which makes things much nastier.
+ */
+static noinline struct dentry *__d_lookup_rcu_op_compare(
+       const struct dentry *parent,
+       const struct qstr *name,
+       unsigned *seqp)
+{
+       u64 hashlen = name->hash_len;
+       struct hlist_bl_head *b = d_hash(hashlen_hash(hashlen));
+       struct hlist_bl_node *node;
+       struct dentry *dentry;
+
+       hlist_bl_for_each_entry_rcu(dentry, node, b, d_hash) {
+               int tlen;
+               const char *tname;
+               unsigned seq;
+
+seqretry:
+               seq = raw_seqcount_begin(&dentry->d_seq);
+               if (dentry->d_parent != parent)
+                       continue;
+               if (d_unhashed(dentry))
+                       continue;
+               if (dentry->d_name.hash != hashlen_hash(hashlen))
+                       continue;
+               tlen = dentry->d_name.len;
+               tname = dentry->d_name.name;
+               /* we want a consistent (name,len) pair */
+               if (read_seqcount_retry(&dentry->d_seq, seq)) {
+                       cpu_relax();
+                       goto seqretry;
+               }
+               if (parent->d_op->d_compare(dentry, tlen, tname, name) != 0)
+                       continue;
+               *seqp = seq;
+               return dentry;
+       }
+       return NULL;
+}
+
 /**
  * __d_lookup_rcu - search for a dentry (racy, store-free)
  * @parent: parent dentry
@@ -2316,6 +2358,9 @@ struct dentry *__d_lookup_rcu(const struct dentry *parent,
         * Keep the two functions in sync.
         */
 
+       if (unlikely(parent->d_flags & DCACHE_OP_COMPARE))
+               return __d_lookup_rcu_op_compare(parent, name, seqp);
+
        /*
         * The hash list is protected using RCU.
         *
@@ -2332,7 +2377,6 @@ struct dentry *__d_lookup_rcu(const struct dentry *parent,
        hlist_bl_for_each_entry_rcu(dentry, node, b, d_hash) {
                unsigned seq;
 
-seqretry:
                /*
                 * The dentry sequence count protects us from concurrent
                 * renames, and thus protects parent and name fields.
@@ -2355,28 +2399,10 @@ seqretry:
                        continue;
                if (d_unhashed(dentry))
                        continue;
-
-               if (unlikely(parent->d_flags & DCACHE_OP_COMPARE)) {
-                       int tlen;
-                       const char *tname;
-                       if (dentry->d_name.hash != hashlen_hash(hashlen))
-                               continue;
-                       tlen = dentry->d_name.len;
-                       tname = dentry->d_name.name;
-                       /* we want a consistent (name,len) pair */
-                       if (read_seqcount_retry(&dentry->d_seq, seq)) {
-                               cpu_relax();
-                               goto seqretry;
-                       }
-                       if (parent->d_op->d_compare(dentry,
-                                                   tlen, tname, name) != 0)
-                               continue;
-               } else {
-                       if (dentry->d_name.hash_len != hashlen)
-                               continue;
-                       if (dentry_cmp(dentry, str, hashlen_len(hashlen)) != 0)
-                               continue;
-               }
+               if (dentry->d_name.hash_len != hashlen)
+                       continue;
+               if (dentry_cmp(dentry, str, hashlen_len(hashlen)) != 0)
+                       continue;
                *seqp = seq;
                return dentry;
        }
index 3dcf0b8..232cfdf 100644 (file)
@@ -745,6 +745,28 @@ void debugfs_remove(struct dentry *dentry)
 EXPORT_SYMBOL_GPL(debugfs_remove);
 
 /**
+ * debugfs_lookup_and_remove - lookup a directory or file and recursively remove it
+ * @name: a pointer to a string containing the name of the item to look up.
+ * @parent: a pointer to the parent dentry of the item.
+ *
+ * This is the equlivant of doing something like
+ * debugfs_remove(debugfs_lookup(..)) but with the proper reference counting
+ * handled for the directory being looked up.
+ */
+void debugfs_lookup_and_remove(const char *name, struct dentry *parent)
+{
+       struct dentry *dentry;
+
+       dentry = debugfs_lookup(name, parent);
+       if (!dentry)
+               return;
+
+       debugfs_remove(dentry);
+       dput(dentry);
+}
+EXPORT_SYMBOL_GPL(debugfs_lookup_and_remove);
+
+/**
  * debugfs_rename - rename a file/directory in the debugfs filesystem
  * @old_dir: a pointer to the parent dentry for the renamed object. This
  *          should be a directory dentry.
index 8e01d89..b5fd9d7 100644 (file)
@@ -222,8 +222,10 @@ static int erofs_fscache_meta_read_folio(struct file *data, struct folio *folio)
 
        rreq = erofs_fscache_alloc_request(folio_mapping(folio),
                                folio_pos(folio), folio_size(folio));
-       if (IS_ERR(rreq))
+       if (IS_ERR(rreq)) {
+               ret = PTR_ERR(rreq);
                goto out;
+       }
 
        return erofs_fscache_read_folios_async(mdev.m_fscache->cookie,
                                rreq, mdev.m_pa);
@@ -301,8 +303,10 @@ static int erofs_fscache_read_folio(struct file *file, struct folio *folio)
 
        rreq = erofs_fscache_alloc_request(folio_mapping(folio),
                                folio_pos(folio), folio_size(folio));
-       if (IS_ERR(rreq))
+       if (IS_ERR(rreq)) {
+               ret = PTR_ERR(rreq);
                goto out_unlock;
+       }
 
        pstart = mdev.m_pa + (pos - map.m_la);
        return erofs_fscache_read_folios_async(mdev.m_fscache->cookie,
index cfee49d..a01cc82 100644 (file)
@@ -195,7 +195,6 @@ struct erofs_workgroup {
        atomic_t refcount;
 };
 
-#if defined(CONFIG_SMP)
 static inline bool erofs_workgroup_try_to_freeze(struct erofs_workgroup *grp,
                                                 int val)
 {
@@ -224,34 +223,6 @@ static inline int erofs_wait_on_workgroup_freezed(struct erofs_workgroup *grp)
        return atomic_cond_read_relaxed(&grp->refcount,
                                        VAL != EROFS_LOCKED_MAGIC);
 }
-#else
-static inline bool erofs_workgroup_try_to_freeze(struct erofs_workgroup *grp,
-                                                int val)
-{
-       preempt_disable();
-       /* no need to spin on UP platforms, let's just disable preemption. */
-       if (val != atomic_read(&grp->refcount)) {
-               preempt_enable();
-               return false;
-       }
-       return true;
-}
-
-static inline void erofs_workgroup_unfreeze(struct erofs_workgroup *grp,
-                                           int orig_val)
-{
-       preempt_enable();
-}
-
-static inline int erofs_wait_on_workgroup_freezed(struct erofs_workgroup *grp)
-{
-       int v = atomic_read(&grp->refcount);
-
-       /* workgroup is never freezed on uniprocessor systems */
-       DBG_BUGON(v == EROFS_LOCKED_MAGIC);
-       return v;
-}
-#endif /* !CONFIG_SMP */
 #endif /* !CONFIG_EROFS_FS_ZIP */
 
 /* we strictly follow PAGE_SIZE and no buffer head yet */
index 572f0b8..d58549c 100644 (file)
@@ -141,7 +141,7 @@ struct z_erofs_maprecorder {
        u8  type, headtype;
        u16 clusterofs;
        u16 delta[2];
-       erofs_blk_t pblk, compressedlcs;
+       erofs_blk_t pblk, compressedblks;
        erofs_off_t nextpackoff;
 };
 
@@ -192,7 +192,7 @@ static int legacy_load_cluster_from_disk(struct z_erofs_maprecorder *m,
                                DBG_BUGON(1);
                                return -EFSCORRUPTED;
                        }
-                       m->compressedlcs = m->delta[0] &
+                       m->compressedblks = m->delta[0] &
                                ~Z_EROFS_VLE_DI_D0_CBLKCNT;
                        m->delta[0] = 1;
                }
@@ -293,7 +293,7 @@ static int unpack_compacted_index(struct z_erofs_maprecorder *m,
                                DBG_BUGON(1);
                                return -EFSCORRUPTED;
                        }
-                       m->compressedlcs = lo & ~Z_EROFS_VLE_DI_D0_CBLKCNT;
+                       m->compressedblks = lo & ~Z_EROFS_VLE_DI_D0_CBLKCNT;
                        m->delta[0] = 1;
                        return 0;
                } else if (i + 1 != (int)vcnt) {
@@ -497,7 +497,7 @@ static int z_erofs_get_extent_compressedlen(struct z_erofs_maprecorder *m,
                return 0;
        }
        lcn = m->lcn + 1;
-       if (m->compressedlcs)
+       if (m->compressedblks)
                goto out;
 
        err = z_erofs_load_cluster_from_disk(m, lcn, false);
@@ -506,7 +506,7 @@ static int z_erofs_get_extent_compressedlen(struct z_erofs_maprecorder *m,
 
        /*
         * If the 1st NONHEAD lcluster has already been handled initially w/o
-        * valid compressedlcs, which means at least it mustn't be CBLKCNT, or
+        * valid compressedblks, which means at least it mustn't be CBLKCNT, or
         * an internal implemenatation error is detected.
         *
         * The following code can also handle it properly anyway, but let's
@@ -523,12 +523,12 @@ static int z_erofs_get_extent_compressedlen(struct z_erofs_maprecorder *m,
                 * if the 1st NONHEAD lcluster is actually PLAIN or HEAD type
                 * rather than CBLKCNT, it's a 1 lcluster-sized pcluster.
                 */
-               m->compressedlcs = 1;
+               m->compressedblks = 1 << (lclusterbits - LOG_BLOCK_SIZE);
                break;
        case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD:
                if (m->delta[0] != 1)
                        goto err_bonus_cblkcnt;
-               if (m->compressedlcs)
+               if (m->compressedblks)
                        break;
                fallthrough;
        default:
@@ -539,7 +539,7 @@ static int z_erofs_get_extent_compressedlen(struct z_erofs_maprecorder *m,
                return -EFSCORRUPTED;
        }
 out:
-       map->m_plen = (u64)m->compressedlcs << lclusterbits;
+       map->m_plen = (u64)m->compressedblks << LOG_BLOCK_SIZE;
        return 0;
 err_bonus_cblkcnt:
        erofs_err(m->inode->i_sb,
index f793221..d046dbb 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -65,7 +65,6 @@
 #include <linux/io_uring.h>
 #include <linux/syscall_user_dispatch.h>
 #include <linux/coredump.h>
-#include <linux/time_namespace.h>
 
 #include <linux/uaccess.h>
 #include <asm/mmu_context.h>
@@ -584,11 +583,11 @@ static int copy_strings(int argc, struct user_arg_ptr argv,
 
                                if (kmapped_page) {
                                        flush_dcache_page(kmapped_page);
-                                       kunmap(kmapped_page);
+                                       kunmap_local(kaddr);
                                        put_arg_page(kmapped_page);
                                }
                                kmapped_page = page;
-                               kaddr = kmap(kmapped_page);
+                               kaddr = kmap_local_page(kmapped_page);
                                kpos = pos & PAGE_MASK;
                                flush_arg_page(bprm, kpos, kmapped_page);
                        }
@@ -602,7 +601,7 @@ static int copy_strings(int argc, struct user_arg_ptr argv,
 out:
        if (kmapped_page) {
                flush_dcache_page(kmapped_page);
-               kunmap(kmapped_page);
+               kunmap_local(kaddr);
                put_arg_page(kmapped_page);
        }
        return ret;
@@ -880,11 +879,11 @@ int transfer_args_to_stack(struct linux_binprm *bprm,
 
        for (index = MAX_ARG_PAGES - 1; index >= stop; index--) {
                unsigned int offset = index == stop ? bprm->p & ~PAGE_MASK : 0;
-               char *src = kmap(bprm->page[index]) + offset;
+               char *src = kmap_local_page(bprm->page[index]) + offset;
                sp -= PAGE_SIZE - offset;
                if (copy_to_user((void *) sp, src, PAGE_SIZE - offset) != 0)
                        ret = -EFAULT;
-               kunmap(bprm->page[index]);
+               kunmap_local(src);
                if (ret)
                        goto out;
        }
@@ -979,12 +978,10 @@ static int exec_mmap(struct mm_struct *mm)
 {
        struct task_struct *tsk;
        struct mm_struct *old_mm, *active_mm;
-       bool vfork;
        int ret;
 
        /* Notify parent that we're no longer interested in the old VM */
        tsk = current;
-       vfork = !!tsk->vfork_done;
        old_mm = current->mm;
        exec_mm_release(tsk, old_mm);
        if (old_mm)
@@ -1029,10 +1026,6 @@ static int exec_mmap(struct mm_struct *mm)
        tsk->mm->vmacache_seqnum = 0;
        vmacache_flush(tsk);
        task_unlock(tsk);
-
-       if (vfork)
-               timens_on_fork(tsk->nsproxy, tsk);
-
        if (old_mm) {
                mmap_read_unlock(old_mm);
                BUG_ON(active_mm != old_mm);
@@ -1686,13 +1679,13 @@ int remove_arg_zero(struct linux_binprm *bprm)
                        ret = -EFAULT;
                        goto out;
                }
-               kaddr = kmap_atomic(page);
+               kaddr = kmap_local_page(page);
 
                for (; offset < PAGE_SIZE && kaddr[offset];
                                offset++, bprm->p++)
                        ;
 
-               kunmap_atomic(kaddr);
+               kunmap_local(kaddr);
                put_arg_page(page);
        } while (offset == PAGE_SIZE);
 
index ee0b7cf..41ae4cc 100644 (file)
@@ -270,8 +270,7 @@ int exfat_zeroed_cluster(struct inode *dir, unsigned int clu)
        struct super_block *sb = dir->i_sb;
        struct exfat_sb_info *sbi = EXFAT_SB(sb);
        struct buffer_head *bh;
-       sector_t blknr, last_blknr;
-       int i;
+       sector_t blknr, last_blknr, i;
 
        blknr = exfat_cluster_to_sector(sbi, clu);
        last_blknr = blknr + sbi->sect_per_clus;
index 0522136..08a1993 100644 (file)
@@ -134,10 +134,10 @@ static bool inode_io_list_move_locked(struct inode *inode,
 
 static void wb_wakeup(struct bdi_writeback *wb)
 {
-       spin_lock_bh(&wb->work_lock);
+       spin_lock_irq(&wb->work_lock);
        if (test_bit(WB_registered, &wb->state))
                mod_delayed_work(bdi_wq, &wb->dwork, 0);
-       spin_unlock_bh(&wb->work_lock);
+       spin_unlock_irq(&wb->work_lock);
 }
 
 static void finish_writeback_work(struct bdi_writeback *wb,
@@ -164,7 +164,7 @@ static void wb_queue_work(struct bdi_writeback *wb,
        if (work->done)
                atomic_inc(&work->done->cnt);
 
-       spin_lock_bh(&wb->work_lock);
+       spin_lock_irq(&wb->work_lock);
 
        if (test_bit(WB_registered, &wb->state)) {
                list_add_tail(&work->list, &wb->work_list);
@@ -172,7 +172,7 @@ static void wb_queue_work(struct bdi_writeback *wb,
        } else
                finish_writeback_work(wb, work);
 
-       spin_unlock_bh(&wb->work_lock);
+       spin_unlock_irq(&wb->work_lock);
 }
 
 /**
@@ -2082,13 +2082,13 @@ static struct wb_writeback_work *get_next_work_item(struct bdi_writeback *wb)
 {
        struct wb_writeback_work *work = NULL;
 
-       spin_lock_bh(&wb->work_lock);
+       spin_lock_irq(&wb->work_lock);
        if (!list_empty(&wb->work_list)) {
                work = list_entry(wb->work_list.next,
                                  struct wb_writeback_work, list);
                list_del_init(&work->list);
        }
-       spin_unlock_bh(&wb->work_lock);
+       spin_unlock_irq(&wb->work_lock);
        return work;
 }
 
index 6462276..ba1de23 100644 (file)
@@ -2018,23 +2018,25 @@ static int __file_remove_privs(struct file *file, unsigned int flags)
 {
        struct dentry *dentry = file_dentry(file);
        struct inode *inode = file_inode(file);
-       int error;
+       int error = 0;
        int kill;
 
        if (IS_NOSEC(inode) || !S_ISREG(inode->i_mode))
                return 0;
 
        kill = dentry_needs_remove_privs(dentry);
-       if (kill <= 0)
+       if (kill < 0)
                return kill;
 
-       if (flags & IOCB_NOWAIT)
-               return -EAGAIN;
+       if (kill) {
+               if (flags & IOCB_NOWAIT)
+                       return -EAGAIN;
+
+               error = __remove_privs(file_mnt_user_ns(file), dentry, kill);
+       }
 
-       error = __remove_privs(file_mnt_user_ns(file), dentry, kill);
        if (!error)
                inode_has_no_xattr(inode);
-
        return error;
 }
 
index 52aa0ad..e0cbcfa 100644 (file)
@@ -349,6 +349,7 @@ enum KSMBD_TREE_CONN_STATUS {
 #define KSMBD_SHARE_FLAG_STREAMS               BIT(11)
 #define KSMBD_SHARE_FLAG_FOLLOW_SYMLINKS       BIT(12)
 #define KSMBD_SHARE_FLAG_ACL_XATTR             BIT(13)
+#define KSMBD_SHARE_FLAG_UPDATE                BIT(14)
 
 /*
  * Tree connect request flags.
@@ -364,6 +365,7 @@ enum KSMBD_TREE_CONN_STATUS {
 #define KSMBD_TREE_CONN_FLAG_READ_ONLY         BIT(1)
 #define KSMBD_TREE_CONN_FLAG_WRITABLE          BIT(2)
 #define KSMBD_TREE_CONN_FLAG_ADMIN_ACCOUNT     BIT(3)
+#define KSMBD_TREE_CONN_FLAG_UPDATE            BIT(4)
 
 /*
  * RPC over IPC.
index 70655af..c9bca1c 100644 (file)
@@ -51,12 +51,16 @@ static void kill_share(struct ksmbd_share_config *share)
        kfree(share);
 }
 
-void __ksmbd_share_config_put(struct ksmbd_share_config *share)
+void ksmbd_share_config_del(struct ksmbd_share_config *share)
 {
        down_write(&shares_table_lock);
        hash_del(&share->hlist);
        up_write(&shares_table_lock);
+}
 
+void __ksmbd_share_config_put(struct ksmbd_share_config *share)
+{
+       ksmbd_share_config_del(share);
        kill_share(share);
 }
 
index 28bf351..902f2cb 100644 (file)
@@ -64,6 +64,7 @@ static inline int test_share_config_flag(struct ksmbd_share_config *share,
        return share->flags & flag;
 }
 
+void ksmbd_share_config_del(struct ksmbd_share_config *share);
 void __ksmbd_share_config_put(struct ksmbd_share_config *share);
 
 static inline void ksmbd_share_config_put(struct ksmbd_share_config *share)
index b35ea6a..97ab798 100644 (file)
@@ -19,7 +19,7 @@ struct ksmbd_tree_conn_status
 ksmbd_tree_conn_connect(struct ksmbd_conn *conn, struct ksmbd_session *sess,
                        char *share_name)
 {
-       struct ksmbd_tree_conn_status status = {-EINVAL, NULL};
+       struct ksmbd_tree_conn_status status = {-ENOENT, NULL};
        struct ksmbd_tree_connect_response *resp = NULL;
        struct ksmbd_share_config *sc;
        struct ksmbd_tree_connect *tree_conn = NULL;
@@ -57,6 +57,20 @@ ksmbd_tree_conn_connect(struct ksmbd_conn *conn, struct ksmbd_session *sess,
                goto out_error;
 
        tree_conn->flags = resp->connection_flags;
+       if (test_tree_conn_flag(tree_conn, KSMBD_TREE_CONN_FLAG_UPDATE)) {
+               struct ksmbd_share_config *new_sc;
+
+               ksmbd_share_config_del(sc);
+               new_sc = ksmbd_share_config_get(share_name);
+               if (!new_sc) {
+                       pr_err("Failed to update stale share config\n");
+                       status.ret = -ESTALE;
+                       goto out_error;
+               }
+               ksmbd_share_config_put(sc);
+               sc = new_sc;
+       }
+
        tree_conn->user = sess->user;
        tree_conn->share_conf = sc;
        status.tree_conn = tree_conn;
index 9751cc9..19412ac 100644 (file)
@@ -1944,8 +1944,10 @@ out_err1:
                rsp->hdr.Status = STATUS_SUCCESS;
                rc = 0;
                break;
+       case -ESTALE:
+       case -ENOENT:
        case KSMBD_TREE_CONN_STATUS_NO_SHARE:
-               rsp->hdr.Status = STATUS_BAD_NETWORK_PATH;
+               rsp->hdr.Status = STATUS_BAD_NETWORK_NAME;
                break;
        case -ENOMEM:
        case KSMBD_TREE_CONN_STATUS_NOMEM:
@@ -2328,15 +2330,15 @@ static int smb2_remove_smb_xattrs(struct path *path)
                        name += strlen(name) + 1) {
                ksmbd_debug(SMB, "%s, len %zd\n", name, strlen(name));
 
-               if (strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) &&
-                   strncmp(&name[XATTR_USER_PREFIX_LEN], DOS_ATTRIBUTE_PREFIX,
-                           DOS_ATTRIBUTE_PREFIX_LEN) &&
-                   strncmp(&name[XATTR_USER_PREFIX_LEN], STREAM_PREFIX, STREAM_PREFIX_LEN))
-                       continue;
-
-               err = ksmbd_vfs_remove_xattr(user_ns, path->dentry, name);
-               if (err)
-                       ksmbd_debug(SMB, "remove xattr failed : %s\n", name);
+               if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) &&
+                   !strncmp(&name[XATTR_USER_PREFIX_LEN], STREAM_PREFIX,
+                            STREAM_PREFIX_LEN)) {
+                       err = ksmbd_vfs_remove_xattr(user_ns, path->dentry,
+                                                    name);
+                       if (err)
+                               ksmbd_debug(SMB, "remove xattr failed : %s\n",
+                                           name);
+               }
        }
 out:
        kvfree(xattr_list);
@@ -3042,12 +3044,6 @@ int smb2_open(struct ksmbd_work *work)
        list_add(&fp->node, &fp->f_ci->m_fp_list);
        write_unlock(&fp->f_ci->m_lock);
 
-       rc = ksmbd_vfs_getattr(&path, &stat);
-       if (rc) {
-               generic_fillattr(user_ns, d_inode(path.dentry), &stat);
-               rc = 0;
-       }
-
        /* Check delete pending among previous fp before oplock break */
        if (ksmbd_inode_pending_delete(fp)) {
                rc = -EBUSY;
@@ -3134,6 +3130,10 @@ int smb2_open(struct ksmbd_work *work)
                }
        }
 
+       rc = ksmbd_vfs_getattr(&path, &stat);
+       if (rc)
+               goto err_out;
+
        if (stat.result_mask & STATX_BTIME)
                fp->create_time = ksmbd_UnixTimeToNT(stat.btime);
        else
@@ -3149,9 +3149,6 @@ int smb2_open(struct ksmbd_work *work)
 
        memcpy(fp->client_guid, conn->ClientGUID, SMB2_CLIENT_GUID_SIZE);
 
-       generic_fillattr(user_ns, file_inode(fp->filp),
-                        &stat);
-
        rsp->StructureSize = cpu_to_le16(89);
        rcu_read_lock();
        opinfo = rcu_dereference(fp->f_opinfo);
index c266cfd..607f94a 100644 (file)
@@ -2129,6 +2129,7 @@ SYSCALL_DEFINE2(flock, unsigned int, fd, unsigned int, cmd)
        else
                error = locks_lock_file_wait(f.file, &fl);
 
+       locks_release_private(&fl);
  out_putf:
        fdput(f);
 
index 68789f8..df137ba 100644 (file)
@@ -4238,6 +4238,13 @@ static int build_mount_idmapped(const struct mount_attr *attr, size_t usize,
                err = -EPERM;
                goto out_fput;
        }
+
+       /* We're not controlling the target namespace. */
+       if (!ns_capable(mnt_userns, CAP_SYS_ADMIN)) {
+               err = -EPERM;
+               goto out_fput;
+       }
+
        kattr->mnt_userns = get_user_ns(mnt_userns);
 
 out_fput:
index dbab3ca..5d6c2dd 100644 (file)
@@ -2382,7 +2382,8 @@ static void nfs_dentry_remove_handle_error(struct inode *dir,
 {
        switch (error) {
        case -ENOENT:
-               d_delete(dentry);
+               if (d_really_is_positive(dentry))
+                       d_delete(dentry);
                nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
                break;
        case 0:
@@ -2484,8 +2485,10 @@ int nfs_unlink(struct inode *dir, struct dentry *dentry)
         */
        error = -ETXTBSY;
        if (WARN_ON(dentry->d_flags & DCACHE_NFSFS_RENAMED) ||
-           WARN_ON(dentry->d_fsdata == NFS_FSDATA_BLOCKED))
+           WARN_ON(dentry->d_fsdata == NFS_FSDATA_BLOCKED)) {
+               spin_unlock(&dentry->d_lock);
                goto out;
+       }
        if (dentry->d_fsdata)
                /* old devname */
                kfree(dentry->d_fsdata);
index d2bcd48..e032fe2 100644 (file)
@@ -221,8 +221,10 @@ nfs_file_fsync_commit(struct file *file, int datasync)
 int
 nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)
 {
-       struct nfs_open_context *ctx = nfs_file_open_context(file);
        struct inode *inode = file_inode(file);
+       struct nfs_inode *nfsi = NFS_I(inode);
+       long save_nredirtied = atomic_long_read(&nfsi->redirtied_pages);
+       long nredirtied;
        int ret;
 
        trace_nfs_fsync_enter(inode);
@@ -237,15 +239,10 @@ nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)
                ret = pnfs_sync_inode(inode, !!datasync);
                if (ret != 0)
                        break;
-               if (!test_and_clear_bit(NFS_CONTEXT_RESEND_WRITES, &ctx->flags))
+               nredirtied = atomic_long_read(&nfsi->redirtied_pages);
+               if (nredirtied == save_nredirtied)
                        break;
-               /*
-                * If nfs_file_fsync_commit detected a server reboot, then
-                * resend all dirty pages that might have been covered by
-                * the NFS_CONTEXT_RESEND_WRITES flag
-                */
-               start = 0;
-               end = LLONG_MAX;
+               save_nredirtied = nredirtied;
        }
 
        trace_nfs_fsync_exit(inode, ret);
index b4e46b0..bea7c00 100644 (file)
@@ -426,6 +426,7 @@ nfs_ilookup(struct super_block *sb, struct nfs_fattr *fattr, struct nfs_fh *fh)
 static void nfs_inode_init_regular(struct nfs_inode *nfsi)
 {
        atomic_long_set(&nfsi->nrequests, 0);
+       atomic_long_set(&nfsi->redirtied_pages, 0);
        INIT_LIST_HEAD(&nfsi->commit_info.list);
        atomic_long_set(&nfsi->commit_info.ncommit, 0);
        atomic_set(&nfsi->commit_info.rpcs_out, 0);
index 27c720d..898dd95 100644 (file)
@@ -606,6 +606,31 @@ static inline gfp_t nfs_io_gfp_mask(void)
        return GFP_KERNEL;
 }
 
+/*
+ * Special version of should_remove_suid() that ignores capabilities.
+ */
+static inline int nfs_should_remove_suid(const struct inode *inode)
+{
+       umode_t mode = inode->i_mode;
+       int kill = 0;
+
+       /* suid always must be killed */
+       if (unlikely(mode & S_ISUID))
+               kill = ATTR_KILL_SUID;
+
+       /*
+        * sgid without any exec bits is just a mandatory locking mark; leave
+        * it alone.  If some exec bits are set, it's a real sgid; kill it.
+        */
+       if (unlikely((mode & S_ISGID) && (mode & S_IXGRP)))
+               kill |= ATTR_KILL_SGID;
+
+       if (unlikely(kill && S_ISREG(mode)))
+               return kill;
+
+       return 0;
+}
+
 /* unlink.c */
 extern struct rpc_task *
 nfs_async_rename(struct inode *old_dir, struct inode *new_dir,
index 068c45b..6dab9e4 100644 (file)
@@ -78,10 +78,15 @@ static int _nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep,
 
        status = nfs4_call_sync(server->client, server, msg,
                                &args.seq_args, &res.seq_res, 0);
-       if (status == 0)
+       if (status == 0) {
+               if (nfs_should_remove_suid(inode)) {
+                       spin_lock(&inode->i_lock);
+                       nfs_set_cache_invalid(inode, NFS_INO_INVALID_MODE);
+                       spin_unlock(&inode->i_lock);
+               }
                status = nfs_post_op_update_inode_force_wcc(inode,
                                                            res.falloc_fattr);
-
+       }
        if (msg->rpc_proc == &nfs4_procedures[NFSPROC4_CLNT_ALLOCATE])
                trace_nfs4_fallocate(inode, &args, status);
        else
index e88f6b1..9eb1812 100644 (file)
@@ -340,6 +340,11 @@ static struct file *__nfs42_ssc_open(struct vfsmount *ss_mnt,
                goto out;
        }
 
+       if (!S_ISREG(fattr->mode)) {
+               res = ERR_PTR(-EBADF);
+               goto out;
+       }
+
        res = ERR_PTR(-ENOMEM);
        len = strlen(SSC_READ_NAME_BODY) + 16;
        read_name = kzalloc(len, GFP_KERNEL);
@@ -357,6 +362,7 @@ static struct file *__nfs42_ssc_open(struct vfsmount *ss_mnt,
                                     r_ino->i_fop);
        if (IS_ERR(filep)) {
                res = ERR_CAST(filep);
+               iput(r_ino);
                goto out_free_name;
        }
 
index 41a9b6b..2613b7e 100644 (file)
@@ -2817,7 +2817,6 @@ int pnfs_write_done_resend_to_mds(struct nfs_pgio_header *hdr)
        /* Resend all requests through the MDS */
        nfs_pageio_init_write(&pgio, hdr->inode, FLUSH_STABLE, true,
                              hdr->completion_ops);
-       set_bit(NFS_CONTEXT_RESEND_WRITES, &hdr->args.context->flags);
        return nfs_pageio_resend(&pgio, hdr);
 }
 EXPORT_SYMBOL_GPL(pnfs_write_done_resend_to_mds);
index 82944e1..ee66ffd 100644 (file)
@@ -1051,22 +1051,31 @@ static void nfs_fill_super(struct super_block *sb, struct nfs_fs_context *ctx)
        if (ctx->bsize)
                sb->s_blocksize = nfs_block_size(ctx->bsize, &sb->s_blocksize_bits);
 
-       if (server->nfs_client->rpc_ops->version != 2) {
-               /* The VFS shouldn't apply the umask to mode bits. We will do
-                * so ourselves when necessary.
+       switch (server->nfs_client->rpc_ops->version) {
+       case 2:
+               sb->s_time_gran = 1000;
+               sb->s_time_min = 0;
+               sb->s_time_max = U32_MAX;
+               break;
+       case 3:
+               /*
+                * The VFS shouldn't apply the umask to mode bits.
+                * We will do so ourselves when necessary.
                 */
                sb->s_flags |= SB_POSIXACL;
                sb->s_time_gran = 1;
-               sb->s_export_op = &nfs_export_ops;
-       } else
-               sb->s_time_gran = 1000;
-
-       if (server->nfs_client->rpc_ops->version != 4) {
                sb->s_time_min = 0;
                sb->s_time_max = U32_MAX;
-       } else {
+               sb->s_export_op = &nfs_export_ops;
+               break;
+       case 4:
+               sb->s_flags |= SB_POSIXACL;
+               sb->s_time_gran = 1;
                sb->s_time_min = S64_MIN;
                sb->s_time_max = S64_MAX;
+               if (server->caps & NFS_CAP_ATOMIC_OPEN_V1)
+                       sb->s_export_op = &nfs_export_ops;
+               break;
        }
 
        sb->s_magic = NFS_SUPER_MAGIC;
index 51a7e20..f41d24b 100644 (file)
@@ -1420,10 +1420,12 @@ static void nfs_initiate_write(struct nfs_pgio_header *hdr,
  */
 static void nfs_redirty_request(struct nfs_page *req)
 {
+       struct nfs_inode *nfsi = NFS_I(page_file_mapping(req->wb_page)->host);
+
        /* Bump the transmission count */
        req->wb_nio++;
        nfs_mark_request_dirty(req);
-       set_bit(NFS_CONTEXT_RESEND_WRITES, &nfs_req_openctx(req)->flags);
+       atomic_long_inc(&nfsi->redirtied_pages);
        nfs_end_page_writeback(req);
        nfs_release_request(req);
 }
@@ -1494,31 +1496,6 @@ void nfs_commit_prepare(struct rpc_task *task, void *calldata)
        NFS_PROTO(data->inode)->commit_rpc_prepare(task, data);
 }
 
-/*
- * Special version of should_remove_suid() that ignores capabilities.
- */
-static int nfs_should_remove_suid(const struct inode *inode)
-{
-       umode_t mode = inode->i_mode;
-       int kill = 0;
-
-       /* suid always must be killed */
-       if (unlikely(mode & S_ISUID))
-               kill = ATTR_KILL_SUID;
-
-       /*
-        * sgid without any exec bits is just a mandatory locking mark; leave
-        * it alone.  If some exec bits are set, it's a real sgid; kill it.
-        */
-       if (unlikely((mode & S_ISGID) && (mode & S_IXGRP)))
-               kill |= ATTR_KILL_SGID;
-
-       if (unlikely(kill && S_ISREG(mode)))
-               return kill;
-
-       return 0;
-}
-
 static void nfs_writeback_check_extend(struct nfs_pgio_header *hdr,
                struct nfs_fattr *fattr)
 {
@@ -1904,7 +1881,7 @@ static void nfs_commit_release_pages(struct nfs_commit_data *data)
                /* We have a mismatch. Write the page again */
                dprintk_cont(" mismatch\n");
                nfs_mark_request_dirty(req);
-               set_bit(NFS_CONTEXT_RESEND_WRITES, &nfs_req_openctx(req)->flags);
+               atomic_long_inc(&NFS_I(data->inode)->redirtied_pages);
        next:
                nfs_unlock_and_release_request(req);
                /* Latency breaker */
index 9f486b7..fc17b0a 100644 (file)
@@ -300,6 +300,10 @@ commit_metadata(struct svc_fh *fhp)
 static void
 nfsd_sanitize_attrs(struct inode *inode, struct iattr *iap)
 {
+       /* Ignore mode updates on symlinks */
+       if (S_ISLNK(inode->i_mode))
+               iap->ia_valid &= ~ATTR_MODE;
+
        /* sanitize the mode change */
        if (iap->ia_valid & ATTR_MODE) {
                iap->ia_mode &= S_IALLUGO;
@@ -353,7 +357,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp,
        int             accmode = NFSD_MAY_SATTR;
        umode_t         ftype = 0;
        __be32          err;
-       int             host_err;
+       int             host_err = 0;
        bool            get_write_count;
        bool            size_change = (iap->ia_valid & ATTR_SIZE);
 
@@ -391,13 +395,6 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp,
        dentry = fhp->fh_dentry;
        inode = d_inode(dentry);
 
-       /* Ignore any mode updates on symlinks */
-       if (S_ISLNK(inode->i_mode))
-               iap->ia_valid &= ~ATTR_MODE;
-
-       if (!iap->ia_valid)
-               return 0;
-
        nfsd_sanitize_attrs(inode, iap);
 
        if (check_guard && guardtime != inode->i_ctime.tv_sec)
@@ -448,8 +445,10 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp,
                        goto out_unlock;
        }
 
-       iap->ia_valid |= ATTR_CTIME;
-       host_err = notify_change(&init_user_ns, dentry, iap, NULL);
+       if (iap->ia_valid) {
+               iap->ia_valid |= ATTR_CTIME;
+               host_err = notify_change(&init_user_ns, dentry, iap, NULL);
+       }
 
 out_unlock:
        if (attr->na_seclabel && attr->na_seclabel->len)
@@ -846,10 +845,14 @@ nfsd_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
                  struct splice_desc *sd)
 {
        struct svc_rqst *rqstp = sd->u.data;
-
-       svc_rqst_replace_page(rqstp, buf->page);
-       if (rqstp->rq_res.page_len == 0)
-               rqstp->rq_res.page_base = buf->offset;
+       struct page *page = buf->page;  // may be a compound one
+       unsigned offset = buf->offset;
+
+       page += offset / PAGE_SIZE;
+       for (int i = sd->len; i > 0; i -= PAGE_SIZE)
+               svc_rqst_replace_page(rqstp, page++);
+       if (rqstp->rq_res.page_len == 0)        // first call
+               rqstp->rq_res.page_base = offset % PAGE_SIZE;
        rqstp->rq_res.page_len += sd->len;
        return sd->len;
 }
index e8c00dd..71f870d 100644 (file)
@@ -84,8 +84,8 @@ static inline bool attr_must_be_resident(struct ntfs_sb_info *sbi,
 /*
  * attr_load_runs - Load all runs stored in @attr.
  */
-int attr_load_runs(struct ATTRIB *attr, struct ntfs_inode *ni,
-                  struct runs_tree *run, const CLST *vcn)
+static int attr_load_runs(struct ATTRIB *attr, struct ntfs_inode *ni,
+                         struct runs_tree *run, const CLST *vcn)
 {
        int err;
        CLST svcn = le64_to_cpu(attr->nres.svcn);
@@ -140,7 +140,10 @@ failed:
                }
 
                if (lcn != SPARSE_LCN) {
-                       mark_as_free_ex(sbi, lcn, clen, trim);
+                       if (sbi) {
+                               /* mark bitmap range [lcn + clen) as free and trim clusters. */
+                               mark_as_free_ex(sbi, lcn, clen, trim);
+                       }
                        dn += clen;
                }
 
@@ -173,7 +176,6 @@ int attr_allocate_clusters(struct ntfs_sb_info *sbi, struct runs_tree *run,
 {
        int err;
        CLST flen, vcn0 = vcn, pre = pre_alloc ? *pre_alloc : 0;
-       struct wnd_bitmap *wnd = &sbi->used.bitmap;
        size_t cnt = run->count;
 
        for (;;) {
@@ -196,9 +198,7 @@ int attr_allocate_clusters(struct ntfs_sb_info *sbi, struct runs_tree *run,
                /* Add new fragment into run storage. */
                if (!run_add_entry(run, vcn, lcn, flen, opt == ALLOCATE_MFT)) {
                        /* Undo last 'ntfs_look_for_free_space' */
-                       down_write_nested(&wnd->rw_lock, BITMAP_MUTEX_CLUSTERS);
-                       wnd_set_free(wnd, lcn, flen);
-                       up_write(&wnd->rw_lock);
+                       mark_as_free_ex(sbi, lcn, len, false);
                        err = -ENOMEM;
                        goto out;
                }
@@ -320,7 +320,7 @@ int attr_make_nonresident(struct ntfs_inode *ni, struct ATTRIB *attr,
 
        err = ni_insert_nonresident(ni, attr_s->type, attr_name(attr_s),
                                    attr_s->name_len, run, 0, alen,
-                                   attr_s->flags, &attr, NULL);
+                                   attr_s->flags, &attr, NULL, NULL);
        if (err)
                goto out3;
 
@@ -419,40 +419,44 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type,
        struct mft_inode *mi, *mi_b;
        CLST alen, vcn, lcn, new_alen, old_alen, svcn, evcn;
        CLST next_svcn, pre_alloc = -1, done = 0;
-       bool is_ext;
+       bool is_ext, is_bad = false;
        u32 align;
        struct MFT_REC *rec;
 
 again:
+       alen = 0;
        le_b = NULL;
        attr_b = ni_find_attr(ni, NULL, &le_b, type, name, name_len, NULL,
                              &mi_b);
        if (!attr_b) {
                err = -ENOENT;
-               goto out;
+               goto bad_inode;
        }
 
        if (!attr_b->non_res) {
                err = attr_set_size_res(ni, attr_b, le_b, mi_b, new_size, run,
                                        &attr_b);
-               if (err || !attr_b->non_res)
-                       goto out;
+               if (err)
+                       return err;
+
+               /* Return if file is still resident. */
+               if (!attr_b->non_res)
+                       goto ok1;
 
                /* Layout of records may be changed, so do a full search. */
                goto again;
        }
 
        is_ext = is_attr_ext(attr_b);
-
-again_1:
        align = sbi->cluster_size;
-
        if (is_ext)
                align <<= attr_b->nres.c_unit;
 
        old_valid = le64_to_cpu(attr_b->nres.valid_size);
        old_size = le64_to_cpu(attr_b->nres.data_size);
        old_alloc = le64_to_cpu(attr_b->nres.alloc_size);
+
+again_1:
        old_alen = old_alloc >> cluster_bits;
 
        new_alloc = (new_size + align - 1) & ~(u64)(align - 1);
@@ -475,24 +479,27 @@ again_1:
                mi = mi_b;
        } else if (!le_b) {
                err = -EINVAL;
-               goto out;
+               goto bad_inode;
        } else {
                le = le_b;
                attr = ni_find_attr(ni, attr_b, &le, type, name, name_len, &vcn,
                                    &mi);
                if (!attr) {
                        err = -EINVAL;
-                       goto out;
+                       goto bad_inode;
                }
 
 next_le_1:
                svcn = le64_to_cpu(attr->nres.svcn);
                evcn = le64_to_cpu(attr->nres.evcn);
        }
-
+       /*
+        * Here we have:
+        * attr,mi,le - last attribute segment (containing 'vcn').
+        * attr_b,mi_b,le_b - base (primary) attribute segment.
+        */
 next_le:
        rec = mi->mrec;
-
        err = attr_load_runs(attr, ni, run, NULL);
        if (err)
                goto out;
@@ -507,6 +514,13 @@ next_le:
                        goto ok;
                }
 
+               /*
+                * Add clusters. In simple case we have to:
+                *  - allocate space (vcn, lcn, len)
+                *  - update packed run in 'mi'
+                *  - update attr->nres.evcn
+                *  - update attr_b->nres.data_size/attr_b->nres.alloc_size
+                */
                to_allocate = new_alen - old_alen;
 add_alloc_in_same_attr_seg:
                lcn = 0;
@@ -520,9 +534,11 @@ add_alloc_in_same_attr_seg:
                        pre_alloc = 0;
                        if (type == ATTR_DATA && !name_len &&
                            sbi->options->prealloc) {
-                               CLST new_alen2 = bytes_to_cluster(
-                                       sbi, get_pre_allocated(new_size));
-                               pre_alloc = new_alen2 - new_alen;
+                               pre_alloc =
+                                       bytes_to_cluster(
+                                               sbi,
+                                               get_pre_allocated(new_size)) -
+                                       new_alen;
                        }
 
                        /* Get the last LCN to allocate from. */
@@ -580,7 +596,7 @@ add_alloc_in_same_attr_seg:
 pack_runs:
                err = mi_pack_runs(mi, attr, run, vcn - svcn);
                if (err)
-                       goto out;
+                       goto undo_1;
 
                next_svcn = le64_to_cpu(attr->nres.evcn) + 1;
                new_alloc_tmp = (u64)next_svcn << cluster_bits;
@@ -614,7 +630,7 @@ pack_runs:
                if (type == ATTR_LIST) {
                        err = ni_expand_list(ni);
                        if (err)
-                               goto out;
+                               goto undo_2;
                        if (next_svcn < vcn)
                                goto pack_runs;
 
@@ -624,8 +640,9 @@ pack_runs:
 
                if (!ni->attr_list.size) {
                        err = ni_create_attr_list(ni);
+                       /* In case of error layout of records is not changed. */
                        if (err)
-                               goto out;
+                               goto undo_2;
                        /* Layout of records is changed. */
                }
 
@@ -637,48 +654,57 @@ pack_runs:
                /* Insert new attribute segment. */
                err = ni_insert_nonresident(ni, type, name, name_len, run,
                                            next_svcn, vcn - next_svcn,
-                                           attr_b->flags, &attr, &mi);
-               if (err)
-                       goto out;
-
-               if (!is_mft)
-                       run_truncate_head(run, evcn + 1);
-
-               svcn = le64_to_cpu(attr->nres.svcn);
-               evcn = le64_to_cpu(attr->nres.evcn);
+                                           attr_b->flags, &attr, &mi, NULL);
 
-               le_b = NULL;
                /*
                 * Layout of records maybe changed.
                 * Find base attribute to update.
                 */
+               le_b = NULL;
                attr_b = ni_find_attr(ni, NULL, &le_b, type, name, name_len,
                                      NULL, &mi_b);
                if (!attr_b) {
-                       err = -ENOENT;
-                       goto out;
+                       err = -EINVAL;
+                       goto bad_inode;
                }
 
-               attr_b->nres.alloc_size = cpu_to_le64((u64)vcn << cluster_bits);
-               attr_b->nres.data_size = attr_b->nres.alloc_size;
-               attr_b->nres.valid_size = attr_b->nres.alloc_size;
+               if (err) {
+                       /* ni_insert_nonresident failed. */
+                       attr = NULL;
+                       goto undo_2;
+               }
+
+               if (!is_mft)
+                       run_truncate_head(run, evcn + 1);
+
+               svcn = le64_to_cpu(attr->nres.svcn);
+               evcn = le64_to_cpu(attr->nres.evcn);
+
+               /*
+                * Attribute is in consistency state.
+                * Save this point to restore to if next steps fail.
+                */
+               old_valid = old_size = old_alloc = (u64)vcn << cluster_bits;
+               attr_b->nres.valid_size = attr_b->nres.data_size =
+                       attr_b->nres.alloc_size = cpu_to_le64(old_size);
                mi_b->dirty = true;
                goto again_1;
        }
 
        if (new_size != old_size ||
            (new_alloc != old_alloc && !keep_prealloc)) {
+               /*
+                * Truncate clusters. In simple case we have to:
+                *  - update packed run in 'mi'
+                *  - update attr->nres.evcn
+                *  - update attr_b->nres.data_size/attr_b->nres.alloc_size
+                *  - mark and trim clusters as free (vcn, lcn, len)
+                */
+               CLST dlen = 0;
+
                vcn = max(svcn, new_alen);
                new_alloc_tmp = (u64)vcn << cluster_bits;
 
-               alen = 0;
-               err = run_deallocate_ex(sbi, run, vcn, evcn - vcn + 1, &alen,
-                                       true);
-               if (err)
-                       goto out;
-
-               run_truncate(run, vcn);
-
                if (vcn > svcn) {
                        err = mi_pack_runs(mi, attr, run, vcn - svcn);
                        if (err)
@@ -697,7 +723,7 @@ pack_runs:
 
                        if (!al_remove_le(ni, le)) {
                                err = -EINVAL;
-                               goto out;
+                               goto bad_inode;
                        }
 
                        le = (struct ATTR_LIST_ENTRY *)((u8 *)le - le_sz);
@@ -723,12 +749,20 @@ pack_runs:
                                attr_b->nres.valid_size =
                                        attr_b->nres.alloc_size;
                }
+               mi_b->dirty = true;
 
-               if (is_ext)
+               err = run_deallocate_ex(sbi, run, vcn, evcn - vcn + 1, &dlen,
+                                       true);
+               if (err)
+                       goto out;
+
+               if (is_ext) {
+                       /* dlen - really deallocated clusters. */
                        le64_sub_cpu(&attr_b->nres.total_size,
-                                    ((u64)alen << cluster_bits));
+                                    ((u64)dlen << cluster_bits));
+               }
 
-               mi_b->dirty = true;
+               run_truncate(run, vcn);
 
                if (new_alloc_tmp <= new_alloc)
                        goto ok;
@@ -747,7 +781,7 @@ pack_runs:
                if (le->type != type || le->name_len != name_len ||
                    memcmp(le_name(le), name, name_len * sizeof(short))) {
                        err = -EINVAL;
-                       goto out;
+                       goto bad_inode;
                }
 
                err = ni_load_mi(ni, le, &mi);
@@ -757,7 +791,7 @@ pack_runs:
                attr = mi_find_attr(mi, NULL, type, name, name_len, &le->id);
                if (!attr) {
                        err = -EINVAL;
-                       goto out;
+                       goto bad_inode;
                }
                goto next_le_1;
        }
@@ -772,13 +806,13 @@ ok:
                }
        }
 
-out:
-       if (!err && attr_b && ret)
+ok1:
+       if (ret)
                *ret = attr_b;
 
        /* Update inode_set_bytes. */
-       if (!err && ((type == ATTR_DATA && !name_len) ||
-                    (type == ATTR_ALLOC && name == I30_NAME))) {
+       if (((type == ATTR_DATA && !name_len) ||
+            (type == ATTR_ALLOC && name == I30_NAME))) {
                bool dirty = false;
 
                if (ni->vfs_inode.i_size != new_size) {
@@ -786,7 +820,7 @@ out:
                        dirty = true;
                }
 
-               if (attr_b && attr_b->non_res) {
+               if (attr_b->non_res) {
                        new_alloc = le64_to_cpu(attr_b->nres.alloc_size);
                        if (inode_get_bytes(&ni->vfs_inode) != new_alloc) {
                                inode_set_bytes(&ni->vfs_inode, new_alloc);
@@ -800,6 +834,47 @@ out:
                }
        }
 
+       return 0;
+
+undo_2:
+       vcn -= alen;
+       attr_b->nres.data_size = cpu_to_le64(old_size);
+       attr_b->nres.valid_size = cpu_to_le64(old_valid);
+       attr_b->nres.alloc_size = cpu_to_le64(old_alloc);
+
+       /* Restore 'attr' and 'mi'. */
+       if (attr)
+               goto restore_run;
+
+       if (le64_to_cpu(attr_b->nres.svcn) <= svcn &&
+           svcn <= le64_to_cpu(attr_b->nres.evcn)) {
+               attr = attr_b;
+               le = le_b;
+               mi = mi_b;
+       } else if (!le_b) {
+               err = -EINVAL;
+               goto bad_inode;
+       } else {
+               le = le_b;
+               attr = ni_find_attr(ni, attr_b, &le, type, name, name_len,
+                                   &svcn, &mi);
+               if (!attr)
+                       goto bad_inode;
+       }
+
+restore_run:
+       if (mi_pack_runs(mi, attr, run, evcn - svcn + 1))
+               is_bad = true;
+
+undo_1:
+       run_deallocate_ex(sbi, run, vcn, alen, NULL, false);
+
+       run_truncate(run, vcn);
+out:
+       if (is_bad) {
+bad_inode:
+               _ntfs_bad_inode(&ni->vfs_inode);
+       }
        return err;
 }
 
@@ -855,7 +930,7 @@ int attr_data_get_block(struct ntfs_inode *ni, CLST vcn, CLST clen, CLST *lcn,
                goto out;
        }
 
-       asize = le64_to_cpu(attr_b->nres.alloc_size) >> sbi->cluster_bits;
+       asize = le64_to_cpu(attr_b->nres.alloc_size) >> cluster_bits;
        if (vcn >= asize) {
                err = -EINVAL;
                goto out;
@@ -1047,7 +1122,7 @@ ins_ext:
        if (evcn1 > next_svcn) {
                err = ni_insert_nonresident(ni, ATTR_DATA, NULL, 0, run,
                                            next_svcn, evcn1 - next_svcn,
-                                           attr_b->flags, &attr, &mi);
+                                           attr_b->flags, &attr, &mi, NULL);
                if (err)
                        goto out;
        }
@@ -1173,7 +1248,7 @@ int attr_load_runs_range(struct ntfs_inode *ni, enum ATTR_TYPE type,
 {
        struct ntfs_sb_info *sbi = ni->mi.sbi;
        u8 cluster_bits = sbi->cluster_bits;
-       CLST vcn = from >> cluster_bits;
+       CLST vcn;
        CLST vcn_last = (to - 1) >> cluster_bits;
        CLST lcn, clen;
        int err;
@@ -1647,7 +1722,7 @@ ins_ext:
        if (evcn1 > next_svcn) {
                err = ni_insert_nonresident(ni, ATTR_DATA, NULL, 0, run,
                                            next_svcn, evcn1 - next_svcn,
-                                           attr_b->flags, &attr, &mi);
+                                           attr_b->flags, &attr, &mi, NULL);
                if (err)
                        goto out;
        }
@@ -1812,18 +1887,12 @@ int attr_collapse_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)
                                err = ni_insert_nonresident(
                                        ni, ATTR_DATA, NULL, 0, run, next_svcn,
                                        evcn1 - eat - next_svcn, a_flags, &attr,
-                                       &mi);
+                                       &mi, &le);
                                if (err)
                                        goto out;
 
                                /* Layout of records maybe changed. */
                                attr_b = NULL;
-                               le = al_find_ex(ni, NULL, ATTR_DATA, NULL, 0,
-                                               &next_svcn);
-                               if (!le) {
-                                       err = -EINVAL;
-                                       goto out;
-                               }
                        }
 
                        /* Free all allocated memory. */
@@ -1918,7 +1987,7 @@ next_attr:
 out:
        up_write(&ni->file.run_lock);
        if (err)
-               make_bad_inode(&ni->vfs_inode);
+               _ntfs_bad_inode(&ni->vfs_inode);
 
        return err;
 }
@@ -1936,9 +2005,11 @@ int attr_punch_hole(struct ntfs_inode *ni, u64 vbo, u64 bytes, u32 *frame_size)
        struct ATTRIB *attr = NULL, *attr_b;
        struct ATTR_LIST_ENTRY *le, *le_b;
        struct mft_inode *mi, *mi_b;
-       CLST svcn, evcn1, vcn, len, end, alen, dealloc;
+       CLST svcn, evcn1, vcn, len, end, alen, hole, next_svcn;
        u64 total_size, alloc_size;
        u32 mask;
+       __le16 a_flags;
+       struct runs_tree run2;
 
        if (!bytes)
                return 0;
@@ -1990,6 +2061,9 @@ int attr_punch_hole(struct ntfs_inode *ni, u64 vbo, u64 bytes, u32 *frame_size)
        }
 
        down_write(&ni->file.run_lock);
+       run_init(&run2);
+       run_truncate(run, 0);
+
        /*
         * Enumerate all attribute segments and punch hole where necessary.
         */
@@ -1997,10 +2071,11 @@ int attr_punch_hole(struct ntfs_inode *ni, u64 vbo, u64 bytes, u32 *frame_size)
        vcn = vbo >> sbi->cluster_bits;
        len = bytes >> sbi->cluster_bits;
        end = vcn + len;
-       dealloc = 0;
+       hole = 0;
 
        svcn = le64_to_cpu(attr_b->nres.svcn);
        evcn1 = le64_to_cpu(attr_b->nres.evcn) + 1;
+       a_flags = attr_b->flags;
 
        if (svcn <= vcn && vcn < evcn1) {
                attr = attr_b;
@@ -2008,14 +2083,14 @@ int attr_punch_hole(struct ntfs_inode *ni, u64 vbo, u64 bytes, u32 *frame_size)
                mi = mi_b;
        } else if (!le_b) {
                err = -EINVAL;
-               goto out;
+               goto bad_inode;
        } else {
                le = le_b;
                attr = ni_find_attr(ni, attr_b, &le, ATTR_DATA, NULL, 0, &vcn,
                                    &mi);
                if (!attr) {
                        err = -EINVAL;
-                       goto out;
+                       goto bad_inode;
                }
 
                svcn = le64_to_cpu(attr->nres.svcn);
@@ -2023,49 +2098,91 @@ int attr_punch_hole(struct ntfs_inode *ni, u64 vbo, u64 bytes, u32 *frame_size)
        }
 
        while (svcn < end) {
-               CLST vcn1, zero, dealloc2;
+               CLST vcn1, zero, hole2 = hole;
 
                err = attr_load_runs(attr, ni, run, &svcn);
                if (err)
-                       goto out;
+                       goto done;
                vcn1 = max(vcn, svcn);
                zero = min(end, evcn1) - vcn1;
 
-               dealloc2 = dealloc;
-               err = run_deallocate_ex(sbi, run, vcn1, zero, &dealloc, true);
+               /*
+                * Check range [vcn1 + zero).
+                * Calculate how many clusters there are.
+                * Don't do any destructive actions.
+                */
+               err = run_deallocate_ex(NULL, run, vcn1, zero, &hole2, false);
                if (err)
-                       goto out;
+                       goto done;
 
-               if (dealloc2 == dealloc) {
-                       /* Looks like the required range is already sparsed. */
-               } else {
-                       if (!run_add_entry(run, vcn1, SPARSE_LCN, zero,
-                                          false)) {
-                               err = -ENOMEM;
-                               goto out;
-                       }
+               /* Check if required range is already hole. */
+               if (hole2 == hole)
+                       goto next_attr;
+
+               /* Make a clone of run to undo. */
+               err = run_clone(run, &run2);
+               if (err)
+                       goto done;
+
+               /* Make a hole range (sparse) [vcn1 + zero). */
+               if (!run_add_entry(run, vcn1, SPARSE_LCN, zero, false)) {
+                       err = -ENOMEM;
+                       goto done;
+               }
 
-                       err = mi_pack_runs(mi, attr, run, evcn1 - svcn);
+               /* Update run in attribute segment. */
+               err = mi_pack_runs(mi, attr, run, evcn1 - svcn);
+               if (err)
+                       goto done;
+               next_svcn = le64_to_cpu(attr->nres.evcn) + 1;
+               if (next_svcn < evcn1) {
+                       /* Insert new attribute segment. */
+                       err = ni_insert_nonresident(ni, ATTR_DATA, NULL, 0, run,
+                                                   next_svcn,
+                                                   evcn1 - next_svcn, a_flags,
+                                                   &attr, &mi, &le);
                        if (err)
-                               goto out;
+                               goto undo_punch;
+
+                       /* Layout of records maybe changed. */
+                       attr_b = NULL;
                }
+
+               /* Real deallocate. Should not fail. */
+               run_deallocate_ex(sbi, &run2, vcn1, zero, &hole, true);
+
+next_attr:
                /* Free all allocated memory. */
                run_truncate(run, 0);
 
                if (evcn1 >= alen)
                        break;
 
+               /* Get next attribute segment. */
                attr = ni_enum_attr_ex(ni, attr, &le, &mi);
                if (!attr) {
                        err = -EINVAL;
-                       goto out;
+                       goto bad_inode;
                }
 
                svcn = le64_to_cpu(attr->nres.svcn);
                evcn1 = le64_to_cpu(attr->nres.evcn) + 1;
        }
 
-       total_size -= (u64)dealloc << sbi->cluster_bits;
+done:
+       if (!hole)
+               goto out;
+
+       if (!attr_b) {
+               attr_b = ni_find_attr(ni, NULL, NULL, ATTR_DATA, NULL, 0, NULL,
+                                     &mi_b);
+               if (!attr_b) {
+                       err = -EINVAL;
+                       goto bad_inode;
+               }
+       }
+
+       total_size -= (u64)hole << sbi->cluster_bits;
        attr_b->nres.total_size = cpu_to_le64(total_size);
        mi_b->dirty = true;
 
@@ -2075,9 +2192,263 @@ int attr_punch_hole(struct ntfs_inode *ni, u64 vbo, u64 bytes, u32 *frame_size)
        mark_inode_dirty(&ni->vfs_inode);
 
 out:
+       run_close(&run2);
        up_write(&ni->file.run_lock);
+       return err;
+
+bad_inode:
+       _ntfs_bad_inode(&ni->vfs_inode);
+       goto out;
+
+undo_punch:
+       /*
+        * Restore packed runs.
+        * 'mi_pack_runs' should not fail, cause we restore original.
+        */
+       if (mi_pack_runs(mi, attr, &run2, evcn1 - svcn))
+               goto bad_inode;
+
+       goto done;
+}
+
+/*
+ * attr_insert_range - Insert range (hole) in file.
+ * Not for normal files.
+ */
+int attr_insert_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)
+{
+       int err = 0;
+       struct runs_tree *run = &ni->file.run;
+       struct ntfs_sb_info *sbi = ni->mi.sbi;
+       struct ATTRIB *attr = NULL, *attr_b;
+       struct ATTR_LIST_ENTRY *le, *le_b;
+       struct mft_inode *mi, *mi_b;
+       CLST vcn, svcn, evcn1, len, next_svcn;
+       u64 data_size, alloc_size;
+       u32 mask;
+       __le16 a_flags;
+
+       if (!bytes)
+               return 0;
+
+       le_b = NULL;
+       attr_b = ni_find_attr(ni, NULL, &le_b, ATTR_DATA, NULL, 0, NULL, &mi_b);
+       if (!attr_b)
+               return -ENOENT;
+
+       if (!is_attr_ext(attr_b)) {
+               /* It was checked above. See fallocate. */
+               return -EOPNOTSUPP;
+       }
+
+       if (!attr_b->non_res) {
+               data_size = le32_to_cpu(attr_b->res.data_size);
+               alloc_size = data_size;
+               mask = sbi->cluster_mask; /* cluster_size - 1 */
+       } else {
+               data_size = le64_to_cpu(attr_b->nres.data_size);
+               alloc_size = le64_to_cpu(attr_b->nres.alloc_size);
+               mask = (sbi->cluster_size << attr_b->nres.c_unit) - 1;
+       }
+
+       if (vbo > data_size) {
+               /* Insert range after the file size is not allowed. */
+               return -EINVAL;
+       }
+
+       if ((vbo & mask) || (bytes & mask)) {
+               /* Allow to insert only frame aligned ranges. */
+               return -EINVAL;
+       }
+
+       /*
+        * valid_size <= data_size <= alloc_size
+        * Check alloc_size for maximum possible.
+        */
+       if (bytes > sbi->maxbytes_sparse - alloc_size)
+               return -EFBIG;
+
+       vcn = vbo >> sbi->cluster_bits;
+       len = bytes >> sbi->cluster_bits;
+
+       down_write(&ni->file.run_lock);
+
+       if (!attr_b->non_res) {
+               err = attr_set_size(ni, ATTR_DATA, NULL, 0, run,
+                                   data_size + bytes, NULL, false, NULL);
+
+               le_b = NULL;
+               attr_b = ni_find_attr(ni, NULL, &le_b, ATTR_DATA, NULL, 0, NULL,
+                                     &mi_b);
+               if (!attr_b) {
+                       err = -EINVAL;
+                       goto bad_inode;
+               }
+
+               if (err)
+                       goto out;
+
+               if (!attr_b->non_res) {
+                       /* Still resident. */
+                       char *data = Add2Ptr(attr_b, attr_b->res.data_off);
+
+                       memmove(data + bytes, data, bytes);
+                       memset(data, 0, bytes);
+                       goto done;
+               }
+
+               /* Resident files becomes nonresident. */
+               data_size = le64_to_cpu(attr_b->nres.data_size);
+               alloc_size = le64_to_cpu(attr_b->nres.alloc_size);
+       }
+
+       /*
+        * Enumerate all attribute segments and shift start vcn.
+        */
+       a_flags = attr_b->flags;
+       svcn = le64_to_cpu(attr_b->nres.svcn);
+       evcn1 = le64_to_cpu(attr_b->nres.evcn) + 1;
+
+       if (svcn <= vcn && vcn < evcn1) {
+               attr = attr_b;
+               le = le_b;
+               mi = mi_b;
+       } else if (!le_b) {
+               err = -EINVAL;
+               goto bad_inode;
+       } else {
+               le = le_b;
+               attr = ni_find_attr(ni, attr_b, &le, ATTR_DATA, NULL, 0, &vcn,
+                                   &mi);
+               if (!attr) {
+                       err = -EINVAL;
+                       goto bad_inode;
+               }
+
+               svcn = le64_to_cpu(attr->nres.svcn);
+               evcn1 = le64_to_cpu(attr->nres.evcn) + 1;
+       }
+
+       run_truncate(run, 0); /* clear cached values. */
+       err = attr_load_runs(attr, ni, run, NULL);
+       if (err)
+               goto out;
+
+       if (!run_insert_range(run, vcn, len)) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       /* Try to pack in current record as much as possible. */
+       err = mi_pack_runs(mi, attr, run, evcn1 + len - svcn);
        if (err)
-               make_bad_inode(&ni->vfs_inode);
+               goto out;
+
+       next_svcn = le64_to_cpu(attr->nres.evcn) + 1;
+
+       while ((attr = ni_enum_attr_ex(ni, attr, &le, &mi)) &&
+              attr->type == ATTR_DATA && !attr->name_len) {
+               le64_add_cpu(&attr->nres.svcn, len);
+               le64_add_cpu(&attr->nres.evcn, len);
+               if (le) {
+                       le->vcn = attr->nres.svcn;
+                       ni->attr_list.dirty = true;
+               }
+               mi->dirty = true;
+       }
+
+       if (next_svcn < evcn1 + len) {
+               err = ni_insert_nonresident(ni, ATTR_DATA, NULL, 0, run,
+                                           next_svcn, evcn1 + len - next_svcn,
+                                           a_flags, NULL, NULL, NULL);
+
+               le_b = NULL;
+               attr_b = ni_find_attr(ni, NULL, &le_b, ATTR_DATA, NULL, 0, NULL,
+                                     &mi_b);
+               if (!attr_b) {
+                       err = -EINVAL;
+                       goto bad_inode;
+               }
+
+               if (err) {
+                       /* ni_insert_nonresident failed. Try to undo. */
+                       goto undo_insert_range;
+               }
+       }
+
+       /*
+        * Update primary attribute segment.
+        */
+       if (vbo <= ni->i_valid)
+               ni->i_valid += bytes;
+
+       attr_b->nres.data_size = le64_to_cpu(data_size + bytes);
+       attr_b->nres.alloc_size = le64_to_cpu(alloc_size + bytes);
+
+       /* ni->valid may be not equal valid_size (temporary). */
+       if (ni->i_valid > data_size + bytes)
+               attr_b->nres.valid_size = attr_b->nres.data_size;
+       else
+               attr_b->nres.valid_size = cpu_to_le64(ni->i_valid);
+       mi_b->dirty = true;
+
+done:
+       ni->vfs_inode.i_size += bytes;
+       ni->ni_flags |= NI_FLAG_UPDATE_PARENT;
+       mark_inode_dirty(&ni->vfs_inode);
+
+out:
+       run_truncate(run, 0); /* clear cached values. */
+
+       up_write(&ni->file.run_lock);
 
        return err;
+
+bad_inode:
+       _ntfs_bad_inode(&ni->vfs_inode);
+       goto out;
+
+undo_insert_range:
+       svcn = le64_to_cpu(attr_b->nres.svcn);
+       evcn1 = le64_to_cpu(attr_b->nres.evcn) + 1;
+
+       if (svcn <= vcn && vcn < evcn1) {
+               attr = attr_b;
+               le = le_b;
+               mi = mi_b;
+       } else if (!le_b) {
+               goto bad_inode;
+       } else {
+               le = le_b;
+               attr = ni_find_attr(ni, attr_b, &le, ATTR_DATA, NULL, 0, &vcn,
+                                   &mi);
+               if (!attr) {
+                       goto bad_inode;
+               }
+
+               svcn = le64_to_cpu(attr->nres.svcn);
+               evcn1 = le64_to_cpu(attr->nres.evcn) + 1;
+       }
+
+       if (attr_load_runs(attr, ni, run, NULL))
+               goto bad_inode;
+
+       if (!run_collapse_range(run, vcn, len))
+               goto bad_inode;
+
+       if (mi_pack_runs(mi, attr, run, evcn1 + len - svcn))
+               goto bad_inode;
+
+       while ((attr = ni_enum_attr_ex(ni, attr, &le, &mi)) &&
+              attr->type == ATTR_DATA && !attr->name_len) {
+               le64_sub_cpu(&attr->nres.svcn, len);
+               le64_sub_cpu(&attr->nres.evcn, len);
+               if (le) {
+                       le->vcn = attr->nres.svcn;
+                       ni->attr_list.dirty = true;
+               }
+               mi->dirty = true;
+       }
+
+       goto out;
 }
index aa18440..5d44cea 100644 (file)
@@ -51,11 +51,6 @@ void ntfs3_exit_bitmap(void)
        kmem_cache_destroy(ntfs_enode_cachep);
 }
 
-static inline u32 wnd_bits(const struct wnd_bitmap *wnd, size_t i)
-{
-       return i + 1 == wnd->nwnd ? wnd->bits_last : wnd->sb->s_blocksize * 8;
-}
-
 /*
  * wnd_scan
  *
@@ -1333,9 +1328,7 @@ int wnd_extend(struct wnd_bitmap *wnd, size_t new_bits)
                if (!new_free)
                        return -ENOMEM;
 
-               if (new_free != wnd->free_bits)
-                       memcpy(new_free, wnd->free_bits,
-                              wnd->nwnd * sizeof(short));
+               memcpy(new_free, wnd->free_bits, wnd->nwnd * sizeof(short));
                memset(new_free + wnd->nwnd, 0,
                       (new_wnd - wnd->nwnd) * sizeof(short));
                kfree(wnd->free_bits);
@@ -1395,9 +1388,8 @@ int wnd_extend(struct wnd_bitmap *wnd, size_t new_bits)
 
 void wnd_zone_set(struct wnd_bitmap *wnd, size_t lcn, size_t len)
 {
-       size_t zlen;
+       size_t zlen = wnd->zone_end - wnd->zone_bit;
 
-       zlen = wnd->zone_end - wnd->zone_bit;
        if (zlen)
                wnd_add_free_ext(wnd, wnd->zone_bit, zlen, false);
 
index 4a21745..4f2ffc7 100644 (file)
@@ -530,21 +530,35 @@ static int ntfs_truncate(struct inode *inode, loff_t new_size)
 static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
 {
        struct inode *inode = file->f_mapping->host;
+       struct address_space *mapping = inode->i_mapping;
        struct super_block *sb = inode->i_sb;
        struct ntfs_sb_info *sbi = sb->s_fs_info;
        struct ntfs_inode *ni = ntfs_i(inode);
        loff_t end = vbo + len;
        loff_t vbo_down = round_down(vbo, PAGE_SIZE);
-       loff_t i_size;
+       bool is_supported_holes = is_sparsed(ni) || is_compressed(ni);
+       loff_t i_size, new_size;
+       bool map_locked;
        int err;
 
        /* No support for dir. */
        if (!S_ISREG(inode->i_mode))
                return -EOPNOTSUPP;
 
-       /* Return error if mode is not supported. */
-       if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE |
-                    FALLOC_FL_COLLAPSE_RANGE)) {
+       /*
+        * vfs_fallocate checks all possible combinations of mode.
+        * Do additional checks here before ntfs_set_state(dirty).
+        */
+       if (mode & FALLOC_FL_PUNCH_HOLE) {
+               if (!is_supported_holes)
+                       return -EOPNOTSUPP;
+       } else if (mode & FALLOC_FL_COLLAPSE_RANGE) {
+       } else if (mode & FALLOC_FL_INSERT_RANGE) {
+               if (!is_supported_holes)
+                       return -EOPNOTSUPP;
+       } else if (mode &
+                  ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE |
+                    FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_INSERT_RANGE)) {
                ntfs_inode_warn(inode, "fallocate(0x%x) is not supported",
                                mode);
                return -EOPNOTSUPP;
@@ -554,6 +568,8 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
 
        inode_lock(inode);
        i_size = inode->i_size;
+       new_size = max(end, i_size);
+       map_locked = false;
 
        if (WARN_ON(ni->ni_flags & NI_FLAG_COMPRESSED_MASK)) {
                /* Should never be here, see ntfs_file_open. */
@@ -561,38 +577,27 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
                goto out;
        }
 
+       if (mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_COLLAPSE_RANGE |
+                   FALLOC_FL_INSERT_RANGE)) {
+               inode_dio_wait(inode);
+               filemap_invalidate_lock(mapping);
+               map_locked = true;
+       }
+
        if (mode & FALLOC_FL_PUNCH_HOLE) {
                u32 frame_size;
                loff_t mask, vbo_a, end_a, tmp;
 
-               if (!(mode & FALLOC_FL_KEEP_SIZE)) {
-                       err = -EINVAL;
-                       goto out;
-               }
-
-               err = filemap_write_and_wait_range(inode->i_mapping, vbo,
-                                                  end - 1);
+               err = filemap_write_and_wait_range(mapping, vbo, end - 1);
                if (err)
                        goto out;
 
-               err = filemap_write_and_wait_range(inode->i_mapping, end,
-                                                  LLONG_MAX);
+               err = filemap_write_and_wait_range(mapping, end, LLONG_MAX);
                if (err)
                        goto out;
 
-               inode_dio_wait(inode);
-
                truncate_pagecache(inode, vbo_down);
 
-               if (!is_sparsed(ni) && !is_compressed(ni)) {
-                       /*
-                        * Normal file, can't make hole.
-                        * TODO: Try to find way to save info about hole.
-                        */
-                       err = -EOPNOTSUPP;
-                       goto out;
-               }
-
                ni_lock(ni);
                err = attr_punch_hole(ni, vbo, len, &frame_size);
                ni_unlock(ni);
@@ -624,17 +629,11 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
                        ni_unlock(ni);
                }
        } else if (mode & FALLOC_FL_COLLAPSE_RANGE) {
-               if (mode & ~FALLOC_FL_COLLAPSE_RANGE) {
-                       err = -EINVAL;
-                       goto out;
-               }
-
                /*
                 * Write tail of the last page before removed range since
                 * it will get removed from the page cache below.
                 */
-               err = filemap_write_and_wait_range(inode->i_mapping, vbo_down,
-                                                  vbo);
+               err = filemap_write_and_wait_range(mapping, vbo_down, vbo);
                if (err)
                        goto out;
 
@@ -642,34 +641,58 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
                 * Write data that will be shifted to preserve them
                 * when discarding page cache below.
                 */
-               err = filemap_write_and_wait_range(inode->i_mapping, end,
-                                                  LLONG_MAX);
+               err = filemap_write_and_wait_range(mapping, end, LLONG_MAX);
                if (err)
                        goto out;
 
-               /* Wait for existing dio to complete. */
-               inode_dio_wait(inode);
-
                truncate_pagecache(inode, vbo_down);
 
                ni_lock(ni);
                err = attr_collapse_range(ni, vbo, len);
                ni_unlock(ni);
+       } else if (mode & FALLOC_FL_INSERT_RANGE) {
+               /* Check new size. */
+               err = inode_newsize_ok(inode, new_size);
+               if (err)
+                       goto out;
+
+               /* Write out all dirty pages. */
+               err = filemap_write_and_wait_range(mapping, vbo_down,
+                                                  LLONG_MAX);
+               if (err)
+                       goto out;
+               truncate_pagecache(inode, vbo_down);
+
+               ni_lock(ni);
+               err = attr_insert_range(ni, vbo, len);
+               ni_unlock(ni);
        } else {
-               /*
-                * Normal file: Allocate clusters, do not change 'valid' size.
-                */
-               loff_t new_size = max(end, i_size);
+               /* Check new size. */
+
+               /* generic/213: expected -ENOSPC instead of -EFBIG. */
+               if (!is_supported_holes) {
+                       loff_t to_alloc = new_size - inode_get_bytes(inode);
+
+                       if (to_alloc > 0 &&
+                           (to_alloc >> sbi->cluster_bits) >
+                                   wnd_zeroes(&sbi->used.bitmap)) {
+                               err = -ENOSPC;
+                               goto out;
+                       }
+               }
 
                err = inode_newsize_ok(inode, new_size);
                if (err)
                        goto out;
 
+               /*
+                * Allocate clusters, do not change 'valid' size.
+                */
                err = ntfs_set_size(inode, new_size);
                if (err)
                        goto out;
 
-               if (is_sparsed(ni) || is_compressed(ni)) {
+               if (is_supported_holes) {
                        CLST vcn_v = ni->i_valid >> sbi->cluster_bits;
                        CLST vcn = vbo >> sbi->cluster_bits;
                        CLST cend = bytes_to_cluster(sbi, end);
@@ -717,8 +740,8 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
        }
 
 out:
-       if (err == -EFBIG)
-               err = -ENOSPC;
+       if (map_locked)
+               filemap_invalidate_unlock(mapping);
 
        if (!err) {
                inode->i_ctime = inode->i_mtime = current_time(inode);
@@ -989,7 +1012,6 @@ static ssize_t ntfs_compress_write(struct kiocb *iocb, struct iov_iter *from)
                if (bytes > count)
                        bytes = count;
 
-               frame = pos >> frame_bits;
                frame_vbo = pos & ~(frame_size - 1);
                index = frame_vbo >> PAGE_SHIFT;
 
index 1884299..381a38a 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <linux/fiemap.h>
 #include <linux/fs.h>
+#include <linux/minmax.h>
 #include <linux/vmalloc.h>
 
 #include "debug.h"
@@ -468,7 +469,7 @@ ni_ins_new_attr(struct ntfs_inode *ni, struct mft_inode *mi,
                                &ref, &le);
                if (err) {
                        /* No memory or no space. */
-                       return NULL;
+                       return ERR_PTR(err);
                }
                le_added = true;
 
@@ -649,6 +650,7 @@ static int ni_try_remove_attr_list(struct ntfs_inode *ni)
        struct mft_inode *mi;
        u32 asize, free;
        struct MFT_REF ref;
+       struct MFT_REC *mrec;
        __le16 id;
 
        if (!ni->attr_list.dirty)
@@ -692,11 +694,17 @@ static int ni_try_remove_attr_list(struct ntfs_inode *ni)
                free -= asize;
        }
 
+       /* Make a copy of primary record to restore if error. */
+       mrec = kmemdup(ni->mi.mrec, sbi->record_size, GFP_NOFS);
+       if (!mrec)
+               return 0; /* Not critical. */
+
        /* It seems that attribute list can be removed from primary record. */
        mi_remove_attr(NULL, &ni->mi, attr_list);
 
        /*
-        * Repeat the cycle above and move all attributes to primary record.
+        * Repeat the cycle above and copy all attributes to primary record.
+        * Do not remove original attributes from subrecords!
         * It should be success!
         */
        le = NULL;
@@ -707,14 +715,14 @@ static int ni_try_remove_attr_list(struct ntfs_inode *ni)
                mi = ni_find_mi(ni, ino_get(&le->ref));
                if (!mi) {
                        /* Should never happened, 'cause already checked. */
-                       goto bad;
+                       goto out;
                }
 
                attr = mi_find_attr(mi, NULL, le->type, le_name(le),
                                    le->name_len, &le->id);
                if (!attr) {
                        /* Should never happened, 'cause already checked. */
-                       goto bad;
+                       goto out;
                }
                asize = le32_to_cpu(attr->size);
 
@@ -724,18 +732,33 @@ static int ni_try_remove_attr_list(struct ntfs_inode *ni)
                                          le16_to_cpu(attr->name_off));
                if (!attr_ins) {
                        /*
-                        * Internal error.
-                        * Either no space in primary record (already checked).
-                        * Either tried to insert another
-                        * non indexed attribute (logic error).
+                        * No space in primary record (already checked).
                         */
-                       goto bad;
+                       goto out;
                }
 
                /* Copy all except id. */
                id = attr_ins->id;
                memcpy(attr_ins, attr, asize);
                attr_ins->id = id;
+       }
+
+       /*
+        * Repeat the cycle above and remove all attributes from subrecords.
+        */
+       le = NULL;
+       while ((le = al_enumerate(ni, le))) {
+               if (!memcmp(&le->ref, &ref, sizeof(ref)))
+                       continue;
+
+               mi = ni_find_mi(ni, ino_get(&le->ref));
+               if (!mi)
+                       continue;
+
+               attr = mi_find_attr(mi, NULL, le->type, le_name(le),
+                                   le->name_len, &le->id);
+               if (!attr)
+                       continue;
 
                /* Remove from original record. */
                mi_remove_attr(NULL, mi, attr);
@@ -748,11 +771,13 @@ static int ni_try_remove_attr_list(struct ntfs_inode *ni)
        ni->attr_list.le = NULL;
        ni->attr_list.dirty = false;
 
+       kfree(mrec);
+       return 0;
+out:
+       /* Restore primary record. */
+       swap(mrec, ni->mi.mrec);
+       kfree(mrec);
        return 0;
-bad:
-       ntfs_inode_err(&ni->vfs_inode, "Internal error");
-       make_bad_inode(&ni->vfs_inode);
-       return -EINVAL;
 }
 
 /*
@@ -986,6 +1011,8 @@ static int ni_ins_attr_ext(struct ntfs_inode *ni, struct ATTR_LIST_ENTRY *le,
                                       name_off, svcn, ins_le);
                if (!attr)
                        continue;
+               if (IS_ERR(attr))
+                       return PTR_ERR(attr);
 
                if (ins_attr)
                        *ins_attr = attr;
@@ -1007,8 +1034,15 @@ insert_ext:
 
        attr = ni_ins_new_attr(ni, mi, le, type, name, name_len, asize,
                               name_off, svcn, ins_le);
-       if (!attr)
+       if (!attr) {
+               err = -EINVAL;
                goto out2;
+       }
+
+       if (IS_ERR(attr)) {
+               err = PTR_ERR(attr);
+               goto out2;
+       }
 
        if (ins_attr)
                *ins_attr = attr;
@@ -1020,10 +1054,9 @@ insert_ext:
 out2:
        ni_remove_mi(ni, mi);
        mi_put(mi);
-       err = -EINVAL;
 
 out1:
-       ntfs_mark_rec_free(sbi, rno);
+       ntfs_mark_rec_free(sbi, rno, is_mft);
 
 out:
        return err;
@@ -1076,6 +1109,11 @@ static int ni_insert_attr(struct ntfs_inode *ni, enum ATTR_TYPE type,
        if (asize <= free) {
                attr = ni_ins_new_attr(ni, &ni->mi, NULL, type, name, name_len,
                                       asize, name_off, svcn, ins_le);
+               if (IS_ERR(attr)) {
+                       err = PTR_ERR(attr);
+                       goto out;
+               }
+
                if (attr) {
                        if (ins_attr)
                                *ins_attr = attr;
@@ -1173,6 +1211,11 @@ static int ni_insert_attr(struct ntfs_inode *ni, enum ATTR_TYPE type,
                goto out;
        }
 
+       if (IS_ERR(attr)) {
+               err = PTR_ERR(attr);
+               goto out;
+       }
+
        if (ins_attr)
                *ins_attr = attr;
        if (ins_mi)
@@ -1218,7 +1261,7 @@ static int ni_expand_mft_list(struct ntfs_inode *ni)
                mft_min = mft_new;
                mi_min = mi_new;
        } else {
-               ntfs_mark_rec_free(sbi, mft_new);
+               ntfs_mark_rec_free(sbi, mft_new, true);
                mft_new = 0;
                ni_remove_mi(ni, mi_new);
        }
@@ -1262,7 +1305,7 @@ static int ni_expand_mft_list(struct ntfs_inode *ni)
        done = asize - run_size - SIZEOF_NONRESIDENT;
        le32_sub_cpu(&ni->mi.mrec->used, done);
 
-       /* Estimate the size of second part: run_buf=NULL. */
+       /* Estimate packed size (run_buf=NULL). */
        err = run_pack(run, svcn, evcn + 1 - svcn, NULL, sbi->record_size,
                       &plen);
        if (err < 0)
@@ -1288,10 +1331,16 @@ static int ni_expand_mft_list(struct ntfs_inode *ni)
                goto out;
        }
 
+       if (IS_ERR(attr)) {
+               err = PTR_ERR(attr);
+               goto out;
+       }
+
        attr->non_res = 1;
        attr->name_off = SIZEOF_NONRESIDENT_LE;
        attr->flags = 0;
 
+       /* This function can't fail - cause already checked above. */
        run_pack(run, svcn, evcn + 1 - svcn, Add2Ptr(attr, SIZEOF_NONRESIDENT),
                 run_size, &plen);
 
@@ -1301,7 +1350,7 @@ static int ni_expand_mft_list(struct ntfs_inode *ni)
 
 out:
        if (mft_new) {
-               ntfs_mark_rec_free(sbi, mft_new);
+               ntfs_mark_rec_free(sbi, mft_new, true);
                ni_remove_mi(ni, mi_new);
        }
 
@@ -1367,8 +1416,6 @@ int ni_expand_list(struct ntfs_inode *ni)
 
        /* Split MFT data as much as possible. */
        err = ni_expand_mft_list(ni);
-       if (err)
-               goto out;
 
 out:
        return !err && !done ? -EOPNOTSUPP : err;
@@ -1381,7 +1428,7 @@ int ni_insert_nonresident(struct ntfs_inode *ni, enum ATTR_TYPE type,
                          const __le16 *name, u8 name_len,
                          const struct runs_tree *run, CLST svcn, CLST len,
                          __le16 flags, struct ATTRIB **new_attr,
-                         struct mft_inode **mi)
+                         struct mft_inode **mi, struct ATTR_LIST_ENTRY **le)
 {
        int err;
        CLST plen;
@@ -1394,6 +1441,7 @@ int ni_insert_nonresident(struct ntfs_inode *ni, enum ATTR_TYPE type,
        u32 run_size, asize;
        struct ntfs_sb_info *sbi = ni->mi.sbi;
 
+       /* Estimate packed size (run_buf=NULL). */
        err = run_pack(run, svcn, len, NULL, sbi->max_bytes_per_attr - run_off,
                       &plen);
        if (err < 0)
@@ -1414,7 +1462,7 @@ int ni_insert_nonresident(struct ntfs_inode *ni, enum ATTR_TYPE type,
        }
 
        err = ni_insert_attr(ni, type, name, name_len, asize, name_off, svcn,
-                            &attr, mi, NULL);
+                            &attr, mi, le);
 
        if (err)
                goto out;
@@ -1423,12 +1471,12 @@ int ni_insert_nonresident(struct ntfs_inode *ni, enum ATTR_TYPE type,
        attr->name_off = cpu_to_le16(name_off);
        attr->flags = flags;
 
+       /* This function can't fail - cause already checked above. */
        run_pack(run, svcn, len, Add2Ptr(attr, run_off), run_size, &plen);
 
        attr->nres.svcn = cpu_to_le64(svcn);
        attr->nres.evcn = cpu_to_le64((u64)svcn + len - 1);
 
-       err = 0;
        if (new_attr)
                *new_attr = attr;
 
@@ -1560,7 +1608,7 @@ int ni_delete_all(struct ntfs_inode *ni)
                mi->dirty = true;
                mi_write(mi, 0);
 
-               ntfs_mark_rec_free(sbi, mi->rno);
+               ntfs_mark_rec_free(sbi, mi->rno, false);
                ni_remove_mi(ni, mi);
                mi_put(mi);
                node = next;
@@ -1571,7 +1619,7 @@ int ni_delete_all(struct ntfs_inode *ni)
        ni->mi.dirty = true;
        err = mi_write(&ni->mi, 0);
 
-       ntfs_mark_rec_free(sbi, ni->mi.rno);
+       ntfs_mark_rec_free(sbi, ni->mi.rno, false);
 
        return err;
 }
@@ -1589,7 +1637,8 @@ struct ATTR_FILE_NAME *ni_fname_name(struct ntfs_inode *ni,
        struct ATTRIB *attr = NULL;
        struct ATTR_FILE_NAME *fname;
 
-       *le = NULL;
+       if (le)
+               *le = NULL;
 
        /* Enumerate all names. */
 next:
@@ -1605,7 +1654,7 @@ next:
                goto next;
 
        if (!uni)
-               goto next;
+               return fname;
 
        if (uni->len != fname->name_len)
                goto next;
@@ -2302,10 +2351,8 @@ remove_wof:
 
 out:
        kfree(pages);
-       if (err) {
-               make_bad_inode(inode);
-               ntfs_set_state(sbi, NTFS_DIRTY_ERROR);
-       }
+       if (err)
+               _ntfs_bad_inode(inode);
 
        return err;
 }
@@ -2944,7 +2991,7 @@ bool ni_remove_name_undo(struct ntfs_inode *dir_ni, struct ntfs_inode *ni,
 }
 
 /*
- * ni_add_name - Add new name in MFT and in directory.
+ * ni_add_name - Add new name into MFT and into directory.
  */
 int ni_add_name(struct ntfs_inode *dir_ni, struct ntfs_inode *ni,
                struct NTFS_DE *de)
@@ -2953,13 +3000,20 @@ int ni_add_name(struct ntfs_inode *dir_ni, struct ntfs_inode *ni,
        struct ATTRIB *attr;
        struct ATTR_LIST_ENTRY *le;
        struct mft_inode *mi;
+       struct ATTR_FILE_NAME *fname;
        struct ATTR_FILE_NAME *de_name = (struct ATTR_FILE_NAME *)(de + 1);
        u16 de_key_size = le16_to_cpu(de->key_size);
 
        mi_get_ref(&ni->mi, &de->ref);
        mi_get_ref(&dir_ni->mi, &de_name->home);
 
-       /* Insert new name in MFT. */
+       /* Fill duplicate from any ATTR_NAME. */
+       fname = ni_fname_name(ni, NULL, NULL, NULL, NULL);
+       if (fname)
+               memcpy(&de_name->dup, &fname->dup, sizeof(fname->dup));
+       de_name->dup.fa = ni->std_fa;
+
+       /* Insert new name into MFT. */
        err = ni_insert_resident(ni, de_key_size, ATTR_NAME, NULL, 0, &attr,
                                 &mi, &le);
        if (err)
@@ -2967,7 +3021,7 @@ int ni_add_name(struct ntfs_inode *dir_ni, struct ntfs_inode *ni,
 
        memcpy(Add2Ptr(attr, SIZEOF_RESIDENT), de_name, de_key_size);
 
-       /* Insert new name in directory. */
+       /* Insert new name into directory. */
        err = indx_insert_entry(&dir_ni->dir, dir_ni, de, ni->mi.sbi, NULL, 0);
        if (err)
                ni_remove_attr_le(ni, attr, mi, le);
@@ -2991,7 +3045,7 @@ int ni_rename(struct ntfs_inode *dir_ni, struct ntfs_inode *new_dir_ni,
         * 1) Add new name and remove old name.
         * 2) Remove old name and add new name.
         *
-        * In most cases (not all!) adding new name in MFT and in directory can
+        * In most cases (not all!) adding new name into MFT and into directory can
         * allocate additional cluster(s).
         * Second way may result to bad inode if we can't add new name
         * and then can't restore (add) old name.
@@ -3261,7 +3315,7 @@ int ni_write_inode(struct inode *inode, int sync, const char *hint)
                        err = err2;
 
                if (is_empty) {
-                       ntfs_mark_rec_free(sbi, mi->rno);
+                       ntfs_mark_rec_free(sbi, mi->rno, false);
                        rb_erase(node, &ni->mi_tree);
                        mi_put(mi);
                }
index 49b7df6..e7c4940 100644 (file)
@@ -3843,6 +3843,8 @@ int log_replay(struct ntfs_inode *ni, bool *initialized)
 
        memset(&rst_info2, 0, sizeof(struct restart_info));
        err = log_read_rst(log, l_size, false, &rst_info2);
+       if (err)
+               goto out;
 
        /* Determine which restart area to use. */
        if (!rst_info2.restart || rst_info2.last_lsn <= rst_info.last_lsn)
@@ -5057,7 +5059,7 @@ undo_action_next:
                goto add_allocated_vcns;
 
        vcn = le64_to_cpu(lrh->target_vcn);
-       vcn &= ~(log->clst_per_page - 1);
+       vcn &= ~(u64)(log->clst_per_page - 1);
 
 add_allocated_vcns:
        for (i = 0, vcn = le64_to_cpu(lrh->target_vcn),
index 1835e35..4ed15f6 100644 (file)
@@ -703,12 +703,14 @@ out:
 
 /*
  * ntfs_mark_rec_free - Mark record as free.
+ * is_mft - true if we are changing MFT
  */
-void ntfs_mark_rec_free(struct ntfs_sb_info *sbi, CLST rno)
+void ntfs_mark_rec_free(struct ntfs_sb_info *sbi, CLST rno, bool is_mft)
 {
        struct wnd_bitmap *wnd = &sbi->mft.bitmap;
 
-       down_write_nested(&wnd->rw_lock, BITMAP_MUTEX_MFT);
+       if (!is_mft)
+               down_write_nested(&wnd->rw_lock, BITMAP_MUTEX_MFT);
        if (rno >= wnd->nbits)
                goto out;
 
@@ -727,7 +729,8 @@ void ntfs_mark_rec_free(struct ntfs_sb_info *sbi, CLST rno)
                sbi->mft.next_free = rno;
 
 out:
-       up_write(&wnd->rw_lock);
+       if (!is_mft)
+               up_write(&wnd->rw_lock);
 }
 
 /*
@@ -780,7 +783,7 @@ out:
  */
 int ntfs_refresh_zone(struct ntfs_sb_info *sbi)
 {
-       CLST zone_limit, zone_max, lcn, vcn, len;
+       CLST lcn, vcn, len;
        size_t lcn_s, zlen;
        struct wnd_bitmap *wnd = &sbi->used.bitmap;
        struct ntfs_inode *ni = sbi->mft.ni;
@@ -789,16 +792,6 @@ int ntfs_refresh_zone(struct ntfs_sb_info *sbi)
        if (wnd_zone_len(wnd))
                return 0;
 
-       /*
-        * Compute the MFT zone at two steps.
-        * It would be nice if we are able to allocate 1/8 of
-        * total clusters for MFT but not more then 512 MB.
-        */
-       zone_limit = (512 * 1024 * 1024) >> sbi->cluster_bits;
-       zone_max = wnd->nbits >> 3;
-       if (zone_max > zone_limit)
-               zone_max = zone_limit;
-
        vcn = bytes_to_cluster(sbi,
                               (u64)sbi->mft.bitmap.nbits << sbi->record_bits);
 
@@ -812,13 +805,7 @@ int ntfs_refresh_zone(struct ntfs_sb_info *sbi)
        lcn_s = lcn + 1;
 
        /* Try to allocate clusters after last MFT run. */
-       zlen = wnd_find(wnd, zone_max, lcn_s, 0, &lcn_s);
-       if (!zlen) {
-               ntfs_notice(sbi->sb, "MftZone: unavailable");
-               return 0;
-       }
-
-       /* Truncate too large zone. */
+       zlen = wnd_find(wnd, sbi->zone_max, lcn_s, 0, &lcn_s);
        wnd_zone_set(wnd, lcn_s, zlen);
 
        return 0;
@@ -827,16 +814,21 @@ int ntfs_refresh_zone(struct ntfs_sb_info *sbi)
 /*
  * ntfs_update_mftmirr - Update $MFTMirr data.
  */
-int ntfs_update_mftmirr(struct ntfs_sb_info *sbi, int wait)
+void ntfs_update_mftmirr(struct ntfs_sb_info *sbi, int wait)
 {
        int err;
        struct super_block *sb = sbi->sb;
-       u32 blocksize = sb->s_blocksize;
+       u32 blocksize;
        sector_t block1, block2;
        u32 bytes;
 
+       if (!sb)
+               return;
+
+       blocksize = sb->s_blocksize;
+
        if (!(sbi->flags & NTFS_FLAGS_MFTMIRR))
-               return 0;
+               return;
 
        err = 0;
        bytes = sbi->mft.recs_mirr << sbi->record_bits;
@@ -847,16 +839,13 @@ int ntfs_update_mftmirr(struct ntfs_sb_info *sbi, int wait)
                struct buffer_head *bh1, *bh2;
 
                bh1 = sb_bread(sb, block1++);
-               if (!bh1) {
-                       err = -EIO;
-                       goto out;
-               }
+               if (!bh1)
+                       return;
 
                bh2 = sb_getblk(sb, block2++);
                if (!bh2) {
                        put_bh(bh1);
-                       err = -EIO;
-                       goto out;
+                       return;
                }
 
                if (buffer_locked(bh2))
@@ -876,13 +865,24 @@ int ntfs_update_mftmirr(struct ntfs_sb_info *sbi, int wait)
 
                put_bh(bh2);
                if (err)
-                       goto out;
+                       return;
        }
 
        sbi->flags &= ~NTFS_FLAGS_MFTMIRR;
+}
 
-out:
-       return err;
+/*
+ * ntfs_bad_inode
+ *
+ * Marks inode as bad and marks fs as 'dirty'
+ */
+void ntfs_bad_inode(struct inode *inode, const char *hint)
+{
+       struct ntfs_sb_info *sbi = inode->i_sb->s_fs_info;
+
+       ntfs_inode_err(inode, "%s", hint);
+       make_bad_inode(inode);
+       ntfs_set_state(sbi, NTFS_DIRTY_ERROR);
 }
 
 /*
@@ -1395,7 +1395,7 @@ int ntfs_write_bh(struct ntfs_sb_info *sbi, struct NTFS_RECORD_HEADER *rhdr,
                if (buffer_locked(bh))
                        __wait_on_buffer(bh);
 
-               lock_buffer(nb->bh[idx]);
+               lock_buffer(bh);
 
                bh_data = bh->b_data + off;
                end_data = Add2Ptr(bh_data, op);
@@ -2424,7 +2424,7 @@ static inline void ntfs_unmap_and_discard(struct ntfs_sb_info *sbi, CLST lcn,
 
 void mark_as_free_ex(struct ntfs_sb_info *sbi, CLST lcn, CLST len, bool trim)
 {
-       CLST end, i;
+       CLST end, i, zone_len, zlen;
        struct wnd_bitmap *wnd = &sbi->used.bitmap;
 
        down_write_nested(&wnd->rw_lock, BITMAP_MUTEX_CLUSTERS);
@@ -2459,6 +2459,28 @@ void mark_as_free_ex(struct ntfs_sb_info *sbi, CLST lcn, CLST len, bool trim)
                ntfs_unmap_and_discard(sbi, lcn, len);
        wnd_set_free(wnd, lcn, len);
 
+       /* append to MFT zone, if possible. */
+       zone_len = wnd_zone_len(wnd);
+       zlen = min(zone_len + len, sbi->zone_max);
+
+       if (zlen == zone_len) {
+               /* MFT zone already has maximum size. */
+       } else if (!zone_len) {
+               /* Create MFT zone only if 'zlen' is large enough. */
+               if (zlen == sbi->zone_max)
+                       wnd_zone_set(wnd, lcn, zlen);
+       } else {
+               CLST zone_lcn = wnd_zone_bit(wnd);
+
+               if (lcn + len == zone_lcn) {
+                       /* Append into head MFT zone. */
+                       wnd_zone_set(wnd, lcn, zlen);
+               } else if (zone_lcn + zone_len == lcn) {
+                       /* Append into tail MFT zone. */
+                       wnd_zone_set(wnd, zone_lcn, zlen);
+               }
+       }
+
 out:
        up_write(&wnd->rw_lock);
 }
index 6f81e3a..4403281 100644 (file)
@@ -1042,19 +1042,16 @@ int indx_find(struct ntfs_index *indx, struct ntfs_inode *ni,
 {
        int err;
        struct NTFS_DE *e;
-       const struct INDEX_HDR *hdr;
        struct indx_node *node;
 
        if (!root)
                root = indx_get_root(&ni->dir, ni, NULL, NULL);
 
        if (!root) {
-               err = -EINVAL;
-               goto out;
+               /* Should not happen. */
+               return -EINVAL;
        }
 
-       hdr = &root->ihdr;
-
        /* Check cache. */
        e = fnd->level ? fnd->de[fnd->level - 1] : fnd->root_de;
        if (e && !de_is_last(e) &&
@@ -1068,39 +1065,35 @@ int indx_find(struct ntfs_index *indx, struct ntfs_inode *ni,
        fnd_clear(fnd);
 
        /* Lookup entry that is <= to the search value. */
-       e = hdr_find_e(indx, hdr, key, key_len, ctx, diff);
+       e = hdr_find_e(indx, &root->ihdr, key, key_len, ctx, diff);
        if (!e)
                return -EINVAL;
 
        fnd->root_de = e;
-       err = 0;
 
        for (;;) {
                node = NULL;
-               if (*diff >= 0 || !de_has_vcn_ex(e)) {
-                       *entry = e;
-                       goto out;
-               }
+               if (*diff >= 0 || !de_has_vcn_ex(e))
+                       break;
 
                /* Read next level. */
                err = indx_read(indx, ni, de_get_vbn(e), &node);
                if (err)
-                       goto out;
+                       return err;
 
                /* Lookup entry that is <= to the search value. */
                e = hdr_find_e(indx, &node->index->ihdr, key, key_len, ctx,
                               diff);
                if (!e) {
-                       err = -EINVAL;
                        put_indx_node(node);
-                       goto out;
+                       return -EINVAL;
                }
 
                fnd_push(fnd, node, e);
        }
 
-out:
-       return err;
+       *entry = e;
+       return 0;
 }
 
 int indx_find_sort(struct ntfs_index *indx, struct ntfs_inode *ni,
@@ -1354,7 +1347,7 @@ static int indx_create_allocate(struct ntfs_index *indx, struct ntfs_inode *ni,
                goto out;
 
        err = ni_insert_nonresident(ni, ATTR_ALLOC, in->name, in->name_len,
-                                   &run, 0, len, 0, &alloc, NULL);
+                                   &run, 0, len, 0, &alloc, NULL, NULL);
        if (err)
                goto out1;
 
@@ -1685,8 +1678,8 @@ indx_insert_into_buffer(struct ntfs_index *indx, struct ntfs_inode *ni,
 {
        int err;
        const struct NTFS_DE *sp;
-       struct NTFS_DE *e, *de_t, *up_e = NULL;
-       struct indx_node *n2 = NULL;
+       struct NTFS_DE *e, *de_t, *up_e;
+       struct indx_node *n2;
        struct indx_node *n1 = fnd->nodes[level];
        struct INDEX_HDR *hdr1 = &n1->index->ihdr;
        struct INDEX_HDR *hdr2;
@@ -1994,7 +1987,7 @@ static int indx_free_children(struct ntfs_index *indx, struct ntfs_inode *ni,
                              const struct NTFS_DE *e, bool trim)
 {
        int err;
-       struct indx_node *n;
+       struct indx_node *n = NULL;
        struct INDEX_HDR *hdr;
        CLST vbn = de_get_vbn(e);
        size_t i;
index 80104af..51363d4 100644 (file)
@@ -430,6 +430,7 @@ end_enum:
        } else if (fname && fname->home.low == cpu_to_le32(MFT_REC_EXTEND) &&
                   fname->home.seq == cpu_to_le16(MFT_REC_EXTEND)) {
                /* Records in $Extend are not a files or general directories. */
+               inode->i_op = &ntfs_file_inode_operations;
        } else {
                err = -EINVAL;
                goto out;
@@ -500,7 +501,7 @@ struct inode *ntfs_iget5(struct super_block *sb, const struct MFT_REF *ref,
                inode = ntfs_read_mft(inode, name, ref);
        else if (ref->seq != ntfs_i(inode)->mi.mrec->seq) {
                /* Inode overlaps? */
-               make_bad_inode(inode);
+               _ntfs_bad_inode(inode);
        }
 
        return inode;
@@ -1632,7 +1633,7 @@ out4:
        ni->mi.dirty = false;
        discard_new_inode(inode);
 out3:
-       ntfs_mark_rec_free(sbi, ino);
+       ntfs_mark_rec_free(sbi, ino, false);
 
 out2:
        __putname(new_de);
@@ -1655,7 +1656,6 @@ int ntfs_link_inode(struct inode *inode, struct dentry *dentry)
        struct ntfs_inode *ni = ntfs_i(inode);
        struct ntfs_sb_info *sbi = inode->i_sb->s_fs_info;
        struct NTFS_DE *de;
-       struct ATTR_FILE_NAME *de_name;
 
        /* Allocate PATH_MAX bytes. */
        de = __getname();
@@ -1670,15 +1670,6 @@ int ntfs_link_inode(struct inode *inode, struct dentry *dentry)
        if (err)
                goto out;
 
-       de_name = (struct ATTR_FILE_NAME *)(de + 1);
-       /* Fill duplicate info. */
-       de_name->dup.cr_time = de_name->dup.m_time = de_name->dup.c_time =
-               de_name->dup.a_time = kernel2nt(&inode->i_ctime);
-       de_name->dup.alloc_size = de_name->dup.data_size =
-               cpu_to_le64(inode->i_size);
-       de_name->dup.fa = ni->std_fa;
-       de_name->dup.ea_size = de_name->dup.reparse = 0;
-
        err = ni_add_name(ntfs_i(d_inode(dentry->d_parent)), ni, de);
 out:
        __putname(de);
@@ -1731,9 +1722,7 @@ int ntfs_unlink_inode(struct inode *dir, const struct dentry *dentry)
                if (inode->i_nlink)
                        mark_inode_dirty(inode);
        } else if (!ni_remove_name_undo(dir_ni, ni, de, de2, undo_remove)) {
-               make_bad_inode(inode);
-               ntfs_inode_err(inode, "failed to undo unlink");
-               ntfs_set_state(sbi, NTFS_DIRTY_ERROR);
+               _ntfs_bad_inode(inode);
        } else {
                if (ni_is_dirty(dir))
                        mark_inode_dirty(dir);
index bc74121..bc22cc3 100644 (file)
@@ -208,7 +208,7 @@ static int ntfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
 }
 
 /*
- * ntfs_rmdir - inode_operations::rm_dir
+ * ntfs_rmdir - inode_operations::rmdir
  */
 static int ntfs_rmdir(struct inode *dir, struct dentry *dentry)
 {
@@ -308,9 +308,7 @@ static int ntfs_rename(struct user_namespace *mnt_userns, struct inode *dir,
        err = ni_rename(dir_ni, new_dir_ni, ni, de, new_de, &is_bad);
        if (is_bad) {
                /* Restore after failed rename failed too. */
-               make_bad_inode(inode);
-               ntfs_inode_err(inode, "failed to undo rename");
-               ntfs_set_state(sbi, NTFS_DIRTY_ERROR);
+               _ntfs_bad_inode(inode);
        } else if (!err) {
                inode->i_ctime = dir->i_ctime = dir->i_mtime =
                        current_time(dir);
index 8dbdca0..2c79122 100644 (file)
@@ -220,6 +220,7 @@ struct ntfs_sb_info {
 
        u32 flags; // See NTFS_FLAGS_XXX.
 
+       CLST zone_max; // Maximum MFT zone length in clusters
        CLST bad_clusters; // The count of marked bad clusters.
 
        u16 max_bytes_per_attr; // Maximum attribute size in record.
@@ -408,8 +409,6 @@ enum REPARSE_SIGN {
 };
 
 /* Functions from attrib.c */
-int attr_load_runs(struct ATTRIB *attr, struct ntfs_inode *ni,
-                  struct runs_tree *run, const CLST *vcn);
 int attr_allocate_clusters(struct ntfs_sb_info *sbi, struct runs_tree *run,
                           CLST vcn, CLST lcn, CLST len, CLST *pre_alloc,
                           enum ALLOCATE_OPT opt, CLST *alen, const size_t fr,
@@ -440,6 +439,7 @@ int attr_is_frame_compressed(struct ntfs_inode *ni, struct ATTRIB *attr,
 int attr_allocate_frame(struct ntfs_inode *ni, CLST frame, size_t compr_size,
                        u64 new_valid);
 int attr_collapse_range(struct ntfs_inode *ni, u64 vbo, u64 bytes);
+int attr_insert_range(struct ntfs_inode *ni, u64 vbo, u64 bytes);
 int attr_punch_hole(struct ntfs_inode *ni, u64 vbo, u64 bytes, u32 *frame_size);
 
 /* Functions from attrlist.c */
@@ -528,7 +528,7 @@ int ni_insert_nonresident(struct ntfs_inode *ni, enum ATTR_TYPE type,
                          const __le16 *name, u8 name_len,
                          const struct runs_tree *run, CLST svcn, CLST len,
                          __le16 flags, struct ATTRIB **new_attr,
-                         struct mft_inode **mi);
+                         struct mft_inode **mi, struct ATTR_LIST_ENTRY **le);
 int ni_insert_resident(struct ntfs_inode *ni, u32 data_size,
                       enum ATTR_TYPE type, const __le16 *name, u8 name_len,
                       struct ATTRIB **new_attr, struct mft_inode **mi,
@@ -589,10 +589,12 @@ int ntfs_look_for_free_space(struct ntfs_sb_info *sbi, CLST lcn, CLST len,
                             enum ALLOCATE_OPT opt);
 int ntfs_look_free_mft(struct ntfs_sb_info *sbi, CLST *rno, bool mft,
                       struct ntfs_inode *ni, struct mft_inode **mi);
-void ntfs_mark_rec_free(struct ntfs_sb_info *sbi, CLST rno);
+void ntfs_mark_rec_free(struct ntfs_sb_info *sbi, CLST rno, bool is_mft);
 int ntfs_clear_mft_tail(struct ntfs_sb_info *sbi, size_t from, size_t to);
 int ntfs_refresh_zone(struct ntfs_sb_info *sbi);
-int ntfs_update_mftmirr(struct ntfs_sb_info *sbi, int wait);
+void ntfs_update_mftmirr(struct ntfs_sb_info *sbi, int wait);
+void ntfs_bad_inode(struct inode *inode, const char *hint);
+#define _ntfs_bad_inode(i) ntfs_bad_inode(i, __func__)
 enum NTFS_DIRTY_FLAGS {
        NTFS_DIRTY_CLEAR = 0,
        NTFS_DIRTY_DIRTY = 1,
@@ -738,7 +740,6 @@ static inline struct ATTRIB *rec_find_attr_le(struct mft_inode *rec,
 int mi_write(struct mft_inode *mi, int wait);
 int mi_format_new(struct mft_inode *mi, struct ntfs_sb_info *sbi, CLST rno,
                  __le16 flags, bool is_mft);
-void mi_mark_free(struct mft_inode *mi);
 struct ATTRIB *mi_insert_attr(struct mft_inode *mi, enum ATTR_TYPE type,
                              const __le16 *name, u8 name_len, u32 asize,
                              u16 name_off);
@@ -780,10 +781,10 @@ bool run_lookup_entry(const struct runs_tree *run, CLST vcn, CLST *lcn,
 void run_truncate(struct runs_tree *run, CLST vcn);
 void run_truncate_head(struct runs_tree *run, CLST vcn);
 void run_truncate_around(struct runs_tree *run, CLST vcn);
-bool run_lookup(const struct runs_tree *run, CLST vcn, size_t *Index);
 bool run_add_entry(struct runs_tree *run, CLST vcn, CLST lcn, CLST len,
                   bool is_mft);
 bool run_collapse_range(struct runs_tree *run, CLST vcn, CLST len);
+bool run_insert_range(struct runs_tree *run, CLST vcn, CLST len);
 bool run_get_entry(const struct runs_tree *run, size_t index, CLST *vcn,
                   CLST *lcn, CLST *len);
 bool run_is_mapped_full(const struct runs_tree *run, CLST svcn, CLST evcn);
@@ -802,6 +803,7 @@ int run_unpack_ex(struct runs_tree *run, struct ntfs_sb_info *sbi, CLST ino,
 #define run_unpack_ex run_unpack
 #endif
 int run_get_highest_vcn(CLST vcn, const u8 *run_buf, u64 *highest_vcn);
+int run_clone(const struct runs_tree *run, struct runs_tree *new_run);
 
 /* Globals from super.c */
 void *ntfs_set_shared(void *ptr, u32 bytes);
index 861e357..7d2fac5 100644 (file)
@@ -395,28 +395,6 @@ int mi_format_new(struct mft_inode *mi, struct ntfs_sb_info *sbi, CLST rno,
 }
 
 /*
- * mi_mark_free - Mark record as unused and marks it as free in bitmap.
- */
-void mi_mark_free(struct mft_inode *mi)
-{
-       CLST rno = mi->rno;
-       struct ntfs_sb_info *sbi = mi->sbi;
-
-       if (rno >= MFT_REC_RESERVED && rno < MFT_REC_FREE) {
-               ntfs_clear_mft_tail(sbi, rno, rno + 1);
-               mi->dirty = false;
-               return;
-       }
-
-       if (mi->mrec) {
-               clear_rec_inuse(mi->mrec);
-               mi->dirty = true;
-               mi_write(mi, 0);
-       }
-       ntfs_mark_rec_free(sbi, rno);
-}
-
-/*
  * mi_insert_attr - Reserve space for new attribute.
  *
  * Return: Not full constructed attribute or NULL if not possible to create.
@@ -445,12 +423,11 @@ struct ATTRIB *mi_insert_attr(struct mft_inode *mi, enum ATTR_TYPE type,
        attr = NULL;
        while ((attr = mi_enum_attr(mi, attr))) {
                diff = compare_attr(attr, type, name, name_len, upcase);
-               if (diff > 0)
-                       break;
+
                if (diff < 0)
                        continue;
 
-               if (!is_attr_indexed(attr))
+               if (!diff && !is_attr_indexed(attr))
                        return NULL;
                break;
        }
index a8fec65..aaaa0d3 100644 (file)
@@ -31,7 +31,7 @@ struct ntfs_run {
  * Case of entry missing from list 'index' will be set to
  * point to insertion position for the entry question.
  */
-bool run_lookup(const struct runs_tree *run, CLST vcn, size_t *index)
+static bool run_lookup(const struct runs_tree *run, CLST vcn, size_t *index)
 {
        size_t min_idx, max_idx, mid_idx;
        struct ntfs_run *r;
@@ -547,6 +547,48 @@ bool run_collapse_range(struct runs_tree *run, CLST vcn, CLST len)
        return true;
 }
 
+/* run_insert_range
+ *
+ * Helper for attr_insert_range(),
+ * which is helper for fallocate(insert_range).
+ */
+bool run_insert_range(struct runs_tree *run, CLST vcn, CLST len)
+{
+       size_t index;
+       struct ntfs_run *r, *e;
+
+       if (WARN_ON(!run_lookup(run, vcn, &index)))
+               return false; /* Should never be here. */
+
+       e = run->runs + run->count;
+       r = run->runs + index;
+
+       if (vcn > r->vcn)
+               r += 1;
+
+       for (; r < e; r++)
+               r->vcn += len;
+
+       r = run->runs + index;
+
+       if (vcn > r->vcn) {
+               /* split fragment. */
+               CLST len1 = vcn - r->vcn;
+               CLST len2 = r->len - len1;
+               CLST lcn2 = r->lcn == SPARSE_LCN ? SPARSE_LCN : (r->lcn + len1);
+
+               r->len = len1;
+
+               if (!run_add_entry(run, vcn + len, lcn2, len2, false))
+                       return false;
+       }
+
+       if (!run_add_entry(run, vcn, SPARSE_LCN, len, false))
+               return false;
+
+       return true;
+}
+
 /*
  * run_get_entry - Return index-th mapped region.
  */
@@ -778,26 +820,36 @@ int run_pack(const struct runs_tree *run, CLST svcn, CLST len, u8 *run_buf,
        CLST next_vcn, vcn, lcn;
        CLST prev_lcn = 0;
        CLST evcn1 = svcn + len;
+       const struct ntfs_run *r, *r_end;
        int packed_size = 0;
        size_t i;
-       bool ok;
        s64 dlcn;
        int offset_size, size_size, tmp;
 
-       next_vcn = vcn = svcn;
-
        *packed_vcns = 0;
 
        if (!len)
                goto out;
 
-       ok = run_lookup_entry(run, vcn, &lcn, &len, &i);
+       /* Check all required entries [svcn, encv1) available. */
+       if (!run_lookup(run, svcn, &i))
+               return -ENOENT;
+
+       r_end = run->runs + run->count;
+       r = run->runs + i;
 
-       if (!ok)
-               goto error;
+       for (next_vcn = r->vcn + r->len; next_vcn < evcn1;
+            next_vcn = r->vcn + r->len) {
+               if (++r >= r_end || r->vcn != next_vcn)
+                       return -ENOENT;
+       }
 
-       if (next_vcn != vcn)
-               goto error;
+       /* Repeat cycle above and pack runs. Assume no errors. */
+       r = run->runs + i;
+       len = svcn - r->vcn;
+       vcn = svcn;
+       lcn = r->lcn == SPARSE_LCN ? SPARSE_LCN : (r->lcn + len);
+       len = r->len - len;
 
        for (;;) {
                next_vcn = vcn + len;
@@ -846,12 +898,10 @@ int run_pack(const struct runs_tree *run, CLST svcn, CLST len, u8 *run_buf,
                if (packed_size + 1 >= run_buf_size || next_vcn >= evcn1)
                        goto out;
 
-               ok = run_get_entry(run, ++i, &vcn, &lcn, &len);
-               if (!ok)
-                       goto error;
-
-               if (next_vcn != vcn)
-                       goto error;
+               r += 1;
+               vcn = r->vcn;
+               lcn = r->lcn;
+               len = r->len;
        }
 
 out:
@@ -860,9 +910,6 @@ out:
                run_buf[0] = 0;
 
        return packed_size + 1;
-
-error:
-       return -EOPNOTSUPP;
 }
 
 /*
@@ -1109,3 +1156,28 @@ int run_get_highest_vcn(CLST vcn, const u8 *run_buf, u64 *highest_vcn)
        *highest_vcn = vcn64 - 1;
        return 0;
 }
+
+/*
+ * run_clone
+ *
+ * Make a copy of run
+ */
+int run_clone(const struct runs_tree *run, struct runs_tree *new_run)
+{
+       size_t bytes = run->count * sizeof(struct ntfs_run);
+
+       if (bytes > new_run->allocated) {
+               struct ntfs_run *new_ptr = kvmalloc(bytes, GFP_KERNEL);
+
+               if (!new_ptr)
+                       return -ENOMEM;
+
+               kvfree(new_run->runs);
+               new_run->runs = new_ptr;
+               new_run->allocated = bytes;
+       }
+
+       memcpy(new_run->runs, run->runs, bytes);
+       new_run->count = run->count;
+       return 0;
+}
index 0c6de62..47012c9 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/fs_context.h>
 #include <linux/fs_parser.h>
 #include <linux/log2.h>
+#include <linux/minmax.h>
 #include <linux/module.h>
 #include <linux/nls.h>
 #include <linux/seq_file.h>
@@ -390,7 +391,7 @@ static int ntfs_fs_reconfigure(struct fs_context *fc)
                return -EINVAL;
        }
 
-       memcpy(sbi->options, new_opts, sizeof(*new_opts));
+       swap(sbi->options, fc->fs_private);
 
        return 0;
 }
@@ -870,6 +871,13 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size,
        sb->s_maxbytes = 0xFFFFFFFFull << sbi->cluster_bits;
 #endif
 
+       /*
+        * Compute the MFT zone at two steps.
+        * It would be nice if we are able to allocate 1/8 of
+        * total clusters for MFT but not more then 512 MB.
+        */
+       sbi->zone_max = min_t(CLST, 0x20000000 >> sbi->cluster_bits, clusters >> 3);
+
        err = 0;
 
 out:
@@ -900,6 +908,8 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
        ref.high = 0;
 
        sbi->sb = sb;
+       sbi->options = fc->fs_private;
+       fc->fs_private = NULL;
        sb->s_flags |= SB_NODIRATIME;
        sb->s_magic = 0x7366746e; // "ntfs"
        sb->s_op = &ntfs_sops;
@@ -1262,8 +1272,6 @@ load_root:
                goto put_inode_out;
        }
 
-       fc->fs_private = NULL;
-
        return 0;
 
 put_inode_out:
@@ -1378,7 +1386,7 @@ static const struct fs_context_operations ntfs_context_ops = {
 /*
  * ntfs_init_fs_context - Initialize spi and opts
  *
- * This will called when mount/remount. We will first initiliaze
+ * This will called when mount/remount. We will first initialize
  * options so that if remount we can use just that.
  */
 static int ntfs_init_fs_context(struct fs_context *fc)
@@ -1416,7 +1424,6 @@ static int ntfs_init_fs_context(struct fs_context *fc)
        mutex_init(&sbi->compress.mtx_lzx);
 #endif
 
-       sbi->options = opts;
        fc->s_fs_info = sbi;
 ok:
        fc->fs_private = opts;
index 5e0e028..6ae1f56 100644 (file)
@@ -118,7 +118,7 @@ static int ntfs_read_ea(struct ntfs_inode *ni, struct EA_FULL **ea,
 
                run_init(&run);
 
-               err = attr_load_runs(attr_ea, ni, &run, NULL);
+               err = attr_load_runs_range(ni, ATTR_EA, NULL, 0, &run, 0, size);
                if (!err)
                        err = ntfs_read_run_nb(sbi, &run, 0, ea_p, size, NULL);
                run_close(&run);
@@ -444,6 +444,11 @@ update_ea:
                /* Delete xattr, ATTR_EA */
                ni_remove_attr_le(ni, attr, mi, le);
        } else if (attr->non_res) {
+               err = attr_load_runs_range(ni, ATTR_EA, NULL, 0, &ea_run, 0,
+                                          size);
+               if (err)
+                       goto out;
+
                err = ntfs_sb_write_run(sbi, &ea_run, 0, ea_all, size, 0);
                if (err)
                        goto out;
@@ -478,8 +483,7 @@ out:
 }
 
 #ifdef CONFIG_NTFS3_FS_POSIX_ACL
-static struct posix_acl *ntfs_get_acl_ex(struct user_namespace *mnt_userns,
-                                        struct inode *inode, int type,
+static struct posix_acl *ntfs_get_acl_ex(struct inode *inode, int type,
                                         int locked)
 {
        struct ntfs_inode *ni = ntfs_i(inode);
@@ -514,7 +518,7 @@ static struct posix_acl *ntfs_get_acl_ex(struct user_namespace *mnt_userns,
 
        /* Translate extended attribute to acl. */
        if (err >= 0) {
-               acl = posix_acl_from_xattr(mnt_userns, buf, err);
+               acl = posix_acl_from_xattr(&init_user_ns, buf, err);
        } else if (err == -ENODATA) {
                acl = NULL;
        } else {
@@ -537,8 +541,7 @@ struct posix_acl *ntfs_get_acl(struct inode *inode, int type, bool rcu)
        if (rcu)
                return ERR_PTR(-ECHILD);
 
-       /* TODO: init_user_ns? */
-       return ntfs_get_acl_ex(&init_user_ns, inode, type, 0);
+       return ntfs_get_acl_ex(inode, type, 0);
 }
 
 static noinline int ntfs_set_acl_ex(struct user_namespace *mnt_userns,
@@ -547,28 +550,23 @@ static noinline int ntfs_set_acl_ex(struct user_namespace *mnt_userns,
 {
        const char *name;
        size_t size, name_len;
-       void *value = NULL;
-       int err = 0;
+       void *value;
+       int err;
        int flags;
+       umode_t mode;
 
        if (S_ISLNK(inode->i_mode))
                return -EOPNOTSUPP;
 
+       mode = inode->i_mode;
        switch (type) {
        case ACL_TYPE_ACCESS:
                /* Do not change i_mode if we are in init_acl */
                if (acl && !init_acl) {
-                       umode_t mode;
-
                        err = posix_acl_update_mode(mnt_userns, inode, &mode,
                                                    &acl);
                        if (err)
-                               goto out;
-
-                       if (inode->i_mode != mode) {
-                               inode->i_mode = mode;
-                               mark_inode_dirty(inode);
-                       }
+                               return err;
                }
                name = XATTR_NAME_POSIX_ACL_ACCESS;
                name_len = sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1;
@@ -595,7 +593,7 @@ static noinline int ntfs_set_acl_ex(struct user_namespace *mnt_userns,
                value = kmalloc(size, GFP_NOFS);
                if (!value)
                        return -ENOMEM;
-               err = posix_acl_to_xattr(mnt_userns, acl, value, size);
+               err = posix_acl_to_xattr(&init_user_ns, acl, value, size);
                if (err < 0)
                        goto out;
                flags = 0;
@@ -604,8 +602,13 @@ static noinline int ntfs_set_acl_ex(struct user_namespace *mnt_userns,
        err = ntfs_set_ea(inode, name, name_len, value, size, flags, 0);
        if (err == -ENODATA && !size)
                err = 0; /* Removing non existed xattr. */
-       if (!err)
+       if (!err) {
                set_cached_acl(inode, type, acl);
+               if (inode->i_mode != mode) {
+                       inode->i_mode = mode;
+                       mark_inode_dirty(inode);
+               }
+       }
 
 out:
        kfree(value);
@@ -641,7 +644,7 @@ static int ntfs_xattr_get_acl(struct user_namespace *mnt_userns,
        if (!acl)
                return -ENODATA;
 
-       err = posix_acl_to_xattr(mnt_userns, acl, buffer, size);
+       err = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
        posix_acl_release(acl);
 
        return err;
@@ -665,12 +668,12 @@ static int ntfs_xattr_set_acl(struct user_namespace *mnt_userns,
        if (!value) {
                acl = NULL;
        } else {
-               acl = posix_acl_from_xattr(mnt_userns, value, size);
+               acl = posix_acl_from_xattr(&init_user_ns, value, size);
                if (IS_ERR(acl))
                        return PTR_ERR(acl);
 
                if (acl) {
-                       err = posix_acl_valid(mnt_userns, acl);
+                       err = posix_acl_valid(&init_user_ns, acl);
                        if (err)
                                goto release_and_out;
                }
@@ -706,13 +709,13 @@ int ntfs_init_acl(struct user_namespace *mnt_userns, struct inode *inode,
                inode->i_default_acl = NULL;
        }
 
-       if (!acl)
-               inode->i_acl = NULL;
-       else {
+       if (acl) {
                if (!err)
                        err = ntfs_set_acl_ex(mnt_userns, inode, acl,
                                              ACL_TYPE_ACCESS, true);
                posix_acl_release(acl);
+       } else {
+               inode->i_acl = NULL;
        }
 
        return err;
index 801e60b..c28bc98 100644 (file)
@@ -3403,10 +3403,12 @@ void ocfs2_dlm_shutdown(struct ocfs2_super *osb,
        ocfs2_lock_res_free(&osb->osb_nfs_sync_lockres);
        ocfs2_lock_res_free(&osb->osb_orphan_scan.os_lockres);
 
-       ocfs2_cluster_disconnect(osb->cconn, hangup_pending);
-       osb->cconn = NULL;
+       if (osb->cconn) {
+               ocfs2_cluster_disconnect(osb->cconn, hangup_pending);
+               osb->cconn = NULL;
 
-       ocfs2_dlm_shutdown_debug(osb);
+               ocfs2_dlm_shutdown_debug(osb);
+       }
 }
 
 static int ocfs2_drop_lock(struct ocfs2_super *osb,
index 013a727..e2cc9ee 100644 (file)
@@ -1914,8 +1914,7 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err)
            !ocfs2_is_hard_readonly(osb))
                hangup_needed = 1;
 
-       if (osb->cconn)
-               ocfs2_dlm_shutdown(osb, hangup_needed);
+       ocfs2_dlm_shutdown(osb, hangup_needed);
 
        ocfs2_blockcheck_stats_debugfs_remove(&osb->osb_ecc_stats);
        debugfs_remove_recursive(osb->osb_debug_root);
index 8a813fa..cf7e5c3 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -716,6 +716,8 @@ int chown_common(const struct path *path, uid_t user, gid_t group)
        fs_userns = i_user_ns(inode);
 
 retry_deleg:
+       newattrs.ia_vfsuid = INVALID_VFSUID;
+       newattrs.ia_vfsgid = INVALID_VFSGID;
        newattrs.ia_valid =  ATTR_CTIME;
        if ((user != (uid_t)-1) && !setattr_vfsuid(&newattrs, uid))
                return -EINVAL;
index b45fea6..0fbcb59 100644 (file)
@@ -460,9 +460,12 @@ ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size)
  * of the POSIX ACLs retrieved from the lower layer to this function to not
  * alter the POSIX ACLs for the underlying filesystem.
  */
-static void ovl_idmap_posix_acl(struct user_namespace *mnt_userns,
+static void ovl_idmap_posix_acl(struct inode *realinode,
+                               struct user_namespace *mnt_userns,
                                struct posix_acl *acl)
 {
+       struct user_namespace *fs_userns = i_user_ns(realinode);
+
        for (unsigned int i = 0; i < acl->a_count; i++) {
                vfsuid_t vfsuid;
                vfsgid_t vfsgid;
@@ -470,11 +473,11 @@ static void ovl_idmap_posix_acl(struct user_namespace *mnt_userns,
                struct posix_acl_entry *e = &acl->a_entries[i];
                switch (e->e_tag) {
                case ACL_USER:
-                       vfsuid = make_vfsuid(mnt_userns, &init_user_ns, e->e_uid);
+                       vfsuid = make_vfsuid(mnt_userns, fs_userns, e->e_uid);
                        e->e_uid = vfsuid_into_kuid(vfsuid);
                        break;
                case ACL_GROUP:
-                       vfsgid = make_vfsgid(mnt_userns, &init_user_ns, e->e_gid);
+                       vfsgid = make_vfsgid(mnt_userns, fs_userns, e->e_gid);
                        e->e_gid = vfsgid_into_kgid(vfsgid);
                        break;
                }
@@ -536,7 +539,7 @@ struct posix_acl *ovl_get_acl(struct inode *inode, int type, bool rcu)
        if (!clone)
                clone = ERR_PTR(-ENOMEM);
        else
-               ovl_idmap_posix_acl(mnt_user_ns(realpath.mnt), clone);
+               ovl_idmap_posix_acl(realinode, mnt_user_ns(realpath.mnt), clone);
        /*
         * Since we're not in RCU path walk we always need to release the
         * original ACLs.
index 1d17d7b..5af3380 100644 (file)
@@ -361,6 +361,7 @@ posix_acl_permission(struct user_namespace *mnt_userns, struct inode *inode,
                     const struct posix_acl *acl, int want)
 {
        const struct posix_acl_entry *pa, *pe, *mask_obj;
+       struct user_namespace *fs_userns = i_user_ns(inode);
        int found = 0;
        vfsuid_t vfsuid;
        vfsgid_t vfsgid;
@@ -376,7 +377,7 @@ posix_acl_permission(struct user_namespace *mnt_userns, struct inode *inode,
                                         goto check_perm;
                                 break;
                         case ACL_USER:
-                               vfsuid = make_vfsuid(mnt_userns, &init_user_ns,
+                               vfsuid = make_vfsuid(mnt_userns, fs_userns,
                                                     pa->e_uid);
                                if (vfsuid_eq_kuid(vfsuid, current_fsuid()))
                                         goto mask;
@@ -390,7 +391,7 @@ posix_acl_permission(struct user_namespace *mnt_userns, struct inode *inode,
                                 }
                                break;
                         case ACL_GROUP:
-                               vfsgid = make_vfsgid(mnt_userns, &init_user_ns,
+                               vfsgid = make_vfsgid(mnt_userns, fs_userns,
                                                     pa->e_gid);
                                if (vfsgid_in_group_p(vfsgid)) {
                                        found = 1;
@@ -736,6 +737,7 @@ void posix_acl_getxattr_idmapped_mnt(struct user_namespace *mnt_userns,
 {
        struct posix_acl_xattr_header *header = value;
        struct posix_acl_xattr_entry *entry = (void *)(header + 1), *end;
+       struct user_namespace *fs_userns = i_user_ns(inode);
        int count;
        vfsuid_t vfsuid;
        vfsgid_t vfsgid;
@@ -753,13 +755,13 @@ void posix_acl_getxattr_idmapped_mnt(struct user_namespace *mnt_userns,
                switch (le16_to_cpu(entry->e_tag)) {
                case ACL_USER:
                        uid = make_kuid(&init_user_ns, le32_to_cpu(entry->e_id));
-                       vfsuid = make_vfsuid(mnt_userns, &init_user_ns, uid);
+                       vfsuid = make_vfsuid(mnt_userns, fs_userns, uid);
                        entry->e_id = cpu_to_le32(from_kuid(&init_user_ns,
                                                vfsuid_into_kuid(vfsuid)));
                        break;
                case ACL_GROUP:
                        gid = make_kgid(&init_user_ns, le32_to_cpu(entry->e_id));
-                       vfsgid = make_vfsgid(mnt_userns, &init_user_ns, gid);
+                       vfsgid = make_vfsgid(mnt_userns, fs_userns, gid);
                        entry->e_id = cpu_to_le32(from_kgid(&init_user_ns,
                                                vfsgid_into_kgid(vfsgid)));
                        break;
@@ -775,6 +777,7 @@ void posix_acl_setxattr_idmapped_mnt(struct user_namespace *mnt_userns,
 {
        struct posix_acl_xattr_header *header = value;
        struct posix_acl_xattr_entry *entry = (void *)(header + 1), *end;
+       struct user_namespace *fs_userns = i_user_ns(inode);
        int count;
        vfsuid_t vfsuid;
        vfsgid_t vfsgid;
@@ -793,13 +796,13 @@ void posix_acl_setxattr_idmapped_mnt(struct user_namespace *mnt_userns,
                case ACL_USER:
                        uid = make_kuid(&init_user_ns, le32_to_cpu(entry->e_id));
                        vfsuid = VFSUIDT_INIT(uid);
-                       uid = from_vfsuid(mnt_userns, &init_user_ns, vfsuid);
+                       uid = from_vfsuid(mnt_userns, fs_userns, vfsuid);
                        entry->e_id = cpu_to_le32(from_kuid(&init_user_ns, uid));
                        break;
                case ACL_GROUP:
                        gid = make_kgid(&init_user_ns, le32_to_cpu(entry->e_id));
                        vfsgid = VFSGIDT_INIT(gid);
-                       gid = from_vfsgid(mnt_userns, &init_user_ns, vfsgid);
+                       gid = from_vfsgid(mnt_userns, fs_userns, vfsgid);
                        entry->e_id = cpu_to_le32(from_kgid(&init_user_ns, gid));
                        break;
                default:
index a3398d0..4e00236 100644 (file)
@@ -527,10 +527,12 @@ static void smaps_pte_entry(pte_t *pte, unsigned long addr,
        struct vm_area_struct *vma = walk->vma;
        bool locked = !!(vma->vm_flags & VM_LOCKED);
        struct page *page = NULL;
-       bool migration = false;
+       bool migration = false, young = false, dirty = false;
 
        if (pte_present(*pte)) {
                page = vm_normal_page(vma, addr, *pte);
+               young = pte_young(*pte);
+               dirty = pte_dirty(*pte);
        } else if (is_swap_pte(*pte)) {
                swp_entry_t swpent = pte_to_swp_entry(*pte);
 
@@ -560,8 +562,7 @@ static void smaps_pte_entry(pte_t *pte, unsigned long addr,
        if (!page)
                return;
 
-       smaps_account(mss, page, false, pte_young(*pte), pte_dirty(*pte),
-                     locked, migration);
+       smaps_account(mss, page, false, young, dirty, locked, migration);
 }
 
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
index 98e64fe..e565109 100644 (file)
@@ -593,7 +593,7 @@ static void squashfs_readahead(struct readahead_control *ractl)
 
                res = squashfs_read_data(inode->i_sb, block, bsize, NULL, actor);
 
-               kfree(actor);
+               squashfs_page_actor_free(actor);
 
                if (res == expected) {
                        int bytes;
index be4b12d..f1ccad5 100644 (file)
@@ -74,7 +74,7 @@ int squashfs_readpage_block(struct page *target_page, u64 block, int bsize,
        /* Decompress directly into the page cache buffers */
        res = squashfs_read_data(inode->i_sb, block, bsize, NULL, actor);
 
-       kfree(actor);
+       squashfs_page_actor_free(actor);
 
        if (res < 0)
                goto mark_errored;
index b23b780..54b93bf 100644 (file)
@@ -52,6 +52,7 @@ struct squashfs_page_actor *squashfs_page_actor_init(void **buffer,
        actor->buffer = buffer;
        actor->pages = pages;
        actor->next_page = 0;
+       actor->tmp_buffer = NULL;
        actor->squashfs_first_page = cache_first_page;
        actor->squashfs_next_page = cache_next_page;
        actor->squashfs_finish_page = cache_finish_page;
@@ -68,20 +69,9 @@ static void *handle_next_page(struct squashfs_page_actor *actor)
 
        if ((actor->next_page == actor->pages) ||
                        (actor->next_index != actor->page[actor->next_page]->index)) {
-               if (actor->alloc_buffer) {
-                       void *tmp_buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
-
-                       if (tmp_buffer) {
-                               actor->tmp_buffer = tmp_buffer;
-                               actor->next_index++;
-                               actor->returned_pages++;
-                               return tmp_buffer;
-                       }
-               }
-
                actor->next_index++;
                actor->returned_pages++;
-               return ERR_PTR(-ENOMEM);
+               return actor->alloc_buffer ? actor->tmp_buffer : ERR_PTR(-ENOMEM);
        }
 
        actor->next_index++;
@@ -96,11 +86,10 @@ static void *direct_first_page(struct squashfs_page_actor *actor)
 
 static void *direct_next_page(struct squashfs_page_actor *actor)
 {
-       if (actor->pageaddr)
+       if (actor->pageaddr) {
                kunmap_local(actor->pageaddr);
-
-       kfree(actor->tmp_buffer);
-       actor->pageaddr = actor->tmp_buffer = NULL;
+               actor->pageaddr = NULL;
+       }
 
        return handle_next_page(actor);
 }
@@ -109,8 +98,6 @@ static void direct_finish_page(struct squashfs_page_actor *actor)
 {
        if (actor->pageaddr)
                kunmap_local(actor->pageaddr);
-
-       kfree(actor->tmp_buffer);
 }
 
 struct squashfs_page_actor *squashfs_page_actor_init_special(struct squashfs_sb_info *msblk,
@@ -121,6 +108,16 @@ struct squashfs_page_actor *squashfs_page_actor_init_special(struct squashfs_sb_
        if (actor == NULL)
                return NULL;
 
+       if (msblk->decompressor->alloc_buffer) {
+               actor->tmp_buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
+
+               if (actor->tmp_buffer == NULL) {
+                       kfree(actor);
+                       return NULL;
+               }
+       } else
+               actor->tmp_buffer = NULL;
+
        actor->length = length ? : pages * PAGE_SIZE;
        actor->page = page;
        actor->pages = pages;
@@ -128,7 +125,6 @@ struct squashfs_page_actor *squashfs_page_actor_init_special(struct squashfs_sb_
        actor->returned_pages = 0;
        actor->next_index = page[0]->index & ~((1 << (msblk->block_log - PAGE_SHIFT)) - 1);
        actor->pageaddr = NULL;
-       actor->tmp_buffer = NULL;
        actor->alloc_buffer = msblk->decompressor->alloc_buffer;
        actor->squashfs_first_page = direct_first_page;
        actor->squashfs_next_page = direct_next_page;
index 24841d2..95ffbb5 100644 (file)
@@ -29,6 +29,11 @@ extern struct squashfs_page_actor *squashfs_page_actor_init(void **buffer,
 extern struct squashfs_page_actor *squashfs_page_actor_init_special(
                                struct squashfs_sb_info *msblk,
                                struct page **page, int pages, int length);
+static inline void squashfs_page_actor_free(struct squashfs_page_actor *actor)
+{
+       kfree(actor->tmp_buffer);
+       kfree(actor);
+}
 static inline void *squashfs_first_page(struct squashfs_page_actor *actor)
 {
        return actor->squashfs_first_page(actor);
index 81d26ab..da85b39 100644 (file)
@@ -141,6 +141,8 @@ struct tracefs_mount_opts {
        kuid_t uid;
        kgid_t gid;
        umode_t mode;
+       /* Opt_* bitfield. */
+       unsigned int opts;
 };
 
 enum {
@@ -241,6 +243,7 @@ static int tracefs_parse_options(char *data, struct tracefs_mount_opts *opts)
        kgid_t gid;
        char *p;
 
+       opts->opts = 0;
        opts->mode = TRACEFS_DEFAULT_MODE;
 
        while ((p = strsep(&data, ",")) != NULL) {
@@ -275,24 +278,36 @@ static int tracefs_parse_options(char *data, struct tracefs_mount_opts *opts)
                 * but traditionally tracefs has ignored all mount options
                 */
                }
+
+               opts->opts |= BIT(token);
        }
 
        return 0;
 }
 
-static int tracefs_apply_options(struct super_block *sb)
+static int tracefs_apply_options(struct super_block *sb, bool remount)
 {
        struct tracefs_fs_info *fsi = sb->s_fs_info;
        struct inode *inode = d_inode(sb->s_root);
        struct tracefs_mount_opts *opts = &fsi->mount_opts;
 
-       inode->i_mode &= ~S_IALLUGO;
-       inode->i_mode |= opts->mode;
+       /*
+        * On remount, only reset mode/uid/gid if they were provided as mount
+        * options.
+        */
+
+       if (!remount || opts->opts & BIT(Opt_mode)) {
+               inode->i_mode &= ~S_IALLUGO;
+               inode->i_mode |= opts->mode;
+       }
 
-       inode->i_uid = opts->uid;
+       if (!remount || opts->opts & BIT(Opt_uid))
+               inode->i_uid = opts->uid;
 
-       /* Set all the group ids to the mount option */
-       set_gid(sb->s_root, opts->gid);
+       if (!remount || opts->opts & BIT(Opt_gid)) {
+               /* Set all the group ids to the mount option */
+               set_gid(sb->s_root, opts->gid);
+       }
 
        return 0;
 }
@@ -307,7 +322,7 @@ static int tracefs_remount(struct super_block *sb, int *flags, char *data)
        if (err)
                goto fail;
 
-       tracefs_apply_options(sb);
+       tracefs_apply_options(sb, true);
 
 fail:
        return err;
@@ -359,7 +374,7 @@ static int trace_fill_super(struct super_block *sb, void *data, int silent)
 
        sb->s_op = &tracefs_super_operations;
 
-       tracefs_apply_options(sb);
+       tracefs_apply_options(sb, false);
 
        return 0;
 
index 1c44bf7..175de70 100644 (file)
@@ -1601,6 +1601,10 @@ static int userfaultfd_unregister(struct userfaultfd_ctx *ctx,
                        wake_userfault(vma->vm_userfaultfd_ctx.ctx, &range);
                }
 
+               /* Reset ptes for the whole vma range if wr-protected */
+               if (userfaultfd_wp(vma))
+                       uffd_wp_range(mm, vma, start, vma_end - start, false);
+
                new_flags = vma->vm_flags & ~__VM_UFFD_FLAGS;
                prev = vma_merge(mm, prev, start, vma_end, new_flags,
                                 vma->anon_vma, vma->vm_file, vma->vm_pgoff,
index 3096f08..71ab4ba 100644 (file)
@@ -39,9 +39,6 @@ arch_test_and_set_bit(unsigned int nr, volatile unsigned long *p)
        unsigned long mask = BIT_MASK(nr);
 
        p += BIT_WORD(nr);
-       if (READ_ONCE(*p) & mask)
-               return 1;
-
        old = arch_atomic_long_fetch_or(mask, (atomic_long_t *)p);
        return !!(old & mask);
 }
@@ -53,9 +50,6 @@ arch_test_and_clear_bit(unsigned int nr, volatile unsigned long *p)
        unsigned long mask = BIT_MASK(nr);
 
        p += BIT_WORD(nr);
-       if (!(READ_ONCE(*p) & mask))
-               return 0;
-
        old = arch_atomic_long_fetch_andnot(mask, (atomic_long_t *)p);
        return !!(old & mask);
 }
index 3d5ebd2..564a8c6 100644 (file)
@@ -4,6 +4,7 @@
 #define __ASM_GENERIC_BITOPS_GENERIC_NON_ATOMIC_H
 
 #include <linux/bits.h>
+#include <asm/barrier.h>
 
 #ifndef _LINUX_BITOPS_H
 #error only <linux/bitops.h> can be included directly
@@ -127,6 +128,18 @@ generic_test_bit(unsigned long nr, const volatile unsigned long *addr)
        return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1)));
 }
 
+/**
+ * generic_test_bit_acquire - Determine, with acquire semantics, whether a bit is set
+ * @nr: bit number to test
+ * @addr: Address to start counting from
+ */
+static __always_inline bool
+generic_test_bit_acquire(unsigned long nr, const volatile unsigned long *addr)
+{
+       unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
+       return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1)));
+}
+
 /*
  * const_*() definitions provide good compile-time optimizations when
  * the passed arguments can be resolved at compile time.
@@ -137,6 +150,7 @@ generic_test_bit(unsigned long nr, const volatile unsigned long *addr)
 #define const___test_and_set_bit       generic___test_and_set_bit
 #define const___test_and_clear_bit     generic___test_and_clear_bit
 #define const___test_and_change_bit    generic___test_and_change_bit
+#define const_test_bit_acquire         generic_test_bit_acquire
 
 /**
  * const_test_bit - Determine whether a bit is set
index 988a3bb..2b238b1 100644 (file)
@@ -142,4 +142,16 @@ _test_bit(unsigned long nr, const volatile unsigned long *addr)
        return arch_test_bit(nr, addr);
 }
 
+/**
+ * _test_bit_acquire - Determine, with acquire semantics, whether a bit is set
+ * @nr: bit number to test
+ * @addr: Address to start counting from
+ */
+static __always_inline bool
+_test_bit_acquire(unsigned long nr, const volatile unsigned long *addr)
+{
+       instrument_atomic_read(addr + BIT_WORD(nr), sizeof(long));
+       return arch_test_bit_acquire(nr, addr);
+}
+
 #endif /* _ASM_GENERIC_BITOPS_INSTRUMENTED_NON_ATOMIC_H */
index 5c37ced..71f8d54 100644 (file)
@@ -13,6 +13,7 @@
 #define arch___test_and_change_bit generic___test_and_change_bit
 
 #define arch_test_bit generic_test_bit
+#define arch_test_bit_acquire generic_test_bit_acquire
 
 #include <asm-generic/bitops/non-instrumented-non-atomic.h>
 
index bdb9b1f..0ddc78d 100644 (file)
@@ -12,5 +12,6 @@
 #define ___test_and_change_bit arch___test_and_change_bit
 
 #define _test_bit              arch_test_bit
+#define _test_bit_acquire      arch_test_bit_acquire
 
 #endif /* __ASM_GENERIC_BITOPS_NON_INSTRUMENTED_NON_ATOMIC_H */
index d0f7bdd..db13bb6 100644 (file)
@@ -97,7 +97,7 @@ static inline bool memory_contains(void *begin, void *end, void *virt,
 /**
  * memory_intersects - checks if the region occupied by an object intersects
  *                     with another memory region
- * @begin: virtual address of the beginning of the memory regien
+ * @begin: virtual address of the beginning of the memory region
  * @end: virtual address of the end of the memory region
  * @virt: virtual address of the memory object
  * @size: size of the memory object
@@ -110,7 +110,10 @@ static inline bool memory_intersects(void *begin, void *end, void *virt,
 {
        void *vend = virt + size;
 
-       return (virt >= begin && virt < end) || (vend >= begin && vend < end);
+       if (virt < end && vend > begin)
+               return true;
+
+       return false;
 }
 
 /**
index d3e2d81..2a67aed 100644 (file)
@@ -2,7 +2,7 @@
 #ifndef __ASM_GENERIC_SOFTIRQ_STACK_H
 #define __ASM_GENERIC_SOFTIRQ_STACK_H
 
-#if defined(CONFIG_HAVE_SOFTIRQ_ON_OWN_STACK) && !defined(CONFIG_PREEMPT_RT)
+#ifdef CONFIG_SOFTIRQ_ON_OWN_STACK
 void do_softirq_own_stack(void);
 #else
 static inline void do_softirq_own_stack(void)
index a1705d6..7df7876 100644 (file)
@@ -319,8 +319,8 @@ enum drm_panel_orientation {
  *             EDID's detailed monitor range
  */
 struct drm_monitor_range_info {
-       u8 min_vfreq;
-       u8 max_vfreq;
+       u16 min_vfreq;
+       u16 max_vfreq;
 };
 
 /**
index 2181977..1ed61e2 100644 (file)
@@ -92,6 +92,11 @@ struct detailed_data_string {
        u8 str[13];
 } __attribute__((packed));
 
+#define DRM_EDID_RANGE_OFFSET_MIN_VFREQ (1 << 0) /* 1.4 */
+#define DRM_EDID_RANGE_OFFSET_MAX_VFREQ (1 << 1) /* 1.4 */
+#define DRM_EDID_RANGE_OFFSET_MIN_HFREQ (1 << 2) /* 1.4 */
+#define DRM_EDID_RANGE_OFFSET_MAX_HFREQ (1 << 3) /* 1.4 */
+
 #define DRM_EDID_DEFAULT_GTF_SUPPORT_FLAG   0x00
 #define DRM_EDID_RANGE_LIMITS_ONLY_FLAG     0x01
 #define DRM_EDID_SECONDARY_GTF_SUPPORT_FLAG 0x02
index c958855..840a2c3 100644 (file)
@@ -826,7 +826,7 @@ do {                                                                               \
 
 #define KUNIT_EXPECT_LE_MSG(test, left, right, fmt, ...)                      \
        KUNIT_BINARY_INT_ASSERTION(test,                                       \
-                                  KUNIT_ASSERTION,                            \
+                                  KUNIT_EXPECTATION,                          \
                                   left, <=, right,                            \
                                   fmt,                                        \
                                    ##__VA_ARGS__)
@@ -1116,7 +1116,7 @@ do {                                                                             \
 
 #define KUNIT_ASSERT_LT_MSG(test, left, right, fmt, ...)                      \
        KUNIT_BINARY_INT_ASSERTION(test,                                       \
-                                  KUNIT_EXPECTATION,                          \
+                                  KUNIT_ASSERTION,                            \
                                   left, <, right,                             \
                                   fmt,                                        \
                                    ##__VA_ARGS__)
@@ -1157,7 +1157,7 @@ do {                                                                             \
 
 #define KUNIT_ASSERT_GT_MSG(test, left, right, fmt, ...)                      \
        KUNIT_BINARY_INT_ASSERTION(test,                                       \
-                                  KUNIT_EXPECTATION,                          \
+                                  KUNIT_ASSERTION,                            \
                                   left, >, right,                             \
                                   fmt,                                        \
                                    ##__VA_ARGS__)
index e94cdf2..5001e14 100644 (file)
@@ -67,6 +67,7 @@ struct amba_device {
        struct clk              *pclk;
        struct device_dma_parameters dma_parms;
        unsigned int            periphid;
+       struct mutex            periphid_lock;
        unsigned int            cid;
        struct amba_cs_uci_id   uci;
        unsigned int            irq[AMBA_NR_IRQS];
index cf9bf65..3b89c64 100644 (file)
@@ -59,6 +59,7 @@ extern unsigned long __sw_hweight64(__u64 w);
 #define __test_and_clear_bit(nr, addr) bitop(___test_and_clear_bit, nr, addr)
 #define __test_and_change_bit(nr, addr)        bitop(___test_and_change_bit, nr, addr)
 #define test_bit(nr, addr)             bitop(_test_bit, nr, addr)
+#define test_bit_acquire(nr, addr)     bitop(_test_bit_acquire, nr, addr)
 
 /*
  * Include this here because some architectures need generic_ffs/fls in
index effee1d..92294a5 100644 (file)
@@ -857,7 +857,6 @@ void blk_mq_kick_requeue_list(struct request_queue *q);
 void blk_mq_delay_kick_requeue_list(struct request_queue *q, unsigned long msecs);
 void blk_mq_complete_request(struct request *rq);
 bool blk_mq_complete_request_remote(struct request *rq);
-bool blk_mq_queue_stopped(struct request_queue *q);
 void blk_mq_stop_hw_queue(struct blk_mq_hw_ctx *hctx);
 void blk_mq_start_hw_queue(struct blk_mq_hw_ctx *hctx);
 void blk_mq_stop_hw_queues(struct request_queue *q);
index def8b8d..df518c4 100644 (file)
@@ -138,6 +138,17 @@ BUFFER_FNS(Defer_Completion, defer_completion)
 static __always_inline void set_buffer_uptodate(struct buffer_head *bh)
 {
        /*
+        * If somebody else already set this uptodate, they will
+        * have done the memory barrier, and a reader will thus
+        * see *some* valid buffer state.
+        *
+        * Any other serialization (with IO errors or whatever that
+        * might clear the bit) has to come from other state (eg BH_Lock).
+        */
+       if (test_bit(BH_Uptodate, &bh->b_state))
+               return;
+
+       /*
         * make it consistent with folio_mark_uptodate
         * pairs with smp_load_acquire in buffer_uptodate
         */
@@ -156,7 +167,7 @@ static __always_inline int buffer_uptodate(const struct buffer_head *bh)
         * make it consistent with folio_test_uptodate
         * pairs with smp_mb__before_atomic in set_buffer_uptodate
         */
-       return (smp_load_acquire(&bh->b_state) & (1UL << BH_Uptodate)) != 0;
+       return test_bit_acquire(BH_Uptodate, &bh->b_state);
 }
 
 #define bh_offset(bh)          ((unsigned long)(bh)->b_data & ~PAGE_MASK)
index ed53bfe..ac5d051 100644 (file)
@@ -734,11 +734,6 @@ static inline struct cgroup *cgroup_parent(struct cgroup *cgrp)
        return NULL;
 }
 
-static inline struct psi_group *cgroup_psi(struct cgroup *cgrp)
-{
-       return NULL;
-}
-
 static inline bool cgroup_psi_enabled(void)
 {
        return false;
index 01ce94b..7713d7b 100644 (file)
@@ -240,6 +240,12 @@ static inline void *offset_to_ptr(const int *off)
 #define __must_be_array(a)     BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0]))
 
 /*
+ * Whether 'type' is a signed type or an unsigned type. Supports scalar types,
+ * bool and also pointer types.
+ */
+#define is_signed_type(type) (((type)(-1)) < (__force type)1)
+
+/*
  * This is needed in functions which generate the stack canary, see
  * arch/x86/kernel/smpboot.c::start_secondary() for an example.
  */
index 0d435d0..bd04786 100644 (file)
@@ -202,12 +202,13 @@ static inline unsigned int cpumask_local_spread(unsigned int i, int node)
        return 0;
 }
 
-static inline int cpumask_any_and_distribute(const struct cpumask *src1p,
-                                            const struct cpumask *src2p) {
+static inline unsigned int cpumask_any_and_distribute(const struct cpumask *src1p,
+                                                     const struct cpumask *src2p)
+{
        return cpumask_first_and(src1p, src2p);
 }
 
-static inline int cpumask_any_distribute(const struct cpumask *srcp)
+static inline unsigned int cpumask_any_distribute(const struct cpumask *srcp)
 {
        return cpumask_first(srcp);
 }
@@ -261,7 +262,26 @@ unsigned int cpumask_next_and(int n, const struct cpumask *src1p,
                (cpu) = cpumask_next_zero((cpu), (mask)),       \
                (cpu) < nr_cpu_ids;)
 
+#if NR_CPUS == 1
+static inline
+unsigned int cpumask_next_wrap(int n, const struct cpumask *mask, int start, bool wrap)
+{
+       cpumask_check(start);
+       if (n != -1)
+               cpumask_check(n);
+
+       /*
+        * Return the first available CPU when wrapping, or when starting before cpu0,
+        * since there is only one valid option.
+        */
+       if (wrap && n >= 0)
+               return nr_cpumask_bits;
+
+       return cpumask_first(mask);
+}
+#else
 unsigned int __pure cpumask_next_wrap(int n, const struct cpumask *mask, int start, bool wrap);
+#endif
 
 /**
  * for_each_cpu_wrap - iterate over every cpu in a mask, starting at a specified location
index c869f1e..f606746 100644 (file)
@@ -91,6 +91,8 @@ struct dentry *debugfs_create_automount(const char *name,
 void debugfs_remove(struct dentry *dentry);
 #define debugfs_remove_recursive debugfs_remove
 
+void debugfs_lookup_and_remove(const char *name, struct dentry *parent);
+
 const struct file_operations *debugfs_real_fops(const struct file *filp);
 
 int debugfs_file_get(struct dentry *dentry);
@@ -225,6 +227,10 @@ static inline void debugfs_remove(struct dentry *dentry)
 static inline void debugfs_remove_recursive(struct dentry *dentry)
 { }
 
+static inline void debugfs_lookup_and_remove(const char *name,
+                                            struct dentry *parent)
+{ }
+
 const struct file_operations *debugfs_real_fops(const struct file *filp);
 
 static inline int debugfs_file_get(struct dentry *dentry)
index 7acaabd..2114d65 100644 (file)
@@ -242,6 +242,7 @@ driver_find_device_by_acpi_dev(struct device_driver *drv, const void *adev)
 
 extern int driver_deferred_probe_timeout;
 void driver_deferred_probe_add(struct device *dev);
+int driver_deferred_probe_check_state(struct device *dev);
 void driver_init(void);
 
 /**
index 25a3090..0ee20b7 100644 (file)
@@ -139,7 +139,6 @@ int dma_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
                void *cpu_addr, dma_addr_t dma_addr, size_t size,
                unsigned long attrs);
 bool dma_can_mmap(struct device *dev);
-int dma_supported(struct device *dev, u64 mask);
 bool dma_pci_p2pdma_supported(struct device *dev);
 int dma_set_mask(struct device *dev, u64 mask);
 int dma_set_coherent_mask(struct device *dev, u64 mask);
@@ -248,10 +247,6 @@ static inline bool dma_can_mmap(struct device *dev)
 {
        return false;
 }
-static inline int dma_supported(struct device *dev, u64 mask)
-{
-       return 0;
-}
 static inline bool dma_pci_p2pdma_supported(struct device *dev)
 {
        return false;
index 720874e..36e5dd8 100644 (file)
@@ -258,7 +258,7 @@ struct fscache_cookie *fscache_acquire_cookie(struct fscache_volume *volume,
 
 /**
  * fscache_use_cookie - Request usage of cookie attached to an object
- * @object: Object description
+ * @cookie: The cookie representing the cache object
  * @will_modify: If cache is expected to be modified locally
  *
  * Request usage of the cookie attached to an object.  The caller should tell
@@ -274,7 +274,7 @@ static inline void fscache_use_cookie(struct fscache_cookie *cookie,
 
 /**
  * fscache_unuse_cookie - Cease usage of cookie attached to an object
- * @object: Object description
+ * @cookie: The cookie representing the cache object
  * @aux_data: Updated auxiliary data (or NULL)
  * @object_size: Revised size of the object (or NULL)
  *
index 6f1dee7..9be8704 100644 (file)
@@ -180,7 +180,7 @@ switch (val) {                                              \
 
 #define HP_SDC_CMD_SET_IM      0x40    /* 010xxxxx == set irq mask */
 
-/* The documents provided do not explicitly state that all registers betwee
+/* The documents provided do not explicitly state that all registers between
  * 0x01 and 0x1f inclusive can be read by sending their register index as a 
  * command, but this is implied and appears to be the case.
  */
index 55e6f4a..b6e6d5b 100644 (file)
@@ -310,9 +310,11 @@ static inline u16 ieee80211_sn_sub(u16 sn1, u16 sn2)
 struct ieee80211_hdr {
        __le16 frame_control;
        __le16 duration_id;
-       u8 addr1[ETH_ALEN];
-       u8 addr2[ETH_ALEN];
-       u8 addr3[ETH_ALEN];
+       struct_group(addrs,
+               u8 addr1[ETH_ALEN];
+               u8 addr2[ETH_ALEN];
+               u8 addr3[ETH_ALEN];
+       );
        __le16 seq_ctrl;
        u8 addr4[ETH_ALEN];
 } __packed __aligned(2);
index 1c480b1..f4519d3 100644 (file)
@@ -656,12 +656,12 @@ struct kvm_irq_routing_table {
 };
 #endif
 
-#ifndef KVM_PRIVATE_MEM_SLOTS
-#define KVM_PRIVATE_MEM_SLOTS 0
+#ifndef KVM_INTERNAL_MEM_SLOTS
+#define KVM_INTERNAL_MEM_SLOTS 0
 #endif
 
 #define KVM_MEM_SLOTS_NUM SHRT_MAX
-#define KVM_USER_MEM_SLOTS (KVM_MEM_SLOTS_NUM - KVM_PRIVATE_MEM_SLOTS)
+#define KVM_USER_MEM_SLOTS (KVM_MEM_SLOTS_NUM - KVM_INTERNAL_MEM_SLOTS)
 
 #ifndef __KVM_VCPU_MULTIPLE_ADDRESS_SPACE
 static inline int kvm_arch_vcpu_memslots_id(struct kvm_vcpu *vcpu)
@@ -765,10 +765,10 @@ struct kvm {
 
 #if defined(CONFIG_MMU_NOTIFIER) && defined(KVM_ARCH_WANT_MMU_NOTIFIER)
        struct mmu_notifier mmu_notifier;
-       unsigned long mmu_notifier_seq;
-       long mmu_notifier_count;
-       unsigned long mmu_notifier_range_start;
-       unsigned long mmu_notifier_range_end;
+       unsigned long mmu_invalidate_seq;
+       long mmu_invalidate_in_progress;
+       unsigned long mmu_invalidate_range_start;
+       unsigned long mmu_invalidate_range_end;
 #endif
        struct list_head devices;
        u64 manual_dirty_log_protect;
@@ -1357,10 +1357,10 @@ void kvm_mmu_free_memory_cache(struct kvm_mmu_memory_cache *mc);
 void *kvm_mmu_memory_cache_alloc(struct kvm_mmu_memory_cache *mc);
 #endif
 
-void kvm_inc_notifier_count(struct kvm *kvm, unsigned long start,
-                                  unsigned long end);
-void kvm_dec_notifier_count(struct kvm *kvm, unsigned long start,
-                                  unsigned long end);
+void kvm_mmu_invalidate_begin(struct kvm *kvm, unsigned long start,
+                             unsigned long end);
+void kvm_mmu_invalidate_end(struct kvm *kvm, unsigned long start,
+                           unsigned long end);
 
 long kvm_arch_dev_ioctl(struct file *filp,
                        unsigned int ioctl, unsigned long arg);
@@ -1907,42 +1907,44 @@ extern const struct kvm_stats_header kvm_vcpu_stats_header;
 extern const struct _kvm_stats_desc kvm_vcpu_stats_desc[];
 
 #if defined(CONFIG_MMU_NOTIFIER) && defined(KVM_ARCH_WANT_MMU_NOTIFIER)
-static inline int mmu_notifier_retry(struct kvm *kvm, unsigned long mmu_seq)
+static inline int mmu_invalidate_retry(struct kvm *kvm, unsigned long mmu_seq)
 {
-       if (unlikely(kvm->mmu_notifier_count))
+       if (unlikely(kvm->mmu_invalidate_in_progress))
                return 1;
        /*
-        * Ensure the read of mmu_notifier_count happens before the read
-        * of mmu_notifier_seq.  This interacts with the smp_wmb() in
-        * mmu_notifier_invalidate_range_end to make sure that the caller
-        * either sees the old (non-zero) value of mmu_notifier_count or
-        * the new (incremented) value of mmu_notifier_seq.
-        * PowerPC Book3s HV KVM calls this under a per-page lock
-        * rather than under kvm->mmu_lock, for scalability, so
-        * can't rely on kvm->mmu_lock to keep things ordered.
+        * Ensure the read of mmu_invalidate_in_progress happens before
+        * the read of mmu_invalidate_seq.  This interacts with the
+        * smp_wmb() in mmu_notifier_invalidate_range_end to make sure
+        * that the caller either sees the old (non-zero) value of
+        * mmu_invalidate_in_progress or the new (incremented) value of
+        * mmu_invalidate_seq.
+        *
+        * PowerPC Book3s HV KVM calls this under a per-page lock rather
+        * than under kvm->mmu_lock, for scalability, so can't rely on
+        * kvm->mmu_lock to keep things ordered.
         */
        smp_rmb();
-       if (kvm->mmu_notifier_seq != mmu_seq)
+       if (kvm->mmu_invalidate_seq != mmu_seq)
                return 1;
        return 0;
 }
 
-static inline int mmu_notifier_retry_hva(struct kvm *kvm,
-                                        unsigned long mmu_seq,
-                                        unsigned long hva)
+static inline int mmu_invalidate_retry_hva(struct kvm *kvm,
+                                          unsigned long mmu_seq,
+                                          unsigned long hva)
 {
        lockdep_assert_held(&kvm->mmu_lock);
        /*
-        * If mmu_notifier_count is non-zero, then the range maintained by
-        * kvm_mmu_notifier_invalidate_range_start contains all addresses that
-        * might be being invalidated. Note that it may include some false
+        * If mmu_invalidate_in_progress is non-zero, then the range maintained
+        * by kvm_mmu_notifier_invalidate_range_start contains all addresses
+        * that might be being invalidated. Note that it may include some false
         * positives, due to shortcuts when handing concurrent invalidations.
         */
-       if (unlikely(kvm->mmu_notifier_count) &&
-           hva >= kvm->mmu_notifier_range_start &&
-           hva < kvm->mmu_notifier_range_end)
+       if (unlikely(kvm->mmu_invalidate_in_progress) &&
+           hva >= kvm->mmu_invalidate_range_start &&
+           hva < kvm->mmu_invalidate_range_end)
                return 1;
-       if (kvm->mmu_notifier_seq != mmu_seq)
+       if (kvm->mmu_invalidate_seq != mmu_seq)
                return 1;
        return 0;
 }
index 0269ff1..698032e 100644 (file)
@@ -1382,7 +1382,8 @@ extern const struct attribute_group *ata_common_sdev_groups[];
        .proc_name              = drv_name,                     \
        .slave_destroy          = ata_scsi_slave_destroy,       \
        .bios_param             = ata_std_bios_param,           \
-       .unlock_native_capacity = ata_scsi_unlock_native_capacity
+       .unlock_native_capacity = ata_scsi_unlock_native_capacity,\
+       .max_sectors            = ATA_MAX_SECTORS_LBA48
 
 #define ATA_SUBBASE_SHT(drv_name)                              \
        __ATA_BASE_SHT(drv_name),                               \
index 8064481..60fff13 100644 (file)
@@ -407,4 +407,5 @@ LSM_HOOK(int, 0, perf_event_write, struct perf_event *event)
 #ifdef CONFIG_IO_URING
 LSM_HOOK(int, 0, uring_override_creds, const struct cred *new)
 LSM_HOOK(int, 0, uring_sqpoll, void)
+LSM_HOOK(int, 0, uring_cmd, struct io_uring_cmd *ioucmd)
 #endif /* CONFIG_IO_URING */
index 84a0d7e..3aa6030 100644 (file)
  *      Check whether the current task is allowed to spawn a io_uring polling
  *      thread (IORING_SETUP_SQPOLL).
  *
+ * @uring_cmd:
+ *      Check whether the file_operations uring_cmd is allowed to run.
+ *
  */
 union security_list_options {
        #define LSM_HOOK(RET, DEFAULT, NAME, ...) RET (*NAME)(__VA_ARGS__);
index 4d31ce5..6257867 100644 (file)
@@ -987,19 +987,30 @@ static inline void mod_memcg_page_state(struct page *page,
 
 static inline unsigned long memcg_page_state(struct mem_cgroup *memcg, int idx)
 {
-       return READ_ONCE(memcg->vmstats.state[idx]);
+       long x = READ_ONCE(memcg->vmstats.state[idx]);
+#ifdef CONFIG_SMP
+       if (x < 0)
+               x = 0;
+#endif
+       return x;
 }
 
 static inline unsigned long lruvec_page_state(struct lruvec *lruvec,
                                              enum node_stat_item idx)
 {
        struct mem_cgroup_per_node *pn;
+       long x;
 
        if (mem_cgroup_disabled())
                return node_page_state(lruvec_pgdat(lruvec), idx);
 
        pn = container_of(lruvec, struct mem_cgroup_per_node, lruvec);
-       return READ_ONCE(pn->lruvec_stats.state[idx]);
+       x = READ_ONCE(pn->lruvec_stats.state[idx]);
+#ifdef CONFIG_SMP
+       if (x < 0)
+               x = 0;
+#endif
+       return x;
 }
 
 static inline unsigned long lruvec_page_state_local(struct lruvec *lruvec,
index 96b16fb..c32de98 100644 (file)
@@ -779,6 +779,7 @@ struct mlx5_core_dev {
        enum mlx5_device_state  state;
        /* sync interface state */
        struct mutex            intf_state_mutex;
+       struct lock_class_key   lock_key;
        unsigned long           intf_state;
        struct mlx5_priv        priv;
        struct mlx5_profile     profile;
@@ -1279,16 +1280,17 @@ enum {
        MLX5_TRIGGERED_CMD_COMP = (u64)1 << 32,
 };
 
-static inline bool mlx5_is_roce_init_enabled(struct mlx5_core_dev *dev)
+bool mlx5_is_roce_on(struct mlx5_core_dev *dev);
+
+static inline bool mlx5_get_roce_state(struct mlx5_core_dev *dev)
 {
-       struct devlink *devlink = priv_to_devlink(dev);
-       union devlink_param_value val;
-       int err;
-
-       err = devlink_param_driverinit_value_get(devlink,
-                                                DEVLINK_PARAM_GENERIC_ID_ENABLE_ROCE,
-                                                &val);
-       return err ? MLX5_CAP_GEN(dev, roce) : val.vbool;
+       if (MLX5_CAP_GEN(dev, roce_rw_supported))
+               return MLX5_CAP_GEN(dev, roce);
+
+       /* If RoCE cap is read-only in FW, get RoCE state from devlink
+        * in order to support RoCE enable/disable feature
+        */
+       return mlx5_is_roce_on(dev);
 }
 
 #endif /* MLX5_DRIVER_H */
index 3bedc44..21f8b27 100644 (file)
@@ -1544,9 +1544,16 @@ static inline bool is_longterm_pinnable_page(struct page *page)
        if (mt == MIGRATE_CMA || mt == MIGRATE_ISOLATE)
                return false;
 #endif
-       return !(is_device_coherent_page(page) ||
-                is_zone_movable_page(page) ||
-                is_zero_pfn(page_to_pfn(page)));
+       /* The zero page may always be pinned */
+       if (is_zero_pfn(page_to_pfn(page)))
+               return true;
+
+       /* Coherent device memory must always allow eviction. */
+       if (is_device_coherent_page(page))
+               return false;
+
+       /* Otherwise, non-movable zone pages can be pinned. */
+       return !is_zone_movable_page(page);
 }
 #else
 static inline bool is_longterm_pinnable_page(struct page *page)
@@ -2885,7 +2892,6 @@ struct page *follow_page(struct vm_area_struct *vma, unsigned long address,
 #define FOLL_MIGRATION 0x400   /* wait for page to replace migration entry */
 #define FOLL_TRIED     0x800   /* a retry, previous pass started an IO */
 #define FOLL_REMOTE    0x2000  /* we are working on non-current tsk/mm */
-#define FOLL_COW       0x4000  /* internal GUP flag */
 #define FOLL_ANON      0x8000  /* don't do file mappings */
 #define FOLL_LONGTERM  0x10000 /* mapping lifetime is indefinite: see below */
 #define FOLL_SPLIT_PMD 0x20000 /* split huge pmd before returning */
index 1a3cb93..05d6f3f 100644 (file)
@@ -640,9 +640,23 @@ extern int sysctl_devconf_inherit_init_net;
  */
 static inline bool net_has_fallback_tunnels(const struct net *net)
 {
-       return !IS_ENABLED(CONFIG_SYSCTL) ||
-              !sysctl_fb_tunnels_only_for_init_net ||
-              (net == &init_net && sysctl_fb_tunnels_only_for_init_net == 1);
+#if IS_ENABLED(CONFIG_SYSCTL)
+       int fb_tunnels_only_for_init_net = READ_ONCE(sysctl_fb_tunnels_only_for_init_net);
+
+       return !fb_tunnels_only_for_init_net ||
+               (net_eq(net, &init_net) && fb_tunnels_only_for_init_net == 1);
+#else
+       return true;
+#endif
+}
+
+static inline int net_inherit_devconf(void)
+{
+#if IS_ENABLED(CONFIG_SYSCTL)
+       return READ_ONCE(sysctl_devconf_inherit_init_net);
+#else
+       return 0;
+#endif
 }
 
 static inline int netdev_queue_numa_node_read(const struct netdev_queue *q)
index a13296d..fd53355 100644 (file)
@@ -94,10 +94,6 @@ struct ebt_table {
        struct ebt_replace_kernel *table;
        unsigned int valid_hooks;
        rwlock_t lock;
-       /* e.g. could be the table explicitly only allows certain
-        * matches, targets, ... 0 == let it in */
-       int (*check)(const struct ebt_table_info *info,
-          unsigned int valid_hooks);
        /* the data used by the kernel */
        struct ebt_table_info *private;
        struct nf_hook_ops *ops;
index b32ed68..7931fa4 100644 (file)
@@ -83,7 +83,6 @@ struct nfs_open_context {
        fmode_t mode;
 
        unsigned long flags;
-#define NFS_CONTEXT_RESEND_WRITES      (1)
 #define NFS_CONTEXT_BAD                        (2)
 #define NFS_CONTEXT_UNLOCK     (3)
 #define NFS_CONTEXT_FILE_OPEN          (4)
@@ -182,6 +181,7 @@ struct nfs_inode {
                /* Regular file */
                struct {
                        atomic_long_t   nrequests;
+                       atomic_long_t   redirtied_pages;
                        struct nfs_mds_commit_info commit_info;
                        struct mutex    commit_mutex;
                };
index 1d7992a..1a803e4 100644 (file)
@@ -101,8 +101,9 @@ static inline struct device_node *of_cpu_device_node_get(int cpu)
 }
 
 static inline int of_dma_configure_id(struct device *dev,
-                                  struct device_node *np,
-                                  bool force_dma)
+                                     struct device_node *np,
+                                     bool force_dma,
+                                     const u32 *id)
 {
        return 0;
 }
index f1221d1..0eb3b19 100644 (file)
@@ -30,7 +30,6 @@
  * https://mail-index.netbsd.org/tech-misc/2007/02/05/0000.html -
  * credit to Christian Biere.
  */
-#define is_signed_type(type)       (((type)(-1)) < (type)1)
 #define __type_half_max(type) ((type)1 << (8*sizeof(type) - 1 - is_signed_type(type)))
 #define type_max(T) ((T)((__type_half_max(T) - 1) + __type_half_max(T)))
 #define type_min(T) ((T)((T)-type_max(T)-(T)1))
index 6feade6..15b49e6 100644 (file)
 #define PCI_DEVICE_ID_ICE_1712         0x1712
 #define PCI_DEVICE_ID_VT1724           0x1724
 
+#define PCI_VENDOR_ID_MICROSOFT                0x1414
+#define PCI_DEVICE_ID_HYPERV_VIDEO     0x5353
+
 #define PCI_VENDOR_ID_OXSEMI           0x1415
 #define PCI_DEVICE_ID_OXSEMI_12PCI840  0x8403
 #define PCI_DEVICE_ID_OXSEMI_PCIe840           0xC000
index 3edfb6d..dd81f51 100644 (file)
@@ -7,6 +7,8 @@
 #ifndef PMC_ATOM_H
 #define PMC_ATOM_H
 
+#include <linux/bits.h>
+
 /* ValleyView Power Control Unit PCI Device ID */
 #define        PCI_DEVICE_ID_VLV_PMC   0x0F1C
 /* CherryTrail Power Control Unit PCI Device ID */
 #define        ACPI_MMIO_REG_LEN       0x100
 
 #define        PM1_CNT                 0x4
-#define        SLEEP_TYPE_MASK         0xFFFFECFF
+#define        SLEEP_TYPE_MASK         GENMASK(12, 10)
 #define        SLEEP_TYPE_S5           0x1C00
-#define        SLEEP_ENABLE            0x2000
+#define        SLEEP_ENABLE            BIT(13)
 
 extern int pmc_atom_read(int offset, u32 *value);
 
index 8978476..dd74411 100644 (file)
@@ -27,7 +27,7 @@ void psi_memstall_leave(unsigned long *flags);
 
 int psi_show(struct seq_file *s, struct psi_group *group, enum psi_res res);
 struct psi_trigger *psi_trigger_create(struct psi_group *group,
-                       char *buf, size_t nbytes, enum psi_res res);
+                       char *buf, enum psi_res res);
 void psi_trigger_destroy(struct psi_trigger *t);
 
 __poll_t psi_trigger_poll(void **trigger_ptr, struct file *file,
index bf80adc..b89b4b8 100644 (file)
@@ -41,12 +41,15 @@ struct anon_vma {
        atomic_t refcount;
 
        /*
-        * Count of child anon_vmas and VMAs which points to this anon_vma.
+        * Count of child anon_vmas. Equals to the count of all anon_vmas that
+        * have ->parent pointing to this one, including itself.
         *
         * This counter is used for making decision about reusing anon_vma
         * instead of forking new one. See comments in function anon_vma_clone.
         */
-       unsigned degree;
+       unsigned long num_children;
+       /* Count of VMAs whose ->anon_vma pointer points to this object. */
+       unsigned long num_active_vmas;
 
        struct anon_vma *parent;        /* Parent of this anon_vma */
 
index 1bc362c..7bd0c49 100644 (file)
@@ -2060,6 +2060,7 @@ static inline int security_perf_event_write(struct perf_event *event)
 #ifdef CONFIG_SECURITY
 extern int security_uring_override_creds(const struct cred *new);
 extern int security_uring_sqpoll(void);
+extern int security_uring_cmd(struct io_uring_cmd *ioucmd);
 #else
 static inline int security_uring_override_creds(const struct cred *new)
 {
@@ -2069,6 +2070,10 @@ static inline int security_uring_sqpoll(void)
 {
        return 0;
 }
+static inline int security_uring_cmd(struct io_uring_cmd *ioucmd)
+{
+       return 0;
+}
 #endif /* CONFIG_SECURITY */
 #endif /* CONFIG_IO_URING */
 
index aef3145..6e4f476 100644 (file)
@@ -141,6 +141,14 @@ struct gpio_desc;
  *     Locking: none.
  *     Interrupts: caller dependent.
  *
+ * @start_rx: ``void ()(struct uart_port *port)``
+ *
+ *     Start receiving characters.
+ *
+ *     Locking: @port->lock taken.
+ *     Interrupts: locally disabled.
+ *     This call must not sleep
+ *
  * @stop_rx: ``void ()(struct uart_port *port)``
  *
  *     Stop receiving characters; the @port is in the process of being closed.
index 1b6c401..ff0b990 100644 (file)
@@ -29,15 +29,10 @@ struct shmem_inode_info {
        struct inode            vfs_inode;
 };
 
-#define SHMEM_FL_USER_VISIBLE FS_FL_USER_VISIBLE
-#define SHMEM_FL_USER_MODIFIABLE FS_FL_USER_MODIFIABLE
-#define SHMEM_FL_INHERITED FS_FL_USER_MODIFIABLE
-
-/* Flags that are appropriate for regular files (all but dir-specific ones). */
-#define SHMEM_REG_FLMASK (~(FS_DIRSYNC_FL | FS_TOPDIR_FL))
-
-/* Flags that are appropriate for non-directories/regular files. */
-#define SHMEM_OTHER_FLMASK (FS_NODUMP_FL | FS_NOATIME_FL)
+#define SHMEM_FL_USER_VISIBLE          FS_FL_USER_VISIBLE
+#define SHMEM_FL_USER_MODIFIABLE \
+       (FS_IMMUTABLE_FL | FS_APPEND_FL | FS_NODUMP_FL | FS_NOATIME_FL)
+#define SHMEM_FL_INHERITED             (FS_NODUMP_FL | FS_NOATIME_FL)
 
 struct shmem_sb_info {
        unsigned long max_blocks;   /* How many blocks are allowed */
index ca8afa3..18e163a 100644 (file)
@@ -2444,6 +2444,27 @@ static inline void skb_fill_page_desc(struct sk_buff *skb, int i,
        skb_shinfo(skb)->nr_frags = i + 1;
 }
 
+/**
+ * skb_fill_page_desc_noacc - initialise a paged fragment in an skb
+ * @skb: buffer containing fragment to be initialised
+ * @i: paged fragment index to initialise
+ * @page: the page to use for this fragment
+ * @off: the offset to the data with @page
+ * @size: the length of the data
+ *
+ * Variant of skb_fill_page_desc() which does not deal with
+ * pfmemalloc, if page is not owned by us.
+ */
+static inline void skb_fill_page_desc_noacc(struct sk_buff *skb, int i,
+                                           struct page *page, int off,
+                                           int size)
+{
+       struct skb_shared_info *shinfo = skb_shinfo(skb);
+
+       __skb_fill_page_desc_noacc(shinfo, i, page, off, size);
+       shinfo->nr_frags = i + 1;
+}
+
 void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, int off,
                     int size, unsigned int truesize);
 
index e6c73d5..f089ee1 100644 (file)
@@ -469,6 +469,7 @@ extern struct spi_device *spi_new_ancillary_device(struct spi_device *spi, u8 ch
  *     SPI_TRANS_FAIL_NO_START.
  * @queue_empty: signal green light for opportunistically skipping the queue
  *     for spi_sync transfers.
+ * @must_async: disable all fast paths in the core
  *
  * Each SPI controller can communicate with one or more @spi_device
  * children.  These make a small bus, sharing MOSI, MISO and SCK signals
@@ -690,6 +691,7 @@ struct spi_controller {
 
        /* Flag for enabling opportunistic skipping of the queue in spi_sync */
        bool                    queue_empty;
+       bool                    must_async;
 };
 
 static inline void *spi_controller_get_devdata(struct spi_controller *ctlr)
index b18759a..8401dec 100644 (file)
@@ -814,8 +814,6 @@ extern int trace_add_event_call(struct trace_event_call *call);
 extern int trace_remove_event_call(struct trace_event_call *call);
 extern int trace_event_get_offsets(struct trace_event_call *call);
 
-#define is_signed_type(type)   (((type)(-1)) < (type)1)
-
 int ftrace_set_clr_event(struct trace_array *tr, char *buf, int set);
 int trace_set_clr_event(const char *system, const char *event, int set);
 int trace_array_set_clr_event(struct trace_array *tr, const char *system,
index 254a265..e96da41 100644 (file)
@@ -70,6 +70,7 @@ struct udp_sock {
         * For encapsulation sockets.
         */
        int (*encap_rcv)(struct sock *sk, struct sk_buff *skb);
+       void (*encap_err_rcv)(struct sock *sk, struct sk_buff *skb, unsigned int udp_offset);
        int (*encap_err_lookup)(struct sock *sk, struct sk_buff *skb);
        void (*encap_destroy)(struct sock *sk);
 
index f7a9914..9ff1ad4 100644 (file)
@@ -575,6 +575,7 @@ struct usb3_lpm_parameters {
  * @devaddr: device address, XHCI: assigned by HW, others: same as devnum
  * @can_submit: URBs may be submitted
  * @persist_enabled:  USB_PERSIST enabled for this device
+ * @reset_in_progress: the device is being reset
  * @have_langid: whether string_langid is valid
  * @authorized: policy has said we can use it;
  *     (user space) policy determines if we authorize this device to be
@@ -662,6 +663,7 @@ struct usb_device {
 
        unsigned can_submit:1;
        unsigned persist_enabled:1;
+       unsigned reset_in_progress:1;
        unsigned have_langid:1;
        unsigned authorized:1;
        unsigned authenticated:1;
index cfb916c..8d09c2f 100644 (file)
@@ -73,6 +73,11 @@ enum {
 #define DP_CAP_USB                     BIT(7)
 #define DP_CAP_DFP_D_PIN_ASSIGN(_cap_) (((_cap_) & GENMASK(15, 8)) >> 8)
 #define DP_CAP_UFP_D_PIN_ASSIGN(_cap_) (((_cap_) & GENMASK(23, 16)) >> 16)
+/* Get pin assignment taking plug & receptacle into consideration */
+#define DP_CAP_PIN_ASSIGN_UFP_D(_cap_) ((_cap_ & DP_CAP_RECEPTACLE) ? \
+                       DP_CAP_UFP_D_PIN_ASSIGN(_cap_) : DP_CAP_DFP_D_PIN_ASSIGN(_cap_))
+#define DP_CAP_PIN_ASSIGN_DFP_D(_cap_) ((_cap_ & DP_CAP_RECEPTACLE) ? \
+                       DP_CAP_DFP_D_PIN_ASSIGN(_cap_) : DP_CAP_UFP_D_PIN_ASSIGN(_cap_))
 
 /* DisplayPort Status Update VDO bits */
 #define DP_STATUS_CONNECTION(_status_) ((_status_) & 3)
index 732b522..e1b8a91 100644 (file)
@@ -73,6 +73,8 @@ extern ssize_t mcopy_continue(struct mm_struct *dst_mm, unsigned long dst_start,
 extern int mwriteprotect_range(struct mm_struct *dst_mm,
                               unsigned long start, unsigned long len,
                               bool enable_wp, atomic_t *mmap_changing);
+extern void uffd_wp_range(struct mm_struct *dst_mm, struct vm_area_struct *vma,
+                         unsigned long start, unsigned long len, bool enable_wp);
 
 /* mm helpers */
 static inline bool is_mergeable_vm_userfaultfd_ctx(struct vm_area_struct *vma,
index a3f73bb..dcab9c7 100644 (file)
@@ -11,7 +11,7 @@
 #include <linux/gfp.h>
 
 /**
- * virtqueue - a queue to register buffers for sending or receiving.
+ * struct virtqueue - a queue to register buffers for sending or receiving.
  * @list: the chain of virtqueues for this device
  * @callback: the function to call when buffers are consumed (can be NULL).
  * @name: the name of this virtqueue (mainly for debugging)
@@ -97,7 +97,7 @@ int virtqueue_resize(struct virtqueue *vq, u32 num,
                     void (*recycle)(struct virtqueue *vq, void *buf));
 
 /**
- * virtio_device - representation of a device using virtio
+ * struct virtio_device - representation of a device using virtio
  * @index: unique position on the virtio bus
  * @failed: saved value for VIRTIO_CONFIG_S_FAILED bit (for restore)
  * @config_enabled: configuration change reporting enabled
@@ -156,7 +156,7 @@ size_t virtio_max_dma_size(struct virtio_device *vdev);
        list_for_each_entry(vq, &vdev->vqs, list)
 
 /**
- * virtio_driver - operations for a virtio I/O driver
+ * struct virtio_driver - operations for a virtio I/O driver
  * @driver: underlying device driver (populate name and owner).
  * @id_table: the ids serviced by this driver.
  * @feature_table: an array of feature numbers supported by this driver.
index 6adff09..4b51764 100644 (file)
@@ -55,7 +55,6 @@ struct virtio_shm_region {
  *             include a NULL entry for vqs that do not need a callback
  *     names: array of virtqueue names (mainly for debugging)
  *             include a NULL entry for vqs unused by driver
- *     sizes: array of virtqueue sizes
  *     Returns 0 on success or error status
  * @del_vqs: free virtqueues found by find_vqs().
  * @synchronize_cbs: synchronize with the virtqueue callbacks (optional)
@@ -104,9 +103,7 @@ struct virtio_config_ops {
        void (*reset)(struct virtio_device *vdev);
        int (*find_vqs)(struct virtio_device *, unsigned nvqs,
                        struct virtqueue *vqs[], vq_callback_t *callbacks[],
-                       const char * const names[],
-                       u32 sizes[],
-                       const bool *ctx,
+                       const char * const names[], const bool *ctx,
                        struct irq_affinity *desc);
        void (*del_vqs)(struct virtio_device *);
        void (*synchronize_cbs)(struct virtio_device *);
@@ -215,7 +212,7 @@ struct virtqueue *virtio_find_single_vq(struct virtio_device *vdev,
        const char *names[] = { n };
        struct virtqueue *vq;
        int err = vdev->config->find_vqs(vdev, 1, &vq, callbacks, names, NULL,
-                                        NULL, NULL);
+                                        NULL);
        if (err < 0)
                return ERR_PTR(err);
        return vq;
@@ -227,8 +224,7 @@ int virtio_find_vqs(struct virtio_device *vdev, unsigned nvqs,
                        const char * const names[],
                        struct irq_affinity *desc)
 {
-       return vdev->config->find_vqs(vdev, nvqs, vqs, callbacks, names, NULL,
-                                     NULL, desc);
+       return vdev->config->find_vqs(vdev, nvqs, vqs, callbacks, names, NULL, desc);
 }
 
 static inline
@@ -237,25 +233,13 @@ int virtio_find_vqs_ctx(struct virtio_device *vdev, unsigned nvqs,
                        const char * const names[], const bool *ctx,
                        struct irq_affinity *desc)
 {
-       return vdev->config->find_vqs(vdev, nvqs, vqs, callbacks, names, NULL,
-                                     ctx, desc);
-}
-
-static inline
-int virtio_find_vqs_ctx_size(struct virtio_device *vdev, u32 nvqs,
-                            struct virtqueue *vqs[],
-                            vq_callback_t *callbacks[],
-                            const char * const names[],
-                            u32 sizes[],
-                            const bool *ctx, struct irq_affinity *desc)
-{
-       return vdev->config->find_vqs(vdev, nvqs, vqs, callbacks, names, sizes,
-                                     ctx, desc);
+       return vdev->config->find_vqs(vdev, nvqs, vqs, callbacks, names, ctx,
+                                     desc);
 }
 
 /**
  * virtio_synchronize_cbs - synchronize with virtqueue callbacks
- * @vdev: the device
+ * @dev: the virtio device
  */
 static inline
 void virtio_synchronize_cbs(struct virtio_device *dev)
@@ -274,7 +258,7 @@ void virtio_synchronize_cbs(struct virtio_device *dev)
 
 /**
  * virtio_device_ready - enable vq use in probe function
- * @vdev: the device
+ * @dev: the virtio device
  *
  * Driver must call this to use vqs in the probe function.
  *
@@ -322,7 +306,7 @@ const char *virtio_bus_name(struct virtio_device *vdev)
 /**
  * virtqueue_set_affinity - setting affinity for a virtqueue
  * @vq: the virtqueue
- * @cpu: the cpu no.
+ * @cpu_mask: the cpu mask
  *
  * Pay attention the function are best-effort: the affinity hint may not be set
  * due to config support, irq type and sharing.
index 4040244..f3fc36c 100644 (file)
 #define HIGHMEM_ZONE(xx)
 #endif
 
-#define FOR_ALL_ZONES(xx) DMA_ZONE(xx) DMA32_ZONE(xx) xx##_NORMAL, HIGHMEM_ZONE(xx) xx##_MOVABLE
+#ifdef CONFIG_ZONE_DEVICE
+#define DEVICE_ZONE(xx) xx##_DEVICE,
+#else
+#define DEVICE_ZONE(xx)
+#endif
+
+#define FOR_ALL_ZONES(xx) DMA_ZONE(xx) DMA32_ZONE(xx) xx##_NORMAL, \
+       HIGHMEM_ZONE(xx) xx##_MOVABLE, DEVICE_ZONE(xx)
 
 enum vm_event_item { PGPGIN, PGPGOUT, PSWPIN, PSWPOUT,
-               FOR_ALL_ZONES(PGALLOC),
-               FOR_ALL_ZONES(ALLOCSTALL),
-               FOR_ALL_ZONES(PGSCAN_SKIP),
+               FOR_ALL_ZONES(PGALLOC)
+               FOR_ALL_ZONES(ALLOCSTALL)
+               FOR_ALL_ZONES(PGSCAN_SKIP)
                PGFREE, PGACTIVATE, PGDEACTIVATE, PGLAZYFREE,
                PGFAULT, PGMAJFAULT,
                PGLAZYFREED,
index 7dec36a..7725b75 100644 (file)
@@ -71,7 +71,7 @@ static inline int
 wait_on_bit(unsigned long *word, int bit, unsigned mode)
 {
        might_sleep();
-       if (!test_bit(bit, word))
+       if (!test_bit_acquire(bit, word))
                return 0;
        return out_of_line_wait_on_bit(word, bit,
                                       bit_wait,
@@ -96,7 +96,7 @@ static inline int
 wait_on_bit_io(unsigned long *word, int bit, unsigned mode)
 {
        might_sleep();
-       if (!test_bit(bit, word))
+       if (!test_bit_acquire(bit, word))
                return 0;
        return out_of_line_wait_on_bit(word, bit,
                                       bit_wait_io,
@@ -123,7 +123,7 @@ wait_on_bit_timeout(unsigned long *word, int bit, unsigned mode,
                    unsigned long timeout)
 {
        might_sleep();
-       if (!test_bit(bit, word))
+       if (!test_bit_acquire(bit, word))
                return 0;
        return out_of_line_wait_on_bit_timeout(word, bit,
                                               bit_wait_timeout,
@@ -151,7 +151,7 @@ wait_on_bit_action(unsigned long *word, int bit, wait_bit_action_f *action,
                   unsigned mode)
 {
        might_sleep();
-       if (!test_bit(bit, word))
+       if (!test_bit_acquire(bit, word))
                return 0;
        return out_of_line_wait_on_bit(word, bit, action, mode);
 }
index cee5f83..b69ca69 100644 (file)
@@ -66,8 +66,6 @@ int rxrpc_kernel_charge_accept(struct socket *, rxrpc_notify_rx_t,
 void rxrpc_kernel_set_tx_length(struct socket *, struct rxrpc_call *, s64);
 bool rxrpc_kernel_check_life(const struct socket *, const struct rxrpc_call *);
 u32 rxrpc_kernel_get_epoch(struct socket *, struct rxrpc_call *);
-bool rxrpc_kernel_get_reply_time(struct socket *, struct rxrpc_call *,
-                                ktime_t *);
 bool rxrpc_kernel_call_is_complete(struct rxrpc_call *);
 void rxrpc_kernel_set_max_life(struct socket *, struct rxrpc_call *,
                               unsigned long);
index 184105d..be2992e 100644 (file)
@@ -290,7 +290,7 @@ static inline const char *bond_3ad_churn_desc(churn_state_t state)
 }
 
 /* ========== AD Exported functions to the main bonding code ========== */
-void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution);
+void bond_3ad_initialize(struct bonding *bond);
 void bond_3ad_bind_slave(struct slave *slave);
 void bond_3ad_unbind_slave(struct slave *slave);
 void bond_3ad_state_machine_handler(struct work_struct *);
index c4898fc..f90f002 100644 (file)
@@ -33,7 +33,7 @@ extern unsigned int sysctl_net_busy_poll __read_mostly;
 
 static inline bool net_busy_loop_on(void)
 {
-       return sysctl_net_busy_poll;
+       return READ_ONCE(sysctl_net_busy_poll);
 }
 
 static inline bool sk_can_busy_loop(const struct sock *sk)
index fae9b40..c1cbcdb 100644 (file)
@@ -3,6 +3,73 @@
 #ifndef _LINUX_DROPREASON_H
 #define _LINUX_DROPREASON_H
 
+#define DEFINE_DROP_REASON(FN, FNe)    \
+       FN(NOT_SPECIFIED)               \
+       FN(NO_SOCKET)                   \
+       FN(PKT_TOO_SMALL)               \
+       FN(TCP_CSUM)                    \
+       FN(SOCKET_FILTER)               \
+       FN(UDP_CSUM)                    \
+       FN(NETFILTER_DROP)              \
+       FN(OTHERHOST)                   \
+       FN(IP_CSUM)                     \
+       FN(IP_INHDR)                    \
+       FN(IP_RPFILTER)                 \
+       FN(UNICAST_IN_L2_MULTICAST)     \
+       FN(XFRM_POLICY)                 \
+       FN(IP_NOPROTO)                  \
+       FN(SOCKET_RCVBUFF)              \
+       FN(PROTO_MEM)                   \
+       FN(TCP_MD5NOTFOUND)             \
+       FN(TCP_MD5UNEXPECTED)           \
+       FN(TCP_MD5FAILURE)              \
+       FN(SOCKET_BACKLOG)              \
+       FN(TCP_FLAGS)                   \
+       FN(TCP_ZEROWINDOW)              \
+       FN(TCP_OLD_DATA)                \
+       FN(TCP_OVERWINDOW)              \
+       FN(TCP_OFOMERGE)                \
+       FN(TCP_RFC7323_PAWS)            \
+       FN(TCP_INVALID_SEQUENCE)        \
+       FN(TCP_RESET)                   \
+       FN(TCP_INVALID_SYN)             \
+       FN(TCP_CLOSE)                   \
+       FN(TCP_FASTOPEN)                \
+       FN(TCP_OLD_ACK)                 \
+       FN(TCP_TOO_OLD_ACK)             \
+       FN(TCP_ACK_UNSENT_DATA)         \
+       FN(TCP_OFO_QUEUE_PRUNE)         \
+       FN(TCP_OFO_DROP)                \
+       FN(IP_OUTNOROUTES)              \
+       FN(BPF_CGROUP_EGRESS)           \
+       FN(IPV6DISABLED)                \
+       FN(NEIGH_CREATEFAIL)            \
+       FN(NEIGH_FAILED)                \
+       FN(NEIGH_QUEUEFULL)             \
+       FN(NEIGH_DEAD)                  \
+       FN(TC_EGRESS)                   \
+       FN(QDISC_DROP)                  \
+       FN(CPU_BACKLOG)                 \
+       FN(XDP)                         \
+       FN(TC_INGRESS)                  \
+       FN(UNHANDLED_PROTO)             \
+       FN(SKB_CSUM)                    \
+       FN(SKB_GSO_SEG)                 \
+       FN(SKB_UCOPY_FAULT)             \
+       FN(DEV_HDR)                     \
+       FN(DEV_READY)                   \
+       FN(FULL_RING)                   \
+       FN(NOMEM)                       \
+       FN(HDR_TRUNC)                   \
+       FN(TAP_FILTER)                  \
+       FN(TAP_TXFILTER)                \
+       FN(ICMP_CSUM)                   \
+       FN(INVALID_PROTO)               \
+       FN(IP_INADDRERRORS)             \
+       FN(IP_INNOROUTES)               \
+       FN(PKT_TOO_BIG)                 \
+       FNe(MAX)
+
 /**
  * enum skb_drop_reason - the reasons of skb drops
  *
index 867656b..24003de 100644 (file)
@@ -439,7 +439,7 @@ static inline void gro_normal_one(struct napi_struct *napi, struct sk_buff *skb,
 {
        list_add_tail(&skb->list, &napi->rx_list);
        napi->rx_count += segs;
-       if (napi->rx_count >= gro_normal_batch)
+       if (napi->rx_count >= READ_ONCE(gro_normal_batch))
                gro_normal_list(napi);
 }
 
index 63fac94..ced80e2 100644 (file)
@@ -246,7 +246,8 @@ static inline void ip_tunnel_init_flow(struct flowi4 *fl4,
                                       __be32 daddr, __be32 saddr,
                                       __be32 key, __u8 tos,
                                       struct net *net, int oif,
-                                      __u32 mark, __u32 tun_inner_hash)
+                                      __u32 mark, __u32 tun_inner_hash,
+                                      __u8 flow_flags)
 {
        memset(fl4, 0, sizeof(*fl4));
 
@@ -263,6 +264,7 @@ static inline void ip_tunnel_init_flow(struct flowi4 *fl4,
        fl4->fl4_gre_key = key;
        fl4->flowi4_mark = mark;
        fl4->flowi4_multipath_hash = tun_inner_hash;
+       fl4->flowi4_flags = flow_flags;
 }
 
 int ip_tunnel_init(struct net_device *dev);
index 9f0bab0..3827a6b 100644 (file)
@@ -83,6 +83,7 @@ struct neigh_parms {
        struct rcu_head rcu_head;
 
        int     reachable_time;
+       int     qlen;
        int     data[NEIGH_VAR_DATA_MAX];
        DECLARE_BITMAP(data_state, NEIGH_VAR_DATA_MAX);
 };
index a32be8a..6a2019a 100644 (file)
@@ -53,8 +53,6 @@ struct nf_conntrack_net {
        /* only used when new connection is allocated: */
        atomic_t count;
        unsigned int expect_count;
-       u8 sysctl_auto_assign_helper;
-       bool auto_assign_helper_warned;
 
        /* only used from work queues, configuration plane, and so on: */
        unsigned int users4;
index d5326c4..cd982f4 100644 (file)
@@ -270,6 +270,7 @@ void flow_offload_refresh(struct nf_flowtable *flow_table,
 
 struct flow_offload_tuple_rhash *flow_offload_lookup(struct nf_flowtable *flow_table,
                                                     struct flow_offload_tuple *tuple);
+void nf_flow_table_gc_run(struct nf_flowtable *flow_table);
 void nf_flow_table_gc_cleanup(struct nf_flowtable *flowtable,
                              struct net_device *dev);
 void nf_flow_table_cleanup(struct net_device *dev);
@@ -306,6 +307,8 @@ void nf_flow_offload_stats(struct nf_flowtable *flowtable,
                           struct flow_offload *flow);
 
 void nf_flow_table_offload_flush(struct nf_flowtable *flowtable);
+void nf_flow_table_offload_flush_cleanup(struct nf_flowtable *flowtable);
+
 int nf_flow_table_offload_setup(struct nf_flowtable *flowtable,
                                struct net_device *dev,
                                enum flow_block_command cmd);
index 99aae36..cdb7db9 100644 (file)
@@ -1652,6 +1652,7 @@ struct nftables_pernet {
        struct list_head        module_list;
        struct list_head        notify_list;
        struct mutex            commit_mutex;
+       u64                     table_handle;
        unsigned int            base_seq;
        u8                      validate_state;
 };
index 0677cd3..e1290c1 100644 (file)
@@ -95,13 +95,12 @@ struct nf_ip_net {
 
 struct netns_ct {
 #ifdef CONFIG_NF_CONNTRACK_EVENTS
-       bool ctnetlink_has_listener;
+       u8 ctnetlink_has_listener;
        bool ecache_dwork_pending;
 #endif
        u8                      sysctl_log_invalid; /* Log invalid packets */
        u8                      sysctl_events;
        u8                      sysctl_acct;
-       u8                      sysctl_auto_assign_helper;
        u8                      sysctl_tstamp;
        u8                      sysctl_checksum;
 
index c7320ef..6320a76 100644 (file)
@@ -179,6 +179,8 @@ struct netns_ipv4 {
        unsigned int sysctl_tcp_fastopen_blackhole_timeout;
        atomic_t tfo_active_disable_times;
        unsigned long tfo_active_disable_stamp;
+       u32 tcp_challenge_timestamp;
+       u32 tcp_challenge_count;
 
        int sysctl_udp_wmem_min;
        int sysctl_udp_rmem_min;
index 05a1bbd..d08cfe1 100644 (file)
@@ -578,6 +578,31 @@ static inline bool sk_user_data_is_nocopy(const struct sock *sk)
 #define __sk_user_data(sk) ((*((void __rcu **)&(sk)->sk_user_data)))
 
 /**
+ * __locked_read_sk_user_data_with_flags - return the pointer
+ * only if argument flags all has been set in sk_user_data. Otherwise
+ * return NULL
+ *
+ * @sk: socket
+ * @flags: flag bits
+ *
+ * The caller must be holding sk->sk_callback_lock.
+ */
+static inline void *
+__locked_read_sk_user_data_with_flags(const struct sock *sk,
+                                     uintptr_t flags)
+{
+       uintptr_t sk_user_data =
+               (uintptr_t)rcu_dereference_check(__sk_user_data(sk),
+                                                lockdep_is_held(&sk->sk_callback_lock));
+
+       WARN_ON_ONCE(flags & SK_USER_DATA_PTRMASK);
+
+       if ((sk_user_data & flags) == flags)
+               return (void *)(sk_user_data & SK_USER_DATA_PTRMASK);
+       return NULL;
+}
+
+/**
  * __rcu_dereference_sk_user_data_with_flags - return the pointer
  * only if argument flags all has been set in sk_user_data. Otherwise
  * return NULL
index afc7ce7..72394f4 100644 (file)
@@ -67,6 +67,9 @@ static inline int udp_sock_create(struct net *net,
 typedef int (*udp_tunnel_encap_rcv_t)(struct sock *sk, struct sk_buff *skb);
 typedef int (*udp_tunnel_encap_err_lookup_t)(struct sock *sk,
                                             struct sk_buff *skb);
+typedef void (*udp_tunnel_encap_err_rcv_t)(struct sock *sk,
+                                          struct sk_buff *skb,
+                                          unsigned int udp_offset);
 typedef void (*udp_tunnel_encap_destroy_t)(struct sock *sk);
 typedef struct sk_buff *(*udp_tunnel_gro_receive_t)(struct sock *sk,
                                                    struct list_head *head,
@@ -80,6 +83,7 @@ struct udp_tunnel_sock_cfg {
        __u8  encap_type;
        udp_tunnel_encap_rcv_t encap_rcv;
        udp_tunnel_encap_err_lookup_t encap_err_lookup;
+       udp_tunnel_encap_err_rcv_t encap_err_rcv;
        udp_tunnel_encap_destroy_t encap_destroy;
        udp_tunnel_gro_receive_t gro_receive;
        udp_tunnel_gro_complete_t gro_complete;
index 3113471..2493bd6 100644 (file)
@@ -309,8 +309,6 @@ struct scsi_target {
        struct list_head        devices;
        struct device           dev;
        struct kref             reap_ref; /* last put renders target invisible */
-       atomic_t                sdev_count;
-       wait_queue_head_t       sdev_wq;
        unsigned int            channel;
        unsigned int            id; /* target id ... replace
                                     * scsi_device.id eventually */
index aa7b749..9b0a028 100644 (file)
@@ -557,6 +557,8 @@ struct Scsi_Host {
        struct scsi_host_template *hostt;
        struct scsi_transport_template *transportt;
 
+       struct kref             tagset_refcnt;
+       struct completion       tagset_freed;
        /* Area to keep a shared tag map */
        struct blk_mq_tag_set   tag_set;
 
@@ -690,9 +692,6 @@ struct Scsi_Host {
        /* ldm bits */
        struct device           shost_gendev, shost_dev;
 
-       atomic_t                target_count;
-       wait_queue_head_t       targets_wq;
-
        /*
         * Points to the transport data (if any) which is allocated
         * separately
index 9e17247..6ce3bd2 100644 (file)
 #define                DDR3PHY_DSGCR_ODTPDD_ODT0       (1 << 20)       /* ODT[0] Power Down Driver */
 
 #define DDR3PHY_ZQ0SR0                         (0x188)         /* ZQ status register 0 */
+#define DDR3PHY_ZQ0SR0_PDO_OFF                 (0)             /* Pull-down output impedance select offset */
+#define DDR3PHY_ZQ0SR0_PUO_OFF                 (5)             /* Pull-up output impedance select offset */
+#define DDR3PHY_ZQ0SR0_PDODT_OFF               (10)            /* Pull-down on-die termination impedance select offset */
+#define DDR3PHY_ZQ0SRO_PUODT_OFF               (15)            /* Pull-up on-die termination impedance select offset */
+
+#define        DDR3PHY_DX0DLLCR                        (0x1CC)         /* DDR3PHY DATX8 DLL Control Register */
+#define        DDR3PHY_DX1DLLCR                        (0x20C)         /* DDR3PHY DATX8 DLL Control Register */
+#define                DDR3PHY_DXDLLCR_DLLDIS          (1 << 31)       /* DLL Disable */
 
 /* UDDRC */
 #define UDDRC_STAT                             (0x04)          /* UDDRC Operating Mode Status Register */
index ac151ec..2edea90 100644 (file)
 #define REG_RESERVED_ADDR              0xffffffff
 #define REG_RESERVED(reg)              REG(reg, REG_RESERVED_ADDR)
 
-#define for_each_stat(ocelot, stat)                            \
-       for ((stat) = (ocelot)->stats_layout;                   \
-            ((stat)->name[0] != '\0');                         \
-            (stat)++)
-
 enum ocelot_target {
        ANA = 1,
        QS,
@@ -335,13 +330,38 @@ enum ocelot_reg {
        SYS_COUNT_RX_64,
        SYS_COUNT_RX_65_127,
        SYS_COUNT_RX_128_255,
-       SYS_COUNT_RX_256_1023,
+       SYS_COUNT_RX_256_511,
+       SYS_COUNT_RX_512_1023,
        SYS_COUNT_RX_1024_1526,
        SYS_COUNT_RX_1527_MAX,
        SYS_COUNT_RX_PAUSE,
        SYS_COUNT_RX_CONTROL,
        SYS_COUNT_RX_LONGS,
        SYS_COUNT_RX_CLASSIFIED_DROPS,
+       SYS_COUNT_RX_RED_PRIO_0,
+       SYS_COUNT_RX_RED_PRIO_1,
+       SYS_COUNT_RX_RED_PRIO_2,
+       SYS_COUNT_RX_RED_PRIO_3,
+       SYS_COUNT_RX_RED_PRIO_4,
+       SYS_COUNT_RX_RED_PRIO_5,
+       SYS_COUNT_RX_RED_PRIO_6,
+       SYS_COUNT_RX_RED_PRIO_7,
+       SYS_COUNT_RX_YELLOW_PRIO_0,
+       SYS_COUNT_RX_YELLOW_PRIO_1,
+       SYS_COUNT_RX_YELLOW_PRIO_2,
+       SYS_COUNT_RX_YELLOW_PRIO_3,
+       SYS_COUNT_RX_YELLOW_PRIO_4,
+       SYS_COUNT_RX_YELLOW_PRIO_5,
+       SYS_COUNT_RX_YELLOW_PRIO_6,
+       SYS_COUNT_RX_YELLOW_PRIO_7,
+       SYS_COUNT_RX_GREEN_PRIO_0,
+       SYS_COUNT_RX_GREEN_PRIO_1,
+       SYS_COUNT_RX_GREEN_PRIO_2,
+       SYS_COUNT_RX_GREEN_PRIO_3,
+       SYS_COUNT_RX_GREEN_PRIO_4,
+       SYS_COUNT_RX_GREEN_PRIO_5,
+       SYS_COUNT_RX_GREEN_PRIO_6,
+       SYS_COUNT_RX_GREEN_PRIO_7,
        SYS_COUNT_TX_OCTETS,
        SYS_COUNT_TX_UNICAST,
        SYS_COUNT_TX_MULTICAST,
@@ -351,11 +371,46 @@ enum ocelot_reg {
        SYS_COUNT_TX_PAUSE,
        SYS_COUNT_TX_64,
        SYS_COUNT_TX_65_127,
-       SYS_COUNT_TX_128_511,
+       SYS_COUNT_TX_128_255,
+       SYS_COUNT_TX_256_511,
        SYS_COUNT_TX_512_1023,
        SYS_COUNT_TX_1024_1526,
        SYS_COUNT_TX_1527_MAX,
+       SYS_COUNT_TX_YELLOW_PRIO_0,
+       SYS_COUNT_TX_YELLOW_PRIO_1,
+       SYS_COUNT_TX_YELLOW_PRIO_2,
+       SYS_COUNT_TX_YELLOW_PRIO_3,
+       SYS_COUNT_TX_YELLOW_PRIO_4,
+       SYS_COUNT_TX_YELLOW_PRIO_5,
+       SYS_COUNT_TX_YELLOW_PRIO_6,
+       SYS_COUNT_TX_YELLOW_PRIO_7,
+       SYS_COUNT_TX_GREEN_PRIO_0,
+       SYS_COUNT_TX_GREEN_PRIO_1,
+       SYS_COUNT_TX_GREEN_PRIO_2,
+       SYS_COUNT_TX_GREEN_PRIO_3,
+       SYS_COUNT_TX_GREEN_PRIO_4,
+       SYS_COUNT_TX_GREEN_PRIO_5,
+       SYS_COUNT_TX_GREEN_PRIO_6,
+       SYS_COUNT_TX_GREEN_PRIO_7,
        SYS_COUNT_TX_AGING,
+       SYS_COUNT_DROP_LOCAL,
+       SYS_COUNT_DROP_TAIL,
+       SYS_COUNT_DROP_YELLOW_PRIO_0,
+       SYS_COUNT_DROP_YELLOW_PRIO_1,
+       SYS_COUNT_DROP_YELLOW_PRIO_2,
+       SYS_COUNT_DROP_YELLOW_PRIO_3,
+       SYS_COUNT_DROP_YELLOW_PRIO_4,
+       SYS_COUNT_DROP_YELLOW_PRIO_5,
+       SYS_COUNT_DROP_YELLOW_PRIO_6,
+       SYS_COUNT_DROP_YELLOW_PRIO_7,
+       SYS_COUNT_DROP_GREEN_PRIO_0,
+       SYS_COUNT_DROP_GREEN_PRIO_1,
+       SYS_COUNT_DROP_GREEN_PRIO_2,
+       SYS_COUNT_DROP_GREEN_PRIO_3,
+       SYS_COUNT_DROP_GREEN_PRIO_4,
+       SYS_COUNT_DROP_GREEN_PRIO_5,
+       SYS_COUNT_DROP_GREEN_PRIO_6,
+       SYS_COUNT_DROP_GREEN_PRIO_7,
        SYS_RESET_CFG,
        SYS_SR_ETYPE_CFG,
        SYS_VLAN_ETYPE_CFG,
@@ -538,16 +593,111 @@ enum ocelot_ptp_pins {
        TOD_ACC_PIN
 };
 
+enum ocelot_stat {
+       OCELOT_STAT_RX_OCTETS,
+       OCELOT_STAT_RX_UNICAST,
+       OCELOT_STAT_RX_MULTICAST,
+       OCELOT_STAT_RX_BROADCAST,
+       OCELOT_STAT_RX_SHORTS,
+       OCELOT_STAT_RX_FRAGMENTS,
+       OCELOT_STAT_RX_JABBERS,
+       OCELOT_STAT_RX_CRC_ALIGN_ERRS,
+       OCELOT_STAT_RX_SYM_ERRS,
+       OCELOT_STAT_RX_64,
+       OCELOT_STAT_RX_65_127,
+       OCELOT_STAT_RX_128_255,
+       OCELOT_STAT_RX_256_511,
+       OCELOT_STAT_RX_512_1023,
+       OCELOT_STAT_RX_1024_1526,
+       OCELOT_STAT_RX_1527_MAX,
+       OCELOT_STAT_RX_PAUSE,
+       OCELOT_STAT_RX_CONTROL,
+       OCELOT_STAT_RX_LONGS,
+       OCELOT_STAT_RX_CLASSIFIED_DROPS,
+       OCELOT_STAT_RX_RED_PRIO_0,
+       OCELOT_STAT_RX_RED_PRIO_1,
+       OCELOT_STAT_RX_RED_PRIO_2,
+       OCELOT_STAT_RX_RED_PRIO_3,
+       OCELOT_STAT_RX_RED_PRIO_4,
+       OCELOT_STAT_RX_RED_PRIO_5,
+       OCELOT_STAT_RX_RED_PRIO_6,
+       OCELOT_STAT_RX_RED_PRIO_7,
+       OCELOT_STAT_RX_YELLOW_PRIO_0,
+       OCELOT_STAT_RX_YELLOW_PRIO_1,
+       OCELOT_STAT_RX_YELLOW_PRIO_2,
+       OCELOT_STAT_RX_YELLOW_PRIO_3,
+       OCELOT_STAT_RX_YELLOW_PRIO_4,
+       OCELOT_STAT_RX_YELLOW_PRIO_5,
+       OCELOT_STAT_RX_YELLOW_PRIO_6,
+       OCELOT_STAT_RX_YELLOW_PRIO_7,
+       OCELOT_STAT_RX_GREEN_PRIO_0,
+       OCELOT_STAT_RX_GREEN_PRIO_1,
+       OCELOT_STAT_RX_GREEN_PRIO_2,
+       OCELOT_STAT_RX_GREEN_PRIO_3,
+       OCELOT_STAT_RX_GREEN_PRIO_4,
+       OCELOT_STAT_RX_GREEN_PRIO_5,
+       OCELOT_STAT_RX_GREEN_PRIO_6,
+       OCELOT_STAT_RX_GREEN_PRIO_7,
+       OCELOT_STAT_TX_OCTETS,
+       OCELOT_STAT_TX_UNICAST,
+       OCELOT_STAT_TX_MULTICAST,
+       OCELOT_STAT_TX_BROADCAST,
+       OCELOT_STAT_TX_COLLISION,
+       OCELOT_STAT_TX_DROPS,
+       OCELOT_STAT_TX_PAUSE,
+       OCELOT_STAT_TX_64,
+       OCELOT_STAT_TX_65_127,
+       OCELOT_STAT_TX_128_255,
+       OCELOT_STAT_TX_256_511,
+       OCELOT_STAT_TX_512_1023,
+       OCELOT_STAT_TX_1024_1526,
+       OCELOT_STAT_TX_1527_MAX,
+       OCELOT_STAT_TX_YELLOW_PRIO_0,
+       OCELOT_STAT_TX_YELLOW_PRIO_1,
+       OCELOT_STAT_TX_YELLOW_PRIO_2,
+       OCELOT_STAT_TX_YELLOW_PRIO_3,
+       OCELOT_STAT_TX_YELLOW_PRIO_4,
+       OCELOT_STAT_TX_YELLOW_PRIO_5,
+       OCELOT_STAT_TX_YELLOW_PRIO_6,
+       OCELOT_STAT_TX_YELLOW_PRIO_7,
+       OCELOT_STAT_TX_GREEN_PRIO_0,
+       OCELOT_STAT_TX_GREEN_PRIO_1,
+       OCELOT_STAT_TX_GREEN_PRIO_2,
+       OCELOT_STAT_TX_GREEN_PRIO_3,
+       OCELOT_STAT_TX_GREEN_PRIO_4,
+       OCELOT_STAT_TX_GREEN_PRIO_5,
+       OCELOT_STAT_TX_GREEN_PRIO_6,
+       OCELOT_STAT_TX_GREEN_PRIO_7,
+       OCELOT_STAT_TX_AGED,
+       OCELOT_STAT_DROP_LOCAL,
+       OCELOT_STAT_DROP_TAIL,
+       OCELOT_STAT_DROP_YELLOW_PRIO_0,
+       OCELOT_STAT_DROP_YELLOW_PRIO_1,
+       OCELOT_STAT_DROP_YELLOW_PRIO_2,
+       OCELOT_STAT_DROP_YELLOW_PRIO_3,
+       OCELOT_STAT_DROP_YELLOW_PRIO_4,
+       OCELOT_STAT_DROP_YELLOW_PRIO_5,
+       OCELOT_STAT_DROP_YELLOW_PRIO_6,
+       OCELOT_STAT_DROP_YELLOW_PRIO_7,
+       OCELOT_STAT_DROP_GREEN_PRIO_0,
+       OCELOT_STAT_DROP_GREEN_PRIO_1,
+       OCELOT_STAT_DROP_GREEN_PRIO_2,
+       OCELOT_STAT_DROP_GREEN_PRIO_3,
+       OCELOT_STAT_DROP_GREEN_PRIO_4,
+       OCELOT_STAT_DROP_GREEN_PRIO_5,
+       OCELOT_STAT_DROP_GREEN_PRIO_6,
+       OCELOT_STAT_DROP_GREEN_PRIO_7,
+       OCELOT_NUM_STATS,
+};
+
 struct ocelot_stat_layout {
-       u32 offset;
+       u32 reg;
        char name[ETH_GSTRING_LEN];
 };
 
-#define OCELOT_STAT_END { .name = "" }
-
 struct ocelot_stats_region {
        struct list_head node;
-       u32 offset;
+       u32 base;
        int count;
        u32 *buf;
 };
@@ -707,7 +857,6 @@ struct ocelot {
        const u32 *const                *map;
        const struct ocelot_stat_layout *stats_layout;
        struct list_head                stats_regions;
-       unsigned int                    num_stats;
 
        u32                             pool_size[OCELOT_SB_NUM][OCELOT_SB_POOL_NUM];
        int                             packet_buffer_size;
@@ -750,7 +899,7 @@ struct ocelot {
        struct ocelot_psfp_list         psfp;
 
        /* Workqueue to check statistics for overflow with its lock */
-       struct mutex                    stats_lock;
+       spinlock_t                      stats_lock;
        u64                             *stats;
        struct delayed_work             stats_work;
        struct workqueue_struct         *stats_queue;
@@ -786,8 +935,8 @@ struct ocelot_policer {
        u32 burst; /* bytes */
 };
 
-#define ocelot_bulk_read_rix(ocelot, reg, ri, buf, count) \
-       __ocelot_bulk_read_ix(ocelot, reg, reg##_RSZ * (ri), buf, count)
+#define ocelot_bulk_read(ocelot, reg, buf, count) \
+       __ocelot_bulk_read_ix(ocelot, reg, 0, buf, count)
 
 #define ocelot_read_ix(ocelot, reg, gi, ri) \
        __ocelot_read_ix(ocelot, reg, reg##_GSZ * (gi) + reg##_RSZ * (ri))
index 45264e4..50a974f 100644 (file)
@@ -9,6 +9,15 @@
 #include <linux/netdevice.h>
 #include <linux/tracepoint.h>
 
+#undef FN
+#define FN(reason)     TRACE_DEFINE_ENUM(SKB_DROP_REASON_##reason);
+DEFINE_DROP_REASON(FN, FN)
+
+#undef FN
+#undef FNe
+#define FN(reason)     { SKB_DROP_REASON_##reason, #reason },
+#define FNe(reason)    { SKB_DROP_REASON_##reason, #reason }
+
 /*
  * Tracepoint for free an sk_buff:
  */
@@ -35,9 +44,13 @@ TRACE_EVENT(kfree_skb,
 
        TP_printk("skbaddr=%p protocol=%u location=%p reason: %s",
                  __entry->skbaddr, __entry->protocol, __entry->location,
-                 drop_reasons[__entry->reason])
+                 __print_symbolic(__entry->reason,
+                                  DEFINE_DROP_REASON(FN, FNe)))
 );
 
+#undef FN
+#undef FNe
+
 TRACE_EVENT(consume_skb,
 
        TP_PROTO(struct sk_buff *skb),
index 7bf9ba1..59a217c 100644 (file)
@@ -79,7 +79,7 @@ struct bpf_insn {
 /* Key of an a BPF_MAP_TYPE_LPM_TRIE entry */
 struct bpf_lpm_trie_key {
        __u32   prefixlen;      /* up to 32 for AF_INET, 128 for AF_INET6 */
-       __u8    data[]; /* Arbitrary size */
+       __u8    data[0];        /* Arbitrary size */
 };
 
 struct bpf_cgroup_storage_key {
index 1463cfe..6b83177 100644 (file)
 #include <linux/types.h>
 #include <linux/time_types.h>
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /*
  * IO submission data structure (Submission Queue Entry)
  */
@@ -67,8 +71,8 @@ struct io_uring_sqe {
                __s32   splice_fd_in;
                __u32   file_index;
                struct {
-                       __u16   notification_idx;
                        __u16   addr_len;
+                       __u16   __pad3[1];
                };
        };
        union {
@@ -174,8 +178,7 @@ enum io_uring_op {
        IORING_OP_FALLOCATE,
        IORING_OP_OPENAT,
        IORING_OP_CLOSE,
-       IORING_OP_RSRC_UPDATE,
-       IORING_OP_FILES_UPDATE = IORING_OP_RSRC_UPDATE,
+       IORING_OP_FILES_UPDATE,
        IORING_OP_STATX,
        IORING_OP_READ,
        IORING_OP_WRITE,
@@ -202,7 +205,7 @@ enum io_uring_op {
        IORING_OP_GETXATTR,
        IORING_OP_SOCKET,
        IORING_OP_URING_CMD,
-       IORING_OP_SENDZC_NOTIF,
+       IORING_OP_SEND_ZC,
 
        /* this goes last, obviously */
        IORING_OP_LAST,
@@ -224,7 +227,6 @@ enum io_uring_op {
 #define IORING_TIMEOUT_ETIME_SUCCESS   (1U << 5)
 #define IORING_TIMEOUT_CLOCK_MASK      (IORING_TIMEOUT_BOOTTIME | IORING_TIMEOUT_REALTIME)
 #define IORING_TIMEOUT_UPDATE_MASK     (IORING_TIMEOUT_UPDATE | IORING_LINK_TIMEOUT_UPDATE)
-
 /*
  * sqe->splice_flags
  * extends splice(2) flags
@@ -277,29 +279,16 @@ enum io_uring_op {
  *
  * IORING_RECVSEND_FIXED_BUF   Use registered buffers, the index is stored in
  *                             the buf_index field.
- *
- * IORING_RECVSEND_NOTIF_FLUSH Flush a notification after a successful
- *                             successful. Only for zerocopy sends.
  */
 #define IORING_RECVSEND_POLL_FIRST     (1U << 0)
 #define IORING_RECV_MULTISHOT          (1U << 1)
 #define IORING_RECVSEND_FIXED_BUF      (1U << 2)
-#define IORING_RECVSEND_NOTIF_FLUSH    (1U << 3)
 
 /*
  * accept flags stored in sqe->ioprio
  */
 #define IORING_ACCEPT_MULTISHOT        (1U << 0)
 
-
-/*
- * IORING_OP_RSRC_UPDATE flags
- */
-enum {
-       IORING_RSRC_UPDATE_FILES,
-       IORING_RSRC_UPDATE_NOTIF,
-};
-
 /*
  * IORING_OP_MSG_RING command types, stored in sqe->addr
  */
@@ -337,10 +326,13 @@ struct io_uring_cqe {
  * IORING_CQE_F_BUFFER If set, the upper 16 bits are the buffer ID
  * IORING_CQE_F_MORE   If set, parent SQE will generate more CQE entries
  * IORING_CQE_F_SOCK_NONEMPTY  If set, more data to read after socket recv
+ * IORING_CQE_F_NOTIF  Set for notification CQEs. Can be used to distinct
+ *                     them from sends.
  */
 #define IORING_CQE_F_BUFFER            (1U << 0)
 #define IORING_CQE_F_MORE              (1U << 1)
 #define IORING_CQE_F_SOCK_NONEMPTY     (1U << 2)
+#define IORING_CQE_F_NOTIF             (1U << 3)
 
 enum {
        IORING_CQE_BUFFER_SHIFT         = 16,
@@ -481,10 +473,6 @@ enum {
        /* register a range of fixed file slots for automatic slot allocation */
        IORING_REGISTER_FILE_ALLOC_RANGE        = 25,
 
-       /* zerocopy notification API */
-       IORING_REGISTER_NOTIFIERS               = 26,
-       IORING_UNREGISTER_NOTIFIERS             = 27,
-
        /* this goes last */
        IORING_REGISTER_LAST
 };
@@ -661,4 +649,8 @@ struct io_uring_recvmsg_out {
        __u32 flags;
 };
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif
index 29ced55..6cb842e 100644 (file)
@@ -56,7 +56,7 @@
 #define VIRTIO_NET_F_MQ        22      /* Device supports Receive Flow
                                         * Steering */
 #define VIRTIO_NET_F_CTRL_MAC_ADDR 23  /* Set MAC address */
-#define VIRTIO_NET_F_NOTF_COAL 53      /* Guest can handle notifications coalescing */
+#define VIRTIO_NET_F_NOTF_COAL 53      /* Device supports notifications coalescing */
 #define VIRTIO_NET_F_HASH_REPORT  57   /* Supports hash report */
 #define VIRTIO_NET_F_RSS         60    /* Supports RSS RX steering */
 #define VIRTIO_NET_F_RSC_EXT     61    /* extended coalescing info */
@@ -364,24 +364,24 @@ struct virtio_net_hash_config {
  */
 #define VIRTIO_NET_CTRL_NOTF_COAL              6
 /*
- * Set the tx-usecs/tx-max-packets patameters.
- * tx-usecs - Maximum number of usecs to delay a TX notification.
- * tx-max-packets - Maximum number of packets to send before a TX notification.
+ * Set the tx-usecs/tx-max-packets parameters.
  */
 struct virtio_net_ctrl_coal_tx {
+       /* Maximum number of packets to send before a TX notification */
        __le32 tx_max_packets;
+       /* Maximum number of usecs to delay a TX notification */
        __le32 tx_usecs;
 };
 
 #define VIRTIO_NET_CTRL_NOTF_COAL_TX_SET               0
 
 /*
- * Set the rx-usecs/rx-max-packets patameters.
- * rx-usecs - Maximum number of usecs to delay a RX notification.
- * rx-max-frames - Maximum number of packets to receive before a RX notification.
+ * Set the rx-usecs/rx-max-packets parameters.
  */
 struct virtio_net_ctrl_coal_rx {
+       /* Maximum number of packets to receive before a RX notification */
        __le32 rx_max_packets;
+       /* Maximum number of usecs to delay a RX notification */
        __le32 rx_usecs;
 };
 
index 476d3e5..f8c20d3 100644 (file)
 #define VRING_USED_ALIGN_SIZE 4
 #define VRING_DESC_ALIGN_SIZE 16
 
-/* Virtio ring descriptors: 16 bytes.  These can chain together via "next". */
+/**
+ * struct vring_desc - Virtio ring descriptors,
+ * 16 bytes long. These can chain together via @next.
+ *
+ * @addr: buffer address (guest-physical)
+ * @len: buffer length
+ * @flags: descriptor flags
+ * @next: index of the next descriptor in the chain,
+ *        if the VRING_DESC_F_NEXT flag is set. We chain unused
+ *        descriptors via this, too.
+ */
 struct vring_desc {
-       /* Address (guest-physical). */
        __virtio64 addr;
-       /* Length. */
        __virtio32 len;
-       /* The flags as indicated above. */
        __virtio16 flags;
-       /* We chain unused descriptors via this, too */
        __virtio16 next;
 };
 
index b1f3e6a..4f84ea7 100644 (file)
@@ -296,7 +296,7 @@ enum xfrm_attr_type_t {
        XFRMA_ETIMER_THRESH,
        XFRMA_SRCADDR,          /* xfrm_address_t */
        XFRMA_COADDR,           /* xfrm_address_t */
-       XFRMA_LASTUSED,         /* unsigned long  */
+       XFRMA_LASTUSED,         /* __u64 */
        XFRMA_POLICY_TYPE,      /* struct xfrm_userpolicy_type */
        XFRMA_MIGRATE,
        XFRMA_ALG_AEAD,         /* struct xfrm_algo_aead */
index f81aa95..f525566 100644 (file)
@@ -135,11 +135,7 @@ static inline u32 ufshci_version(u32 major, u32 minor)
 
 #define UFSHCD_UIC_MASK                (UIC_COMMAND_COMPL | UFSHCD_UIC_PWR_MASK)
 
-#define UFSHCD_ERROR_MASK      (UIC_ERROR |\
-                               DEVICE_FATAL_ERROR |\
-                               CONTROLLER_FATAL_ERROR |\
-                               SYSTEM_BUS_FATAL_ERROR |\
-                               CRYPTO_ENGINE_FATAL_ERROR)
+#define UFSHCD_ERROR_MASK      (UIC_ERROR | INT_FATAL_ERRORS)
 
 #define INT_FATAL_ERRORS       (DEVICE_FATAL_ERROR |\
                                CONTROLLER_FATAL_ERROR |\
index 80fe60f..532362f 100644 (file)
@@ -70,11 +70,7 @@ config CC_CAN_LINK_STATIC
        default $(success,$(srctree)/scripts/cc-can-link.sh $(CC) $(CLANG_FLAGS) $(USERCFLAGS) $(USERLDFLAGS) $(m64-flag) -static) if 64BIT
        default $(success,$(srctree)/scripts/cc-can-link.sh $(CC) $(CLANG_FLAGS) $(USERCFLAGS) $(USERLDFLAGS) $(m32-flag) -static)
 
-config CC_HAS_ASM_GOTO
-       def_bool $(success,$(srctree)/scripts/gcc-goto.sh $(CC))
-
 config CC_HAS_ASM_GOTO_OUTPUT
-       depends on CC_HAS_ASM_GOTO
        def_bool $(success,echo 'int foo(int x) { asm goto ("": "=r"(x) ::: bar); return x; bar: return 0; }' | $(CC) -x c - -c -o /dev/null)
 
 config CC_HAS_ASM_GOTO_TIED_OUTPUT
index 91642a4..1fe7942 100644 (file)
@@ -1446,13 +1446,25 @@ static noinline void __init kernel_init_freeable(void);
 
 #if defined(CONFIG_STRICT_KERNEL_RWX) || defined(CONFIG_STRICT_MODULE_RWX)
 bool rodata_enabled __ro_after_init = true;
+
+#ifndef arch_parse_debug_rodata
+static inline bool arch_parse_debug_rodata(char *str) { return false; }
+#endif
+
 static int __init set_debug_rodata(char *str)
 {
-       if (strtobool(str, &rodata_enabled))
+       if (arch_parse_debug_rodata(str))
+               return 0;
+
+       if (str && !strcmp(str, "on"))
+               rodata_enabled = true;
+       else if (str && !strcmp(str, "off"))
+               rodata_enabled = false;
+       else
                pr_warn("Invalid option string for rodata: '%s'\n", str);
-       return 1;
+       return 0;
 }
-__setup("rodata=", set_debug_rodata);
+early_param("rodata", set_debug_rodata);
 #endif
 
 #ifdef CONFIG_STRICT_KERNEL_RWX
index e4e1dc0..5fc5d3e 100644 (file)
@@ -218,7 +218,7 @@ static int __io_sync_cancel(struct io_uring_task *tctx,
            (cd->flags & IORING_ASYNC_CANCEL_FD_FIXED)) {
                unsigned long file_ptr;
 
-               if (unlikely(fd > ctx->nr_user_files))
+               if (unlikely(fd >= ctx->nr_user_files))
                        return -EBADF;
                fd = array_index_nospec(fd, ctx->nr_user_files);
                file_ptr = io_fixed_file_slot(&ctx->file_table, fd)->file_ptr;
index ebfdb22..b9640ad 100644 (file)
@@ -1450,9 +1450,10 @@ int io_req_prep_async(struct io_kiocb *req)
                return 0;
        if (WARN_ON_ONCE(req_has_async_data(req)))
                return -EFAULT;
-       if (io_alloc_async_data(req))
-               return -EAGAIN;
-
+       if (!io_op_defs[req->opcode].manual_alloc) {
+               if (io_alloc_async_data(req))
+                       return -EAGAIN;
+       }
        return def->prep_async(req);
 }
 
@@ -1727,6 +1728,7 @@ static void io_queue_async(struct io_kiocb *req, int ret)
 
        switch (io_arm_poll_handler(req, 0)) {
        case IO_APOLL_READY:
+               io_kbuf_recycle(req, 0);
                io_req_task_queue(req);
                break;
        case IO_APOLL_ABORTED:
@@ -2639,7 +2641,6 @@ static __cold void io_ring_ctx_wait_and_kill(struct io_ring_ctx *ctx)
                io_unregister_personality(ctx, index);
        if (ctx->rings)
                io_poll_remove_all(ctx, NULL, true);
-       io_notif_unregister(ctx);
        mutex_unlock(&ctx->uring_lock);
 
        /* failed during ring init, it couldn't have issued any requests */
@@ -3838,15 +3839,6 @@ static int __io_uring_register(struct io_ring_ctx *ctx, unsigned opcode,
                        break;
                ret = io_register_file_alloc_range(ctx, arg);
                break;
-       case IORING_REGISTER_NOTIFIERS:
-               ret = io_notif_register(ctx, arg, nr_args);
-               break;
-       case IORING_UNREGISTER_NOTIFIERS:
-               ret = -EINVAL;
-               if (arg || nr_args)
-                       break;
-               ret = io_notif_unregister(ctx);
-               break;
        default:
                ret = -EINVAL;
                break;
@@ -3932,8 +3924,8 @@ static int __init io_uring_init(void)
        BUILD_BUG_SQE_ELEM(42, __u16,  personality);
        BUILD_BUG_SQE_ELEM(44, __s32,  splice_fd_in);
        BUILD_BUG_SQE_ELEM(44, __u32,  file_index);
-       BUILD_BUG_SQE_ELEM(44, __u16,  notification_idx);
-       BUILD_BUG_SQE_ELEM(46, __u16,  addr_len);
+       BUILD_BUG_SQE_ELEM(44, __u16,  addr_len);
+       BUILD_BUG_SQE_ELEM(46, __u16,  __pad3[0]);
        BUILD_BUG_SQE_ELEM(48, __u64,  addr3);
        BUILD_BUG_SQE_ELEM_SIZE(48, 0, cmd);
        BUILD_BUG_SQE_ELEM(56, __u64,  __pad2);
index d6af208..746fbf3 100644 (file)
@@ -91,9 +91,13 @@ static inline void io_kbuf_recycle(struct io_kiocb *req, unsigned issue_flags)
         * buffer data. However if that buffer is recycled the original request
         * data stored in addr is lost. Therefore forbid recycling for now.
         */
-       if (req->opcode == IORING_OP_READV)
+       if (req->opcode == IORING_OP_READV) {
+               if ((req->flags & REQ_F_BUFFER_RING) && req->buf_list) {
+                       req->buf_list->head++;
+                       req->buf_list = NULL;
+               }
                return;
-
+       }
        if (req->flags & REQ_F_BUFFER_SELECTED)
                io_kbuf_recycle_legacy(req, issue_flags);
        if (req->flags & REQ_F_BUFFER_RING)
index 976c4ba..4a7e5d0 100644 (file)
@@ -165,7 +165,8 @@ done:
                req_set_fail(req);
        io_req_set_res(req, ret, 0);
        /* put file to avoid an attempt to IOPOLL the req */
-       io_put_file(req->file);
+       if (!(req->flags & REQ_F_FIXED_FILE))
+               io_put_file(req->file);
        req->file = NULL;
        return IOU_OK;
 }
index 6d71748..60e392f 100644 (file)
@@ -65,12 +65,12 @@ struct io_sendzc {
        struct file                     *file;
        void __user                     *buf;
        size_t                          len;
-       u16                             slot_idx;
        unsigned                        msg_flags;
        unsigned                        flags;
        unsigned                        addr_len;
        void __user                     *addr;
        size_t                          done_io;
+       struct io_kiocb                 *notif;
 };
 
 #define IO_APOLL_MULTI_POLLED (REQ_F_APOLL_MULTISHOT | REQ_F_POLLED)
@@ -116,7 +116,7 @@ static void io_netmsg_recycle(struct io_kiocb *req, unsigned int issue_flags)
 {
        struct io_async_msghdr *hdr = req->async_data;
 
-       if (!hdr || issue_flags & IO_URING_F_UNLOCKED)
+       if (!req_has_async_data(req) || issue_flags & IO_URING_F_UNLOCKED)
                return;
 
        /* Let normal cleanup path reap it if we fail adding to the cache */
@@ -152,9 +152,9 @@ static int io_setup_async_msg(struct io_kiocb *req,
                              struct io_async_msghdr *kmsg,
                              unsigned int issue_flags)
 {
-       struct io_async_msghdr *async_msg = req->async_data;
+       struct io_async_msghdr *async_msg;
 
-       if (async_msg)
+       if (req_has_async_data(req))
                return -EAGAIN;
        async_msg = io_recvmsg_alloc_async(req, issue_flags);
        if (!async_msg) {
@@ -182,6 +182,37 @@ static int io_sendmsg_copy_hdr(struct io_kiocb *req,
                                        &iomsg->free_iov);
 }
 
+int io_sendzc_prep_async(struct io_kiocb *req)
+{
+       struct io_sendzc *zc = io_kiocb_to_cmd(req, struct io_sendzc);
+       struct io_async_msghdr *io;
+       int ret;
+
+       if (!zc->addr || req_has_async_data(req))
+               return 0;
+       if (io_alloc_async_data(req))
+               return -ENOMEM;
+
+       io = req->async_data;
+       ret = move_addr_to_kernel(zc->addr, zc->addr_len, &io->addr);
+       return ret;
+}
+
+static int io_setup_async_addr(struct io_kiocb *req,
+                             struct sockaddr_storage *addr,
+                             unsigned int issue_flags)
+{
+       struct io_async_msghdr *io;
+
+       if (!addr || req_has_async_data(req))
+               return -EAGAIN;
+       if (io_alloc_async_data(req))
+               return -ENOMEM;
+       io = req->async_data;
+       memcpy(&io->addr, addr, sizeof(io->addr));
+       return -EAGAIN;
+}
+
 int io_sendmsg_prep_async(struct io_kiocb *req)
 {
        int ret;
@@ -848,18 +879,39 @@ out_free:
        return ret;
 }
 
+void io_sendzc_cleanup(struct io_kiocb *req)
+{
+       struct io_sendzc *zc = io_kiocb_to_cmd(req, struct io_sendzc);
+
+       zc->notif->flags |= REQ_F_CQE_SKIP;
+       io_notif_flush(zc->notif);
+       zc->notif = NULL;
+}
+
 int io_sendzc_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
 {
        struct io_sendzc *zc = io_kiocb_to_cmd(req, struct io_sendzc);
        struct io_ring_ctx *ctx = req->ctx;
+       struct io_kiocb *notif;
 
-       if (READ_ONCE(sqe->__pad2[0]) || READ_ONCE(sqe->addr3))
+       if (READ_ONCE(sqe->__pad2[0]) || READ_ONCE(sqe->addr3) ||
+           READ_ONCE(sqe->__pad3[0]))
+               return -EINVAL;
+       /* we don't support IOSQE_CQE_SKIP_SUCCESS just yet */
+       if (req->flags & REQ_F_CQE_SKIP)
                return -EINVAL;
 
        zc->flags = READ_ONCE(sqe->ioprio);
        if (zc->flags & ~(IORING_RECVSEND_POLL_FIRST |
-                         IORING_RECVSEND_FIXED_BUF | IORING_RECVSEND_NOTIF_FLUSH))
+                         IORING_RECVSEND_FIXED_BUF))
                return -EINVAL;
+       notif = zc->notif = io_alloc_notif(ctx);
+       if (!notif)
+               return -ENOMEM;
+       notif->cqe.user_data = req->cqe.user_data;
+       notif->cqe.res = 0;
+       notif->cqe.flags = IORING_CQE_F_NOTIF;
+       req->flags |= REQ_F_NEED_CLEANUP;
        if (zc->flags & IORING_RECVSEND_FIXED_BUF) {
                unsigned idx = READ_ONCE(sqe->buf_index);
 
@@ -867,13 +919,12 @@ int io_sendzc_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
                        return -EFAULT;
                idx = array_index_nospec(idx, ctx->nr_user_bufs);
                req->imu = READ_ONCE(ctx->user_bufs[idx]);
-               io_req_set_rsrc_node(req, ctx, 0);
+               io_req_set_rsrc_node(notif, ctx, 0);
        }
 
        zc->buf = u64_to_user_ptr(READ_ONCE(sqe->addr));
        zc->len = READ_ONCE(sqe->len);
        zc->msg_flags = READ_ONCE(sqe->msg_flags) | MSG_NOSIGNAL;
-       zc->slot_idx = READ_ONCE(sqe->notification_idx);
        if (zc->msg_flags & MSG_DONTWAIT)
                req->flags |= REQ_F_NOWAIT;
 
@@ -925,7 +976,7 @@ static int io_sg_from_iter(struct sock *sk, struct sk_buff *skb,
        shinfo->nr_frags = frag;
        from->bvec += bi.bi_idx;
        from->nr_segs -= bi.bi_idx;
-       from->count = bi.bi_size;
+       from->count -= copied;
        from->iov_offset = bi.bi_bvec_done;
 
        skb->data_len += copied;
@@ -944,62 +995,57 @@ static int io_sg_from_iter(struct sock *sk, struct sk_buff *skb,
 
 int io_sendzc(struct io_kiocb *req, unsigned int issue_flags)
 {
-       struct sockaddr_storage address;
-       struct io_ring_ctx *ctx = req->ctx;
+       struct sockaddr_storage __address, *addr = NULL;
        struct io_sendzc *zc = io_kiocb_to_cmd(req, struct io_sendzc);
-       struct io_notif_slot *notif_slot;
-       struct io_kiocb *notif;
        struct msghdr msg;
        struct iovec iov;
        struct socket *sock;
-       unsigned msg_flags;
+       unsigned msg_flags, cflags;
        int ret, min_ret = 0;
 
-       if (!(req->flags & REQ_F_POLLED) &&
-           (zc->flags & IORING_RECVSEND_POLL_FIRST))
-               return -EAGAIN;
-
-       if (issue_flags & IO_URING_F_UNLOCKED)
-               return -EAGAIN;
        sock = sock_from_file(req->file);
        if (unlikely(!sock))
                return -ENOTSOCK;
 
-       notif_slot = io_get_notif_slot(ctx, zc->slot_idx);
-       if (!notif_slot)
-               return -EINVAL;
-       notif = io_get_notif(ctx, notif_slot);
-       if (!notif)
-               return -ENOMEM;
-
        msg.msg_name = NULL;
        msg.msg_control = NULL;
        msg.msg_controllen = 0;
        msg.msg_namelen = 0;
 
+       if (zc->addr) {
+               if (req_has_async_data(req)) {
+                       struct io_async_msghdr *io = req->async_data;
+
+                       msg.msg_name = addr = &io->addr;
+               } else {
+                       ret = move_addr_to_kernel(zc->addr, zc->addr_len, &__address);
+                       if (unlikely(ret < 0))
+                               return ret;
+                       msg.msg_name = (struct sockaddr *)&__address;
+                       addr = &__address;
+               }
+               msg.msg_namelen = zc->addr_len;
+       }
+
+       if (!(req->flags & REQ_F_POLLED) &&
+           (zc->flags & IORING_RECVSEND_POLL_FIRST))
+               return io_setup_async_addr(req, addr, issue_flags);
+
        if (zc->flags & IORING_RECVSEND_FIXED_BUF) {
                ret = io_import_fixed(WRITE, &msg.msg_iter, req->imu,
                                        (u64)(uintptr_t)zc->buf, zc->len);
                if (unlikely(ret))
-                               return ret;
+                       return ret;
        } else {
                ret = import_single_range(WRITE, zc->buf, zc->len, &iov,
                                          &msg.msg_iter);
                if (unlikely(ret))
                        return ret;
-               ret = io_notif_account_mem(notif, zc->len);
+               ret = io_notif_account_mem(zc->notif, zc->len);
                if (unlikely(ret))
                        return ret;
        }
 
-       if (zc->addr) {
-               ret = move_addr_to_kernel(zc->addr, zc->addr_len, &address);
-               if (unlikely(ret < 0))
-                       return ret;
-               msg.msg_name = (struct sockaddr *)&address;
-               msg.msg_namelen = zc->addr_len;
-       }
-
        msg_flags = zc->msg_flags | MSG_ZEROCOPY;
        if (issue_flags & IO_URING_F_NONBLOCK)
                msg_flags |= MSG_DONTWAIT;
@@ -1007,31 +1053,37 @@ int io_sendzc(struct io_kiocb *req, unsigned int issue_flags)
                min_ret = iov_iter_count(&msg.msg_iter);
 
        msg.msg_flags = msg_flags;
-       msg.msg_ubuf = &io_notif_to_data(notif)->uarg;
+       msg.msg_ubuf = &io_notif_to_data(zc->notif)->uarg;
        msg.sg_from_iter = io_sg_from_iter;
        ret = sock_sendmsg(sock, &msg);
 
        if (unlikely(ret < min_ret)) {
                if (ret == -EAGAIN && (issue_flags & IO_URING_F_NONBLOCK))
-                       return -EAGAIN;
+                       return io_setup_async_addr(req, addr, issue_flags);
+
                if (ret > 0 && io_net_retry(sock, msg.msg_flags)) {
                        zc->len -= ret;
                        zc->buf += ret;
                        zc->done_io += ret;
                        req->flags |= REQ_F_PARTIAL_IO;
-                       return -EAGAIN;
+                       return io_setup_async_addr(req, addr, issue_flags);
                }
+               if (ret < 0 && !zc->done_io)
+                       zc->notif->flags |= REQ_F_CQE_SKIP;
                if (ret == -ERESTARTSYS)
                        ret = -EINTR;
-       } else if (zc->flags & IORING_RECVSEND_NOTIF_FLUSH) {
-               io_notif_slot_flush_submit(notif_slot, 0);
+               req_set_fail(req);
        }
 
        if (ret >= 0)
                ret += zc->done_io;
        else if (zc->done_io)
                ret = zc->done_io;
-       io_req_set_res(req, ret, 0);
+
+       io_notif_flush(zc->notif);
+       req->flags &= ~REQ_F_NEED_CLEANUP;
+       cflags = ret >= 0 ? IORING_CQE_F_MORE : 0;
+       io_req_set_res(req, ret, cflags);
        return IOU_OK;
 }
 
index 7c438d3..d744a0a 100644 (file)
@@ -31,6 +31,7 @@ struct io_async_connect {
 int io_shutdown_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
 int io_shutdown(struct io_kiocb *req, unsigned int issue_flags);
 
+int io_sendzc_prep_async(struct io_kiocb *req);
 int io_sendmsg_prep_async(struct io_kiocb *req);
 void io_sendmsg_recvmsg_cleanup(struct io_kiocb *req);
 int io_sendmsg_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
@@ -54,6 +55,7 @@ int io_connect(struct io_kiocb *req, unsigned int issue_flags);
 
 int io_sendzc(struct io_kiocb *req, unsigned int issue_flags);
 int io_sendzc_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+void io_sendzc_cleanup(struct io_kiocb *req);
 
 void io_netmsg_cache_free(struct io_cache_entry *entry);
 #else
index 977736e..e37c656 100644 (file)
@@ -21,14 +21,6 @@ static void __io_notif_complete_tw(struct io_kiocb *notif, bool *locked)
        io_req_task_complete(notif, locked);
 }
 
-static inline void io_notif_complete(struct io_kiocb *notif)
-       __must_hold(&notif->ctx->uring_lock)
-{
-       bool locked = true;
-
-       __io_notif_complete_tw(notif, &locked);
-}
-
 static void io_uring_tx_zerocopy_callback(struct sk_buff *skb,
                                          struct ubuf_info *uarg,
                                          bool success)
@@ -42,8 +34,7 @@ static void io_uring_tx_zerocopy_callback(struct sk_buff *skb,
        }
 }
 
-struct io_kiocb *io_alloc_notif(struct io_ring_ctx *ctx,
-                               struct io_notif_slot *slot)
+struct io_kiocb *io_alloc_notif(struct io_ring_ctx *ctx)
        __must_hold(&ctx->uring_lock)
 {
        struct io_kiocb *notif;
@@ -59,99 +50,23 @@ struct io_kiocb *io_alloc_notif(struct io_ring_ctx *ctx,
        io_get_task_refs(1);
        notif->rsrc_node = NULL;
        io_req_set_rsrc_node(notif, ctx, 0);
-       notif->cqe.user_data = slot->tag;
-       notif->cqe.flags = slot->seq++;
-       notif->cqe.res = 0;
 
        nd = io_notif_to_data(notif);
        nd->account_pages = 0;
        nd->uarg.flags = SKBFL_ZEROCOPY_FRAG | SKBFL_DONT_ORPHAN;
        nd->uarg.callback = io_uring_tx_zerocopy_callback;
-       /* master ref owned by io_notif_slot, will be dropped on flush */
        refcount_set(&nd->uarg.refcnt, 1);
        return notif;
 }
 
-void io_notif_slot_flush(struct io_notif_slot *slot)
-       __must_hold(&ctx->uring_lock)
+void io_notif_flush(struct io_kiocb *notif)
+       __must_hold(&slot->notif->ctx->uring_lock)
 {
-       struct io_kiocb *notif = slot->notif;
        struct io_notif_data *nd = io_notif_to_data(notif);
 
-       slot->notif = NULL;
-
        /* drop slot's master ref */
-       if (refcount_dec_and_test(&nd->uarg.refcnt))
-               io_notif_complete(notif);
-}
-
-__cold int io_notif_unregister(struct io_ring_ctx *ctx)
-       __must_hold(&ctx->uring_lock)
-{
-       int i;
-
-       if (!ctx->notif_slots)
-               return -ENXIO;
-
-       for (i = 0; i < ctx->nr_notif_slots; i++) {
-               struct io_notif_slot *slot = &ctx->notif_slots[i];
-               struct io_kiocb *notif = slot->notif;
-               struct io_notif_data *nd;
-
-               if (!notif)
-                       continue;
-               nd = io_notif_to_data(notif);
-               slot->notif = NULL;
-               if (!refcount_dec_and_test(&nd->uarg.refcnt))
-                       continue;
+       if (refcount_dec_and_test(&nd->uarg.refcnt)) {
                notif->io_task_work.func = __io_notif_complete_tw;
                io_req_task_work_add(notif);
        }
-
-       kvfree(ctx->notif_slots);
-       ctx->notif_slots = NULL;
-       ctx->nr_notif_slots = 0;
-       return 0;
-}
-
-__cold int io_notif_register(struct io_ring_ctx *ctx,
-                            void __user *arg, unsigned int size)
-       __must_hold(&ctx->uring_lock)
-{
-       struct io_uring_notification_slot __user *slots;
-       struct io_uring_notification_slot slot;
-       struct io_uring_notification_register reg;
-       unsigned i;
-
-       if (ctx->nr_notif_slots)
-               return -EBUSY;
-       if (size != sizeof(reg))
-               return -EINVAL;
-       if (copy_from_user(&reg, arg, sizeof(reg)))
-               return -EFAULT;
-       if (!reg.nr_slots || reg.nr_slots > IORING_MAX_NOTIF_SLOTS)
-               return -EINVAL;
-       if (reg.resv || reg.resv2 || reg.resv3)
-               return -EINVAL;
-
-       slots = u64_to_user_ptr(reg.data);
-       ctx->notif_slots = kvcalloc(reg.nr_slots, sizeof(ctx->notif_slots[0]),
-                               GFP_KERNEL_ACCOUNT);
-       if (!ctx->notif_slots)
-               return -ENOMEM;
-
-       for (i = 0; i < reg.nr_slots; i++, ctx->nr_notif_slots++) {
-               struct io_notif_slot *notif_slot = &ctx->notif_slots[i];
-
-               if (copy_from_user(&slot, &slots[i], sizeof(slot))) {
-                       io_notif_unregister(ctx);
-                       return -EFAULT;
-               }
-               if (slot.resv[0] | slot.resv[1] | slot.resv[2]) {
-                       io_notif_unregister(ctx);
-                       return -EINVAL;
-               }
-               notif_slot->tag = slot.tag;
-       }
-       return 0;
 }
index 65f0b42..5b4d710 100644 (file)
@@ -8,7 +8,6 @@
 #include "rsrc.h"
 
 #define IO_NOTIF_SPLICE_BATCH  32
-#define IORING_MAX_NOTIF_SLOTS (1U << 10)
 
 struct io_notif_data {
        struct file             *file;
@@ -16,63 +15,14 @@ struct io_notif_data {
        unsigned long           account_pages;
 };
 
-struct io_notif_slot {
-       /*
-        * Current/active notifier. A slot holds only one active notifier at a
-        * time and keeps one reference to it. Flush releases the reference and
-        * lazily replaces it with a new notifier.
-        */
-       struct io_kiocb         *notif;
-
-       /*
-        * Default ->user_data for this slot notifiers CQEs
-        */
-       u64                     tag;
-       /*
-        * Notifiers of a slot live in generations, we create a new notifier
-        * only after flushing the previous one. Track the sequential number
-        * for all notifiers and copy it into notifiers's cqe->cflags
-        */
-       u32                     seq;
-};
-
-int io_notif_register(struct io_ring_ctx *ctx,
-                     void __user *arg, unsigned int size);
-int io_notif_unregister(struct io_ring_ctx *ctx);
-
-void io_notif_slot_flush(struct io_notif_slot *slot);
-struct io_kiocb *io_alloc_notif(struct io_ring_ctx *ctx,
-                               struct io_notif_slot *slot);
+void io_notif_flush(struct io_kiocb *notif);
+struct io_kiocb *io_alloc_notif(struct io_ring_ctx *ctx);
 
 static inline struct io_notif_data *io_notif_to_data(struct io_kiocb *notif)
 {
        return io_kiocb_to_cmd(notif, struct io_notif_data);
 }
 
-static inline struct io_kiocb *io_get_notif(struct io_ring_ctx *ctx,
-                                           struct io_notif_slot *slot)
-{
-       if (!slot->notif)
-               slot->notif = io_alloc_notif(ctx, slot);
-       return slot->notif;
-}
-
-static inline struct io_notif_slot *io_get_notif_slot(struct io_ring_ctx *ctx,
-                                                     unsigned idx)
-       __must_hold(&ctx->uring_lock)
-{
-       if (idx >= ctx->nr_notif_slots)
-               return NULL;
-       idx = array_index_nospec(idx, ctx->nr_notif_slots);
-       return &ctx->notif_slots[idx];
-}
-
-static inline void io_notif_slot_flush_submit(struct io_notif_slot *slot,
-                                             unsigned int issue_flags)
-{
-       io_notif_slot_flush(slot);
-}
-
 static inline int io_notif_account_mem(struct io_kiocb *notif, unsigned len)
 {
        struct io_ring_ctx *ctx = notif->ctx;
index 72dd2b2..c4dddd0 100644 (file)
@@ -246,13 +246,12 @@ const struct io_op_def io_op_defs[] = {
                .prep                   = io_close_prep,
                .issue                  = io_close,
        },
-       [IORING_OP_RSRC_UPDATE] = {
+       [IORING_OP_FILES_UPDATE] = {
                .audit_skip             = 1,
                .iopoll                 = 1,
-               .name                   = "RSRC_UPDATE",
-               .prep                   = io_rsrc_update_prep,
-               .issue                  = io_rsrc_update,
-               .ioprio                 = 1,
+               .name                   = "FILES_UPDATE",
+               .prep                   = io_files_update_prep,
+               .issue                  = io_files_update,
        },
        [IORING_OP_STATX] = {
                .audit_skip             = 1,
@@ -471,20 +470,23 @@ const struct io_op_def io_op_defs[] = {
                .issue                  = io_uring_cmd,
                .prep_async             = io_uring_cmd_prep_async,
        },
-       [IORING_OP_SENDZC_NOTIF] = {
-               .name                   = "SENDZC_NOTIF",
+       [IORING_OP_SEND_ZC] = {
+               .name                   = "SEND_ZC",
                .needs_file             = 1,
                .unbound_nonreg_file    = 1,
                .pollout                = 1,
                .audit_skip             = 1,
                .ioprio                 = 1,
+               .manual_alloc           = 1,
 #if defined(CONFIG_NET)
+               .async_size             = sizeof(struct io_async_msghdr),
                .prep                   = io_sendzc_prep,
                .issue                  = io_sendzc,
+               .prep_async             = io_sendzc_prep_async,
+               .cleanup                = io_sendzc_cleanup,
 #else
                .prep                   = io_eopnotsupp_prep,
 #endif
-
        },
 };
 
index ece8ed4..763c6e5 100644 (file)
@@ -25,6 +25,8 @@ struct io_op_def {
        unsigned                ioprio : 1;
        /* supports iopoll */
        unsigned                iopoll : 1;
+       /* opcode specific path will handle ->async_data allocation if needed */
+       unsigned                manual_alloc : 1;
        /* size of async data needed, if any */
        unsigned short          async_size;
 
index 71359a4..cf32721 100644 (file)
 #include "io_uring.h"
 #include "openclose.h"
 #include "rsrc.h"
-#include "notif.h"
 
 struct io_rsrc_update {
        struct file                     *file;
        u64                             arg;
        u32                             nr_args;
        u32                             offset;
-       int                             type;
 };
 
 static int io_sqe_buffer_register(struct io_ring_ctx *ctx, struct iovec *iov,
@@ -655,7 +653,7 @@ __cold int io_register_rsrc(struct io_ring_ctx *ctx, void __user *arg,
        return -EINVAL;
 }
 
-int io_rsrc_update_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+int io_files_update_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
 {
        struct io_rsrc_update *up = io_kiocb_to_cmd(req, struct io_rsrc_update);
 
@@ -669,7 +667,6 @@ int io_rsrc_update_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
        if (!up->nr_args)
                return -EINVAL;
        up->arg = READ_ONCE(sqe->addr);
-       up->type = READ_ONCE(sqe->ioprio);
        return 0;
 }
 
@@ -712,7 +709,7 @@ static int io_files_update_with_index_alloc(struct io_kiocb *req,
        return ret;
 }
 
-static int io_files_update(struct io_kiocb *req, unsigned int issue_flags)
+int io_files_update(struct io_kiocb *req, unsigned int issue_flags)
 {
        struct io_rsrc_update *up = io_kiocb_to_cmd(req, struct io_rsrc_update);
        struct io_ring_ctx *ctx = req->ctx;
@@ -741,54 +738,6 @@ static int io_files_update(struct io_kiocb *req, unsigned int issue_flags)
        return IOU_OK;
 }
 
-static int io_notif_update(struct io_kiocb *req, unsigned int issue_flags)
-{
-       struct io_rsrc_update *up = io_kiocb_to_cmd(req, struct io_rsrc_update);
-       struct io_ring_ctx *ctx = req->ctx;
-       unsigned len = up->nr_args;
-       unsigned idx_end, idx = up->offset;
-       int ret = 0;
-
-       io_ring_submit_lock(ctx, issue_flags);
-       if (unlikely(check_add_overflow(idx, len, &idx_end))) {
-               ret = -EOVERFLOW;
-               goto out;
-       }
-       if (unlikely(idx_end > ctx->nr_notif_slots)) {
-               ret = -EINVAL;
-               goto out;
-       }
-
-       for (; idx < idx_end; idx++) {
-               struct io_notif_slot *slot = &ctx->notif_slots[idx];
-
-               if (!slot->notif)
-                       continue;
-               if (up->arg)
-                       slot->tag = up->arg;
-               io_notif_slot_flush_submit(slot, issue_flags);
-       }
-out:
-       io_ring_submit_unlock(ctx, issue_flags);
-       if (ret < 0)
-               req_set_fail(req);
-       io_req_set_res(req, ret, 0);
-       return IOU_OK;
-}
-
-int io_rsrc_update(struct io_kiocb *req, unsigned int issue_flags)
-{
-       struct io_rsrc_update *up = io_kiocb_to_cmd(req, struct io_rsrc_update);
-
-       switch (up->type) {
-       case IORING_RSRC_UPDATE_FILES:
-               return io_files_update(req, issue_flags);
-       case IORING_RSRC_UPDATE_NOTIF:
-               return io_notif_update(req, issue_flags);
-       }
-       return -EINVAL;
-}
-
 int io_queue_rsrc_removal(struct io_rsrc_data *data, unsigned idx,
                          struct io_rsrc_node *node, void *rsrc)
 {
index f3a9a17..9bce156 100644 (file)
@@ -167,8 +167,8 @@ static inline u64 *io_get_tag_slot(struct io_rsrc_data *data, unsigned int idx)
        return &data->tags[table_idx][off];
 }
 
-int io_rsrc_update(struct io_kiocb *req, unsigned int issue_flags);
-int io_rsrc_update_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+int io_files_update(struct io_kiocb *req, unsigned int issue_flags);
+int io_files_update_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
 
 int __io_account_mem(struct user_struct *user, unsigned long nr_pages);
 
index 1babd77..76ebcfe 100644 (file)
@@ -206,6 +206,20 @@ static bool __io_complete_rw_common(struct io_kiocb *req, long res)
        return false;
 }
 
+static inline int io_fixup_rw_res(struct io_kiocb *req, long res)
+{
+       struct io_async_rw *io = req->async_data;
+
+       /* add previously done IO, if any */
+       if (req_has_async_data(req) && io->bytes_done > 0) {
+               if (res < 0)
+                       res = io->bytes_done;
+               else
+                       res += io->bytes_done;
+       }
+       return res;
+}
+
 static void io_complete_rw(struct kiocb *kiocb, long res)
 {
        struct io_rw *rw = container_of(kiocb, struct io_rw, kiocb);
@@ -213,7 +227,7 @@ static void io_complete_rw(struct kiocb *kiocb, long res)
 
        if (__io_complete_rw_common(req, res))
                return;
-       io_req_set_res(req, res, 0);
+       io_req_set_res(req, io_fixup_rw_res(req, res), 0);
        req->io_task_work.func = io_req_task_complete;
        io_req_task_work_add(req);
 }
@@ -240,22 +254,14 @@ static void io_complete_rw_iopoll(struct kiocb *kiocb, long res)
 static int kiocb_done(struct io_kiocb *req, ssize_t ret,
                       unsigned int issue_flags)
 {
-       struct io_async_rw *io = req->async_data;
        struct io_rw *rw = io_kiocb_to_cmd(req, struct io_rw);
-
-       /* add previously done IO, if any */
-       if (req_has_async_data(req) && io->bytes_done > 0) {
-               if (ret < 0)
-                       ret = io->bytes_done;
-               else
-                       ret += io->bytes_done;
-       }
+       unsigned final_ret = io_fixup_rw_res(req, ret);
 
        if (req->flags & REQ_F_CUR_POS)
                req->file->f_pos = rw->kiocb.ki_pos;
        if (ret >= 0 && (rw->kiocb.ki_complete == io_complete_rw)) {
                if (!__io_complete_rw_common(req, ret)) {
-                       io_req_set_res(req, req->cqe.res,
+                       io_req_set_res(req, final_ret,
                                       io_put_kbuf(req, issue_flags));
                        return IOU_OK;
                }
@@ -268,7 +274,7 @@ static int kiocb_done(struct io_kiocb *req, ssize_t ret,
                if (io_resubmit_prep(req))
                        io_req_task_queue_reissue(req);
                else
-                       io_req_task_queue_fail(req, ret);
+                       io_req_task_queue_fail(req, final_ret);
        }
        return IOU_ISSUE_SKIP_COMPLETE;
 }
index 8e0cc2d..e78b6f9 100644 (file)
@@ -3,6 +3,7 @@
 #include <linux/errno.h>
 #include <linux/file.h>
 #include <linux/io_uring.h>
+#include <linux/security.h>
 
 #include <uapi/linux/io_uring.h>
 
@@ -88,6 +89,10 @@ int io_uring_cmd(struct io_kiocb *req, unsigned int issue_flags)
        if (!req->file->f_op->uring_cmd)
                return -EOPNOTSUPP;
 
+       ret = security_uring_cmd(ioucmd);
+       if (ret)
+               return ret;
+
        if (ctx->flags & IORING_SETUP_SQE128)
                issue_flags |= IO_URING_F_SQE128;
        if (ctx->flags & IORING_SETUP_CQE32)
@@ -112,7 +117,7 @@ int io_uring_cmd(struct io_kiocb *req, unsigned int issue_flags)
                if (ret < 0)
                        req_set_fail(req);
                io_req_set_res(req, ret, 0);
-               return IOU_OK;
+               return ret;
        }
 
        return IOU_ISSUE_SKIP_COMPLETE;
index 6432a37..c565fbf 100644 (file)
@@ -102,6 +102,7 @@ struct audit_fsnotify_mark *audit_alloc_mark(struct audit_krule *krule, char *pa
 
        ret = fsnotify_add_inode_mark(&audit_mark->mark, inode, 0);
        if (ret < 0) {
+               audit_mark->path = NULL;
                fsnotify_put_mark(&audit_mark->mark);
                audit_mark = ERR_PTR(ret);
        }
index dd8d9ab..79a5da1 100644 (file)
@@ -1940,6 +1940,7 @@ void __audit_uring_exit(int success, long code)
                goto out;
        }
 
+       audit_return_fixup(ctx, success, code);
        if (ctx->context == AUDIT_CTX_SYSCALL) {
                /*
                 * NOTE: See the note in __audit_uring_entry() about the case
@@ -1981,7 +1982,6 @@ void __audit_uring_exit(int success, long code)
        audit_filter_inodes(current, ctx);
        if (ctx->current_state != AUDIT_STATE_RECORD)
                goto out;
-       audit_return_fixup(ctx, success, code);
        audit_log_exit();
 
 out:
@@ -2065,13 +2065,13 @@ void __audit_syscall_exit(int success, long return_code)
        if (!list_empty(&context->killed_trees))
                audit_kill_trees(context);
 
+       audit_return_fixup(context, success, return_code);
        /* run through both filters to ensure we set the filterkey properly */
        audit_filter_syscall(current, context);
        audit_filter_inodes(current, context);
        if (context->current_state < AUDIT_STATE_RECORD)
                goto out;
 
-       audit_return_fixup(context, success, return_code);
        audit_log_exit();
 
 out:
index 59b7eb6..4a400cd 100644 (file)
@@ -921,8 +921,10 @@ static void purge_effective_progs(struct cgroup *cgrp, struct bpf_prog *prog,
                                pos++;
                        }
                }
+
+               /* no link or prog match, skip the cgroup of this layer */
+               continue;
 found:
-               BUG_ON(!cg);
                progs = rcu_dereference_protected(
                                desc->bpf.effective[atype],
                                lockdep_is_held(&cgroup_mutex));
index c1e10d0..3d9eb3a 100644 (file)
@@ -971,7 +971,7 @@ pure_initcall(bpf_jit_charge_init);
 
 int bpf_jit_charge_modmem(u32 size)
 {
-       if (atomic_long_add_return(size, &bpf_jit_current) > bpf_jit_limit) {
+       if (atomic_long_add_return(size, &bpf_jit_current) > READ_ONCE(bpf_jit_limit)) {
                if (!bpf_capable()) {
                        atomic_long_sub(size, &bpf_jit_current);
                        return -EPERM;
index 85fa9db..82c6161 100644 (file)
@@ -24,7 +24,7 @@ void bpf_sk_reuseport_detach(struct sock *sk)
        struct sock __rcu **socks;
 
        write_lock_bh(&sk->sk_callback_lock);
-       socks = __rcu_dereference_sk_user_data_with_flags(sk, SK_USER_DATA_BPF);
+       socks = __locked_read_sk_user_data_with_flags(sk, SK_USER_DATA_BPF);
        if (socks) {
                WRITE_ONCE(sk->sk_user_data, NULL);
                /*
index a4d40d9..2776062 100644 (file)
@@ -5197,7 +5197,7 @@ syscall_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
 {
        switch (func_id) {
        case BPF_FUNC_sys_bpf:
-               return &bpf_sys_bpf_proto;
+               return !perfmon_capable() ? NULL : &bpf_sys_bpf_proto;
        case BPF_FUNC_btf_find_by_name_kind:
                return &bpf_btf_find_by_name_kind_proto;
        case BPF_FUNC_sys_close:
index 096fdac..3eadb14 100644 (file)
@@ -6066,6 +6066,9 @@ skip_type_check:
                        return -EACCES;
                }
                meta->mem_size = reg->var_off.value;
+               err = mark_chain_precision(env, regno);
+               if (err)
+                       return err;
                break;
        case ARG_PTR_TO_INT:
        case ARG_PTR_TO_LONG:
@@ -7030,8 +7033,7 @@ record_func_key(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta,
        struct bpf_insn_aux_data *aux = &env->insn_aux_data[insn_idx];
        struct bpf_reg_state *regs = cur_regs(env), *reg;
        struct bpf_map *map = meta->map_ptr;
-       struct tnum range;
-       u64 val;
+       u64 val, max;
        int err;
 
        if (func_id != BPF_FUNC_tail_call)
@@ -7041,10 +7043,11 @@ record_func_key(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta,
                return -EINVAL;
        }
 
-       range = tnum_range(0, map->max_entries - 1);
        reg = &regs[BPF_REG_3];
+       val = reg->var_off.value;
+       max = map->max_entries;
 
-       if (!register_is_const(reg) || !tnum_in(range, reg->var_off)) {
+       if (!(register_is_const(reg) && val < max)) {
                bpf_map_key_store(aux, BPF_MAP_KEY_POISON);
                return 0;
        }
@@ -7052,8 +7055,6 @@ record_func_key(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta,
        err = mark_chain_precision(env, BPF_REG_3);
        if (err)
                return err;
-
-       val = reg->var_off.value;
        if (bpf_map_key_unseen(aux))
                bpf_map_key_store(aux, val);
        else if (!bpf_map_key_poisoned(aux) &&
index 2ade21b..ff6a809 100644 (file)
@@ -59,6 +59,7 @@ int cgroup_attach_task_all(struct task_struct *from, struct task_struct *tsk)
        int retval = 0;
 
        mutex_lock(&cgroup_mutex);
+       cpus_read_lock();
        percpu_down_write(&cgroup_threadgroup_rwsem);
        for_each_root(root) {
                struct cgroup *from_cgrp;
@@ -72,6 +73,7 @@ int cgroup_attach_task_all(struct task_struct *from, struct task_struct *tsk)
                        break;
        }
        percpu_up_write(&cgroup_threadgroup_rwsem);
+       cpus_read_unlock();
        mutex_unlock(&cgroup_mutex);
 
        return retval;
index ffaccd6..e4bb5d5 100644 (file)
@@ -1820,6 +1820,7 @@ int rebind_subsystems(struct cgroup_root *dst_root, u16 ss_mask)
 
                if (ss->css_rstat_flush) {
                        list_del_rcu(&css->rstat_css_node);
+                       synchronize_rcu();
                        list_add_rcu(&css->rstat_css_node,
                                     &dcgrp->rstat_css_list);
                }
@@ -2370,6 +2371,47 @@ int task_cgroup_path(struct task_struct *task, char *buf, size_t buflen)
 EXPORT_SYMBOL_GPL(task_cgroup_path);
 
 /**
+ * cgroup_attach_lock - Lock for ->attach()
+ * @lock_threadgroup: whether to down_write cgroup_threadgroup_rwsem
+ *
+ * cgroup migration sometimes needs to stabilize threadgroups against forks and
+ * exits by write-locking cgroup_threadgroup_rwsem. However, some ->attach()
+ * implementations (e.g. cpuset), also need to disable CPU hotplug.
+ * Unfortunately, letting ->attach() operations acquire cpus_read_lock() can
+ * lead to deadlocks.
+ *
+ * Bringing up a CPU may involve creating and destroying tasks which requires
+ * read-locking threadgroup_rwsem, so threadgroup_rwsem nests inside
+ * cpus_read_lock(). If we call an ->attach() which acquires the cpus lock while
+ * write-locking threadgroup_rwsem, the locking order is reversed and we end up
+ * waiting for an on-going CPU hotplug operation which in turn is waiting for
+ * the threadgroup_rwsem to be released to create new tasks. For more details:
+ *
+ *   http://lkml.kernel.org/r/20220711174629.uehfmqegcwn2lqzu@wubuntu
+ *
+ * Resolve the situation by always acquiring cpus_read_lock() before optionally
+ * write-locking cgroup_threadgroup_rwsem. This allows ->attach() to assume that
+ * CPU hotplug is disabled on entry.
+ */
+static void cgroup_attach_lock(bool lock_threadgroup)
+{
+       cpus_read_lock();
+       if (lock_threadgroup)
+               percpu_down_write(&cgroup_threadgroup_rwsem);
+}
+
+/**
+ * cgroup_attach_unlock - Undo cgroup_attach_lock()
+ * @lock_threadgroup: whether to up_write cgroup_threadgroup_rwsem
+ */
+static void cgroup_attach_unlock(bool lock_threadgroup)
+{
+       if (lock_threadgroup)
+               percpu_up_write(&cgroup_threadgroup_rwsem);
+       cpus_read_unlock();
+}
+
+/**
  * cgroup_migrate_add_task - add a migration target task to a migration context
  * @task: target task
  * @mgctx: target migration context
@@ -2841,8 +2883,7 @@ int cgroup_attach_task(struct cgroup *dst_cgrp, struct task_struct *leader,
 }
 
 struct task_struct *cgroup_procs_write_start(char *buf, bool threadgroup,
-                                            bool *locked)
-       __acquires(&cgroup_threadgroup_rwsem)
+                                            bool *threadgroup_locked)
 {
        struct task_struct *tsk;
        pid_t pid;
@@ -2859,12 +2900,8 @@ struct task_struct *cgroup_procs_write_start(char *buf, bool threadgroup,
         * Therefore, we can skip the global lock.
         */
        lockdep_assert_held(&cgroup_mutex);
-       if (pid || threadgroup) {
-               percpu_down_write(&cgroup_threadgroup_rwsem);
-               *locked = true;
-       } else {
-               *locked = false;
-       }
+       *threadgroup_locked = pid || threadgroup;
+       cgroup_attach_lock(*threadgroup_locked);
 
        rcu_read_lock();
        if (pid) {
@@ -2895,17 +2932,14 @@ struct task_struct *cgroup_procs_write_start(char *buf, bool threadgroup,
        goto out_unlock_rcu;
 
 out_unlock_threadgroup:
-       if (*locked) {
-               percpu_up_write(&cgroup_threadgroup_rwsem);
-               *locked = false;
-       }
+       cgroup_attach_unlock(*threadgroup_locked);
+       *threadgroup_locked = false;
 out_unlock_rcu:
        rcu_read_unlock();
        return tsk;
 }
 
-void cgroup_procs_write_finish(struct task_struct *task, bool locked)
-       __releases(&cgroup_threadgroup_rwsem)
+void cgroup_procs_write_finish(struct task_struct *task, bool threadgroup_locked)
 {
        struct cgroup_subsys *ss;
        int ssid;
@@ -2913,8 +2947,8 @@ void cgroup_procs_write_finish(struct task_struct *task, bool locked)
        /* release reference from cgroup_procs_write_start() */
        put_task_struct(task);
 
-       if (locked)
-               percpu_up_write(&cgroup_threadgroup_rwsem);
+       cgroup_attach_unlock(threadgroup_locked);
+
        for_each_subsys(ss, ssid)
                if (ss->post_attach)
                        ss->post_attach();
@@ -3000,8 +3034,7 @@ static int cgroup_update_dfl_csses(struct cgroup *cgrp)
         * write-locking can be skipped safely.
         */
        has_tasks = !list_empty(&mgctx.preloaded_src_csets);
-       if (has_tasks)
-               percpu_down_write(&cgroup_threadgroup_rwsem);
+       cgroup_attach_lock(has_tasks);
 
        /* NULL dst indicates self on default hierarchy */
        ret = cgroup_migrate_prepare_dst(&mgctx);
@@ -3022,8 +3055,7 @@ static int cgroup_update_dfl_csses(struct cgroup *cgrp)
        ret = cgroup_migrate_execute(&mgctx);
 out_finish:
        cgroup_migrate_finish(&mgctx);
-       if (has_tasks)
-               percpu_up_write(&cgroup_threadgroup_rwsem);
+       cgroup_attach_unlock(has_tasks);
        return ret;
 }
 
@@ -3698,7 +3730,7 @@ static ssize_t cgroup_pressure_write(struct kernfs_open_file *of, char *buf,
        }
 
        psi = cgroup_ino(cgrp) == 1 ? &psi_system : cgrp->psi;
-       new = psi_trigger_create(psi, buf, nbytes, res);
+       new = psi_trigger_create(psi, buf, res);
        if (IS_ERR(new)) {
                cgroup_put(cgrp);
                return PTR_ERR(new);
@@ -4971,13 +5003,13 @@ static ssize_t __cgroup_procs_write(struct kernfs_open_file *of, char *buf,
        struct task_struct *task;
        const struct cred *saved_cred;
        ssize_t ret;
-       bool locked;
+       bool threadgroup_locked;
 
        dst_cgrp = cgroup_kn_lock_live(of->kn, false);
        if (!dst_cgrp)
                return -ENODEV;
 
-       task = cgroup_procs_write_start(buf, threadgroup, &locked);
+       task = cgroup_procs_write_start(buf, threadgroup, &threadgroup_locked);
        ret = PTR_ERR_OR_ZERO(task);
        if (ret)
                goto out_unlock;
@@ -5003,7 +5035,7 @@ static ssize_t __cgroup_procs_write(struct kernfs_open_file *of, char *buf,
        ret = cgroup_attach_task(dst_cgrp, task, threadgroup);
 
 out_finish:
-       cgroup_procs_write_finish(task, locked);
+       cgroup_procs_write_finish(task, threadgroup_locked);
 out_unlock:
        cgroup_kn_unlock(of->kn);
 
index 58aadfd..1f3a552 100644 (file)
@@ -2289,7 +2289,7 @@ static void cpuset_attach(struct cgroup_taskset *tset)
        cgroup_taskset_first(tset, &css);
        cs = css_cs(css);
 
-       cpus_read_lock();
+       lockdep_assert_cpus_held();     /* see cgroup_attach_lock() */
        percpu_down_write(&cpuset_rwsem);
 
        guarantee_online_mems(cs, &cpuset_attach_nodemask_to);
@@ -2343,7 +2343,6 @@ static void cpuset_attach(struct cgroup_taskset *tset)
                wake_up(&cpuset_attach_wq);
 
        percpu_up_write(&cpuset_rwsem);
-       cpus_read_unlock();
 }
 
 /* The various types of files and directories in a cpuset file system */
index 07b26df..a0eb4d5 100644 (file)
@@ -494,6 +494,7 @@ static int __init crash_save_vmcoreinfo_init(void)
 
 #ifdef CONFIG_KALLSYMS
        VMCOREINFO_SYMBOL(kallsyms_names);
+       VMCOREINFO_SYMBOL(kallsyms_num_syms);
        VMCOREINFO_SYMBOL(kallsyms_token_table);
        VMCOREINFO_SYMBOL(kallsyms_token_index);
 #ifdef CONFIG_KALLSYMS_BASE_RELATIVE
index 2caafd1..18c93c2 100644 (file)
@@ -350,11 +350,10 @@ static struct dma_debug_entry *bucket_find_contain(struct hash_bucket **bucket,
                                                   unsigned long *flags)
 {
 
-       unsigned int max_range = dma_get_max_seg_size(ref->dev);
        struct dma_debug_entry *entry, index = *ref;
-       unsigned int range = 0;
+       int limit = min(HASH_SIZE, (index.dev_addr >> HASH_FN_SHIFT) + 1);
 
-       while (range <= max_range) {
+       for (int i = 0; i < limit; i++) {
                entry = __hash_bucket_find(*bucket, ref, containing_match);
 
                if (entry)
@@ -364,7 +363,6 @@ static struct dma_debug_entry *bucket_find_contain(struct hash_bucket **bucket,
                 * Nothing found, go back a hash bucket
                 */
                put_hash_bucket(*bucket, *flags);
-               range          += (1 << HASH_FN_SHIFT);
                index.dev_addr -= (1 << HASH_FN_SHIFT);
                *bucket = get_hash_bucket(&index, flags);
        }
index 49cbf3e..27f2723 100644 (file)
@@ -707,7 +707,7 @@ int dma_mmap_noncontiguous(struct device *dev, struct vm_area_struct *vma,
 }
 EXPORT_SYMBOL_GPL(dma_mmap_noncontiguous);
 
-int dma_supported(struct device *dev, u64 mask)
+static int dma_supported(struct device *dev, u64 mask)
 {
        const struct dma_map_ops *ops = get_dma_ops(dev);
 
@@ -721,7 +721,6 @@ int dma_supported(struct device *dev, u64 mask)
                return 1;
        return ops->dma_supported(dev, mask);
 }
-EXPORT_SYMBOL(dma_supported);
 
 bool dma_pci_p2pdma_supported(struct device *dev)
 {
index c5a9190..0ef6b12 100644 (file)
@@ -326,9 +326,6 @@ void __init swiotlb_init_remap(bool addressing_limit, unsigned int flags,
                swiotlb_adjust_nareas(num_possible_cpus());
 
        nslabs = default_nslabs;
-       if (nslabs < IO_TLB_MIN_SLABS)
-               panic("%s: nslabs = %lu too small\n", __func__, nslabs);
-
        /*
         * By default allocate the bounce buffer memory from low memory, but
         * allow to pick a location everywhere for hypervisors with guest
@@ -341,8 +338,7 @@ retry:
        else
                tlb = memblock_alloc_low(bytes, PAGE_SIZE);
        if (!tlb) {
-               pr_warn("%s: Failed to allocate %zu bytes tlb structure\n",
-                       __func__, bytes);
+               pr_warn("%s: failed to allocate tlb structure\n", __func__);
                return;
        }
 
@@ -579,7 +575,10 @@ static void swiotlb_bounce(struct device *dev, phys_addr_t tlb_addr, size_t size
        }
 }
 
-#define slot_addr(start, idx)  ((start) + ((idx) << IO_TLB_SHIFT))
+static inline phys_addr_t slot_addr(phys_addr_t start, phys_addr_t idx)
+{
+       return start + (idx << IO_TLB_SHIFT);
+}
 
 /*
  * Carefully handle integer overflow which can occur when boundary_mask == ~0UL.
@@ -765,7 +764,7 @@ phys_addr_t swiotlb_tbl_map_single(struct device *dev, phys_addr_t orig_addr,
        /*
         * When dir == DMA_FROM_DEVICE we could omit the copy from the orig
         * to the tlb buffer, if we knew for sure the device will
-        * overwirte the entire current content. But we don't. Thus
+        * overwrite the entire current content. But we don't. Thus
         * unconditional bounce may prevent leaking swiotlb content (i.e.
         * kernel memory) to user-space.
         */
index 90c85b1..2b6bd51 100644 (file)
@@ -1225,6 +1225,7 @@ void mmput_async(struct mm_struct *mm)
                schedule_work(&mm->async_put_work);
        }
 }
+EXPORT_SYMBOL_GPL(mmput_async);
 #endif
 
 /**
@@ -2046,11 +2047,8 @@ static __latent_entropy struct task_struct *copy_process(
        /*
         * If the new process will be in a different time namespace
         * do not allow it to share VM or a thread group with the forking task.
-        *
-        * On vfork, the child process enters the target time namespace only
-        * after exec.
         */
-       if ((clone_flags & (CLONE_VM | CLONE_VFORK)) == CLONE_VM) {
+       if (clone_flags & (CLONE_THREAD | CLONE_VM)) {
                if (nsp->time_ns != nsp->time_ns_for_children)
                        return ERR_PTR(-EINVAL);
        }
index 80697e5..ca9d834 100644 (file)
@@ -1562,6 +1562,7 @@ static int check_kprobe_address_safe(struct kprobe *p,
        /* Ensure it is not in reserved area nor out of text */
        if (!(core_kernel_text((unsigned long) p->addr) ||
            is_module_text_address((unsigned long) p->addr)) ||
+           in_gate_area_no_mm((unsigned long) p->addr) ||
            within_kprobe_blacklist((unsigned long) p->addr) ||
            jump_label_text_reserved(p->addr, p->addr) ||
            static_call_text_reserved(p->addr, p->addr) ||
@@ -1707,11 +1708,12 @@ static struct kprobe *__disable_kprobe(struct kprobe *p)
                /* Try to disarm and disable this/parent probe */
                if (p == orig_p || aggr_kprobe_disabled(orig_p)) {
                        /*
-                        * If 'kprobes_all_disarmed' is set, 'orig_p'
-                        * should have already been disarmed, so
-                        * skip unneed disarming process.
+                        * Don't be lazy here.  Even if 'kprobes_all_disarmed'
+                        * is false, 'orig_p' might not have been armed yet.
+                        * Note arm_all_kprobes() __tries__ to arm all kprobes
+                        * on the best effort basis.
                         */
-                       if (!kprobes_all_disarmed) {
+                       if (!kprobes_all_disarmed && !kprobe_disabled(orig_p)) {
                                ret = disarm_kprobe(orig_p, true);
                                if (ret) {
                                        p->flags &= ~KPROBE_FLAG_DISABLED;
index 6a477c6..a4e4d84 100644 (file)
@@ -2099,7 +2099,7 @@ static int find_module_sections(struct module *mod, struct load_info *info)
                                              sizeof(*mod->static_call_sites),
                                              &mod->num_static_call_sites);
 #endif
-#ifdef CONFIG_KUNIT
+#if IS_ENABLED(CONFIG_KUNIT)
        mod->kunit_suites = section_objs(info, ".kunit_test_suites",
                                              sizeof(*mod->kunit_suites),
                                              &mod->num_kunit_suites);
index b4cbb40..eec72ca 100644 (file)
@@ -179,8 +179,7 @@ int copy_namespaces(unsigned long flags, struct task_struct *tsk)
        if (IS_ERR(new_ns))
                return  PTR_ERR(new_ns);
 
-       if ((flags & CLONE_VM) == 0)
-               timens_on_fork(new_ns, tsk);
+       timens_on_fork(new_ns, tsk);
 
        tsk->nsproxy = new_ns;
        return 0;
index bb3d63b..667876d 100644 (file)
@@ -416,7 +416,7 @@ void update_sched_domain_debugfs(void)
                char buf[32];
 
                snprintf(buf, sizeof(buf), "cpu%d", cpu);
-               debugfs_remove(debugfs_lookup(buf, sd_dentry));
+               debugfs_lookup_and_remove(buf, sd_dentry);
                d_cpu = debugfs_create_dir(buf, sd_dentry);
 
                i = 0;
index ec66b40..ecb4b4f 100644 (file)
@@ -190,12 +190,8 @@ static void group_init(struct psi_group *group)
        /* Init trigger-related members */
        mutex_init(&group->trigger_lock);
        INIT_LIST_HEAD(&group->triggers);
-       memset(group->nr_triggers, 0, sizeof(group->nr_triggers));
-       group->poll_states = 0;
        group->poll_min_period = U32_MAX;
-       memset(group->polling_total, 0, sizeof(group->polling_total));
        group->polling_next_update = ULLONG_MAX;
-       group->polling_until = 0;
        init_waitqueue_head(&group->poll_wait);
        timer_setup(&group->poll_timer, poll_timer_fn, 0);
        rcu_assign_pointer(group->poll_task, NULL);
@@ -957,7 +953,7 @@ int psi_cgroup_alloc(struct cgroup *cgroup)
        if (static_branch_likely(&psi_disabled))
                return 0;
 
-       cgroup->psi = kmalloc(sizeof(struct psi_group), GFP_KERNEL);
+       cgroup->psi = kzalloc(sizeof(struct psi_group), GFP_KERNEL);
        if (!cgroup->psi)
                return -ENOMEM;
 
@@ -1091,7 +1087,7 @@ int psi_show(struct seq_file *m, struct psi_group *group, enum psi_res res)
 }
 
 struct psi_trigger *psi_trigger_create(struct psi_group *group,
-                       char *buf, size_t nbytes, enum psi_res res)
+                       char *buf, enum psi_res res)
 {
        struct psi_trigger *t;
        enum psi_states state;
@@ -1320,7 +1316,7 @@ static ssize_t psi_write(struct file *file, const char __user *user_buf,
                return -EBUSY;
        }
 
-       new = psi_trigger_create(&psi_system, buf, nbytes, res);
+       new = psi_trigger_create(&psi_system, buf, res);
        if (IS_ERR(new)) {
                mutex_unlock(&seq->lock);
                return PTR_ERR(new);
index d4788f8..0b1cd98 100644 (file)
@@ -47,7 +47,7 @@ __wait_on_bit(struct wait_queue_head *wq_head, struct wait_bit_queue_entry *wbq_
                prepare_to_wait(wq_head, &wbq_entry->wq_entry, mode);
                if (test_bit(wbq_entry->key.bit_nr, wbq_entry->key.flags))
                        ret = (*action)(&wbq_entry->key, mode);
-       } while (test_bit(wbq_entry->key.bit_nr, wbq_entry->key.flags) && !ret);
+       } while (test_bit_acquire(wbq_entry->key.bit_nr, wbq_entry->key.flags) && !ret);
 
        finish_wait(wq_head, &wbq_entry->wq_entry);
 
index a492f15..860b2dc 100644 (file)
@@ -277,6 +277,7 @@ COND_SYSCALL(landlock_restrict_self);
 
 /* mm/fadvise.c */
 COND_SYSCALL(fadvise64_64);
+COND_SYSCALL_COMPAT(fadvise64_64);
 
 /* mm/, CONFIG_MMU only */
 COND_SYSCALL(swapon);
index bc921a3..439e2ab 100644 (file)
@@ -1861,8 +1861,6 @@ static void ftrace_hash_rec_enable_modify(struct ftrace_ops *ops,
        ftrace_hash_rec_update_modify(ops, filter_hash, 1);
 }
 
-static bool ops_references_ip(struct ftrace_ops *ops, unsigned long ip);
-
 /*
  * Try to update IPMODIFY flag on each ftrace_rec. Return 0 if it is OK
  * or no-needed to update, -EBUSY if it detects a conflict of the flag
@@ -2974,6 +2972,16 @@ int ftrace_startup(struct ftrace_ops *ops, int command)
 
        ftrace_startup_enable(command);
 
+       /*
+        * If ftrace is in an undefined state, we just remove ops from list
+        * to prevent the NULL pointer, instead of totally rolling it back and
+        * free trampoline, because those actions could cause further damage.
+        */
+       if (unlikely(ftrace_disabled)) {
+               __unregister_ftrace_function(ops);
+               return -ENODEV;
+       }
+
        ops->flags &= ~FTRACE_OPS_FL_ADDING;
 
        return 0;
@@ -3108,49 +3116,6 @@ static inline int ops_traces_mod(struct ftrace_ops *ops)
                ftrace_hash_empty(ops->func_hash->notrace_hash);
 }
 
-/*
- * Check if the current ops references the given ip.
- *
- * If the ops traces all functions, then it was already accounted for.
- * If the ops does not trace the current record function, skip it.
- * If the ops ignores the function via notrace filter, skip it.
- */
-static bool
-ops_references_ip(struct ftrace_ops *ops, unsigned long ip)
-{
-       /* If ops isn't enabled, ignore it */
-       if (!(ops->flags & FTRACE_OPS_FL_ENABLED))
-               return false;
-
-       /* If ops traces all then it includes this function */
-       if (ops_traces_mod(ops))
-               return true;
-
-       /* The function must be in the filter */
-       if (!ftrace_hash_empty(ops->func_hash->filter_hash) &&
-           !__ftrace_lookup_ip(ops->func_hash->filter_hash, ip))
-               return false;
-
-       /* If in notrace hash, we ignore it too */
-       if (ftrace_lookup_ip(ops->func_hash->notrace_hash, ip))
-               return false;
-
-       return true;
-}
-
-/*
- * Check if the current ops references the record.
- *
- * If the ops traces all functions, then it was already accounted for.
- * If the ops does not trace the current record function, skip it.
- * If the ops ignores the function via notrace filter, skip it.
- */
-static bool
-ops_references_rec(struct ftrace_ops *ops, struct dyn_ftrace *rec)
-{
-       return ops_references_ip(ops, rec->ip);
-}
-
 static int ftrace_update_code(struct module *mod, struct ftrace_page *new_pgs)
 {
        bool init_nop = ftrace_need_init_nop();
@@ -6812,6 +6777,38 @@ static int ftrace_get_trampoline_kallsym(unsigned int symnum,
        return -ERANGE;
 }
 
+#if defined(CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS) || defined(CONFIG_MODULES)
+/*
+ * Check if the current ops references the given ip.
+ *
+ * If the ops traces all functions, then it was already accounted for.
+ * If the ops does not trace the current record function, skip it.
+ * If the ops ignores the function via notrace filter, skip it.
+ */
+static bool
+ops_references_ip(struct ftrace_ops *ops, unsigned long ip)
+{
+       /* If ops isn't enabled, ignore it */
+       if (!(ops->flags & FTRACE_OPS_FL_ENABLED))
+               return false;
+
+       /* If ops traces all then it includes this function */
+       if (ops_traces_mod(ops))
+               return true;
+
+       /* The function must be in the filter */
+       if (!ftrace_hash_empty(ops->func_hash->filter_hash) &&
+           !__ftrace_lookup_ip(ops->func_hash->filter_hash, ip))
+               return false;
+
+       /* If in notrace hash, we ignore it too */
+       if (ftrace_lookup_ip(ops->func_hash->notrace_hash, ip))
+               return false;
+
+       return true;
+}
+#endif
+
 #ifdef CONFIG_MODULES
 
 #define next_to_ftrace_page(p) container_of(p, struct ftrace_page, next)
@@ -6824,7 +6821,7 @@ static int referenced_filters(struct dyn_ftrace *rec)
        int cnt = 0;
 
        for (ops = ftrace_ops_list; ops != &ftrace_list_end; ops = ops->next) {
-               if (ops_references_rec(ops, rec)) {
+               if (ops_references_ip(ops, rec->ip)) {
                        if (WARN_ON_ONCE(ops->flags & FTRACE_OPS_FL_DIRECT))
                                continue;
                        if (WARN_ON_ONCE(ops->flags & FTRACE_OPS_FL_IPMODIFY))
index c1c47e2..dacc37b 100644 (file)
@@ -27,7 +27,7 @@ struct automaton_wip {
        bool final_states[state_max_wip];
 };
 
-struct automaton_wip automaton_wip = {
+static struct automaton_wip automaton_wip = {
        .state_names = {
                "preemptive",
                "non_preemptive"
index d1afe55..118e576 100644 (file)
@@ -27,7 +27,7 @@ struct automaton_wwnr {
        bool final_states[state_max_wwnr];
 };
 
-struct automaton_wwnr automaton_wwnr = {
+static struct automaton_wwnr automaton_wwnr = {
        .state_names = {
                "not_running",
                "running"
index b698d05..d65f6c2 100644 (file)
@@ -24,13 +24,13 @@ static struct rv_reactor rv_panic = {
        .react = rv_panic_reaction
 };
 
-static int register_react_panic(void)
+static int __init register_react_panic(void)
 {
        rv_register_reactor(&rv_panic);
        return 0;
 }
 
-static void unregister_react_panic(void)
+static void __exit unregister_react_panic(void)
 {
        rv_unregister_reactor(&rv_panic);
 }
index 31899f9..4b6b710 100644 (file)
@@ -23,13 +23,13 @@ static struct rv_reactor rv_printk = {
        .react = rv_printk_reaction
 };
 
-static int register_react_printk(void)
+static int __init register_react_printk(void)
 {
        rv_register_reactor(&rv_printk);
        return 0;
 }
 
-static void unregister_react_printk(void)
+static void __exit unregister_react_printk(void)
 {
        rv_unregister_reactor(&rv_printk);
 }
index 4a0e9d9..1783e34 100644 (file)
@@ -227,6 +227,7 @@ static int trace_eprobe_tp_arg_update(struct trace_eprobe *ep, int i)
        struct probe_arg *parg = &ep->tp.args[i];
        struct ftrace_event_field *field;
        struct list_head *head;
+       int ret = -ENOENT;
 
        head = trace_get_fields(ep->event);
        list_for_each_entry(field, head, link) {
@@ -236,9 +237,20 @@ static int trace_eprobe_tp_arg_update(struct trace_eprobe *ep, int i)
                        return 0;
                }
        }
+
+       /*
+        * Argument not found on event. But allow for comm and COMM
+        * to be used to get the current->comm.
+        */
+       if (strcmp(parg->code->data, "COMM") == 0 ||
+           strcmp(parg->code->data, "comm") == 0) {
+               parg->code->op = FETCH_OP_COMM;
+               ret = 0;
+       }
+
        kfree(parg->code->data);
        parg->code->data = NULL;
-       return -ENOENT;
+       return ret;
 }
 
 static int eprobe_event_define_fields(struct trace_event_call *event_call)
@@ -311,6 +323,27 @@ static unsigned long get_event_field(struct fetch_insn *code, void *rec)
 
        addr = rec + field->offset;
 
+       if (is_string_field(field)) {
+               switch (field->filter_type) {
+               case FILTER_DYN_STRING:
+                       val = (unsigned long)(rec + (*(unsigned int *)addr & 0xffff));
+                       break;
+               case FILTER_RDYN_STRING:
+                       val = (unsigned long)(addr + (*(unsigned int *)addr & 0xffff));
+                       break;
+               case FILTER_STATIC_STRING:
+                       val = (unsigned long)addr;
+                       break;
+               case FILTER_PTR_STRING:
+                       val = (unsigned long)(*(char *)addr);
+                       break;
+               default:
+                       WARN_ON_ONCE(1);
+                       return 0;
+               }
+               return val;
+       }
+
        switch (field->size) {
        case 1:
                if (field->is_signed)
@@ -342,16 +375,38 @@ static unsigned long get_event_field(struct fetch_insn *code, void *rec)
 
 static int get_eprobe_size(struct trace_probe *tp, void *rec)
 {
+       struct fetch_insn *code;
        struct probe_arg *arg;
        int i, len, ret = 0;
 
        for (i = 0; i < tp->nr_args; i++) {
                arg = tp->args + i;
-               if (unlikely(arg->dynamic)) {
+               if (arg->dynamic) {
                        unsigned long val;
 
-                       val = get_event_field(arg->code, rec);
-                       len = process_fetch_insn_bottom(arg->code + 1, val, NULL, NULL);
+                       code = arg->code;
+ retry:
+                       switch (code->op) {
+                       case FETCH_OP_TP_ARG:
+                               val = get_event_field(code, rec);
+                               break;
+                       case FETCH_OP_IMM:
+                               val = code->immediate;
+                               break;
+                       case FETCH_OP_COMM:
+                               val = (unsigned long)current->comm;
+                               break;
+                       case FETCH_OP_DATA:
+                               val = (unsigned long)code->data;
+                               break;
+                       case FETCH_NOP_SYMBOL:  /* Ignore a place holder */
+                               code++;
+                               goto retry;
+                       default:
+                               continue;
+                       }
+                       code++;
+                       len = process_fetch_insn_bottom(code, val, NULL, NULL);
                        if (len > 0)
                                ret += len;
                }
@@ -369,8 +424,28 @@ process_fetch_insn(struct fetch_insn *code, void *rec, void *dest,
 {
        unsigned long val;
 
-       val = get_event_field(code, rec);
-       return process_fetch_insn_bottom(code + 1, val, dest, base);
+ retry:
+       switch (code->op) {
+       case FETCH_OP_TP_ARG:
+               val = get_event_field(code, rec);
+               break;
+       case FETCH_OP_IMM:
+               val = code->immediate;
+               break;
+       case FETCH_OP_COMM:
+               val = (unsigned long)current->comm;
+               break;
+       case FETCH_OP_DATA:
+               val = (unsigned long)code->data;
+               break;
+       case FETCH_NOP_SYMBOL:  /* Ignore a place holder */
+               code++;
+               goto retry;
+       default:
+               return -EILSEQ;
+       }
+       code++;
+       return process_fetch_insn_bottom(code, val, dest, base);
 }
 NOKPROBE_SYMBOL(process_fetch_insn)
 
@@ -845,6 +920,10 @@ static int trace_eprobe_tp_update_arg(struct trace_eprobe *ep, const char *argv[
                        trace_probe_log_err(0, BAD_ATTACH_ARG);
        }
 
+       /* Handle symbols "@" */
+       if (!ret)
+               ret = traceprobe_update_arg(&ep->tp.args[i]);
+
        return ret;
 }
 
@@ -883,7 +962,7 @@ static int __trace_eprobe_create(int argc, const char *argv[])
        trace_probe_log_set_index(1);
        sys_event = argv[1];
        ret = traceprobe_parse_event_name(&sys_event, &sys_name, buf2, 0);
-       if (!sys_event || !sys_name) {
+       if (ret || !sys_event || !sys_name) {
                trace_probe_log_err(0, NO_EVENT_INFO);
                goto parse_error;
        }
index a114549..61e3a26 100644 (file)
@@ -157,7 +157,7 @@ static void perf_trace_event_unreg(struct perf_event *p_event)
        int i;
 
        if (--tp_event->perf_refcount > 0)
-               goto out;
+               return;
 
        tp_event->class->reg(tp_event, TRACE_REG_PERF_UNREGISTER, NULL);
 
@@ -176,8 +176,6 @@ static void perf_trace_event_unreg(struct perf_event *p_event)
                        perf_trace_buf[i] = NULL;
                }
        }
-out:
-       trace_event_put_ref(tp_event);
 }
 
 static int perf_trace_event_open(struct perf_event *p_event)
@@ -241,6 +239,7 @@ void perf_trace_destroy(struct perf_event *p_event)
        mutex_lock(&event_mutex);
        perf_trace_event_close(p_event);
        perf_trace_event_unreg(p_event);
+       trace_event_put_ref(p_event->tp_event);
        mutex_unlock(&event_mutex);
 }
 
@@ -292,6 +291,7 @@ void perf_kprobe_destroy(struct perf_event *p_event)
        mutex_lock(&event_mutex);
        perf_trace_event_close(p_event);
        perf_trace_event_unreg(p_event);
+       trace_event_put_ref(p_event->tp_event);
        mutex_unlock(&event_mutex);
 
        destroy_local_trace_kprobe(p_event->tp_event);
@@ -347,6 +347,7 @@ void perf_uprobe_destroy(struct perf_event *p_event)
        mutex_lock(&event_mutex);
        perf_trace_event_close(p_event);
        perf_trace_event_unreg(p_event);
+       trace_event_put_ref(p_event->tp_event);
        mutex_unlock(&event_mutex);
        destroy_local_trace_uprobe(p_event->tp_event);
 }
index 181f081..0356cae 100644 (file)
@@ -176,6 +176,7 @@ static int trace_define_generic_fields(void)
 
        __generic_field(int, CPU, FILTER_CPU);
        __generic_field(int, cpu, FILTER_CPU);
+       __generic_field(int, common_cpu, FILTER_CPU);
        __generic_field(char *, COMM, FILTER_COMM);
        __generic_field(char *, comm, FILTER_COMM);
 
index cb866c3..918730d 100644 (file)
@@ -142,7 +142,8 @@ static bool check_user_trigger(struct trace_event_file *file)
 {
        struct event_trigger_data *data;
 
-       list_for_each_entry_rcu(data, &file->triggers, list) {
+       list_for_each_entry_rcu(data, &file->triggers, list,
+                               lockdep_is_held(&event_mutex)) {
                if (data->flags & EVENT_TRIGGER_FL_PROBE)
                        continue;
                return true;
index 95b58bd..1e130da 100644 (file)
@@ -95,14 +95,14 @@ __visible void trace_hardirqs_on_caller(unsigned long caller_addr)
        }
 
        lockdep_hardirqs_on_prepare();
-       lockdep_hardirqs_on(CALLER_ADDR0);
+       lockdep_hardirqs_on(caller_addr);
 }
 EXPORT_SYMBOL(trace_hardirqs_on_caller);
 NOKPROBE_SYMBOL(trace_hardirqs_on_caller);
 
 __visible void trace_hardirqs_off_caller(unsigned long caller_addr)
 {
-       lockdep_hardirqs_off(CALLER_ADDR0);
+       lockdep_hardirqs_off(caller_addr);
 
        if (!this_cpu_read(tracing_irq_cpu)) {
                this_cpu_write(tracing_irq_cpu, 1);
index 850a88a..36dff27 100644 (file)
@@ -283,7 +283,14 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t,
        int ret = 0;
        int len;
 
-       if (strcmp(arg, "retval") == 0) {
+       if (flags & TPARG_FL_TPOINT) {
+               if (code->data)
+                       return -EFAULT;
+               code->data = kstrdup(arg, GFP_KERNEL);
+               if (!code->data)
+                       return -ENOMEM;
+               code->op = FETCH_OP_TP_ARG;
+       } else if (strcmp(arg, "retval") == 0) {
                if (flags & TPARG_FL_RETURN) {
                        code->op = FETCH_OP_RETVAL;
                } else {
@@ -307,7 +314,7 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t,
                        }
                } else
                        goto inval_var;
-       } else if (strcmp(arg, "comm") == 0) {
+       } else if (strcmp(arg, "comm") == 0 || strcmp(arg, "COMM") == 0) {
                code->op = FETCH_OP_COMM;
 #ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API
        } else if (((flags & TPARG_FL_MASK) ==
@@ -323,13 +330,6 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t,
                code->op = FETCH_OP_ARG;
                code->param = (unsigned int)param - 1;
 #endif
-       } else if (flags & TPARG_FL_TPOINT) {
-               if (code->data)
-                       return -EFAULT;
-               code->data = kstrdup(arg, GFP_KERNEL);
-               if (!code->data)
-                       return -ENOMEM;
-               code->op = FETCH_OP_TP_ARG;
        } else
                goto inval_var;
 
@@ -384,6 +384,11 @@ parse_probe_arg(char *arg, const struct fetch_type *type,
                break;
 
        case '%':       /* named register */
+               if (flags & TPARG_FL_TPOINT) {
+                       /* eprobes do not handle registers */
+                       trace_probe_log_err(offs, BAD_VAR);
+                       break;
+               }
                ret = regs_query_register_offset(arg + 1);
                if (ret >= 0) {
                        code->op = FETCH_OP_REG;
@@ -617,9 +622,11 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size,
 
        /*
         * Since $comm and immediate string can not be dereferenced,
-        * we can find those by strcmp.
+        * we can find those by strcmp. But ignore for eprobes.
         */
-       if (strcmp(arg, "$comm") == 0 || strncmp(arg, "\\\"", 2) == 0) {
+       if (!(flags & TPARG_FL_TPOINT) &&
+           (strcmp(arg, "$comm") == 0 || strcmp(arg, "$COMM") == 0 ||
+            strncmp(arg, "\\\"", 2) == 0)) {
                /* The type of $comm must be "string", and not an array. */
                if (parg->count || (t && strcmp(t, "string")))
                        goto out;
index 64ea283..ef42c1a 100644 (file)
@@ -571,7 +571,8 @@ static void for_each_tracepoint_range(
 bool trace_module_has_bad_taint(struct module *mod)
 {
        return mod->taints & ~((1 << TAINT_OOT_MODULE) | (1 << TAINT_CRAP) |
-                              (1 << TAINT_UNSIGNED_MODULE));
+                              (1 << TAINT_UNSIGNED_MODULE) |
+                              (1 << TAINT_TEST));
 }
 
 static BLOCKING_NOTIFIER_HEAD(tracepoint_notify_list);
@@ -647,7 +648,7 @@ static int tracepoint_module_coming(struct module *mod)
        /*
         * We skip modules that taint the kernel, especially those with different
         * module headers (for forced load), to make sure we don't cause a crash.
-        * Staging, out-of-tree, and unsigned GPL modules are fine.
+        * Staging, out-of-tree, unsigned GPL, and test modules are fine.
         */
        if (trace_module_has_bad_taint(mod))
                return 0;
index 072e4b2..bcbe60d 100644 (file)
@@ -2029,13 +2029,16 @@ config LKDTM
        Documentation on how to use the module can be found in
        Documentation/fault-injection/provoke-crashes.rst
 
-config TEST_CPUMASK
-       tristate "cpumask tests" if !KUNIT_ALL_TESTS
+config CPUMASK_KUNIT_TEST
+       tristate "KUnit test for cpumask" if !KUNIT_ALL_TESTS
        depends on KUNIT
        default KUNIT_ALL_TESTS
        help
          Enable to turn on cpumask tests, running at boot or module load time.
 
+         For more information on KUnit and unit tests in general, please refer
+         to the KUnit documentation in Documentation/dev-tools/kunit/.
+
          If unsure, say N.
 
 config TEST_LIST_SORT
index c952121..ffabc30 100644 (file)
@@ -34,9 +34,10 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \
         is_single_threaded.o plist.o decompress.o kobject_uevent.o \
         earlycpio.o seq_buf.o siphash.o dec_and_lock.o \
         nmi_backtrace.o win_minmax.o memcat_p.o \
-        buildid.o cpumask.o
+        buildid.o
 
 lib-$(CONFIG_PRINTK) += dump_stack.o
+lib-$(CONFIG_SMP) += cpumask.o
 
 lib-y  += kobject.o klist.o
 obj-y  += lockref.o
@@ -59,6 +60,7 @@ obj-$(CONFIG_TEST_BPF) += test_bpf.o
 obj-$(CONFIG_TEST_FIRMWARE) += test_firmware.o
 obj-$(CONFIG_TEST_BITOPS) += test_bitops.o
 CFLAGS_test_bitops.o += -Werror
+obj-$(CONFIG_CPUMASK_KUNIT_TEST) += cpumask_kunit.o
 obj-$(CONFIG_TEST_SYSCTL) += test_sysctl.o
 obj-$(CONFIG_TEST_SIPHASH) += test_siphash.o
 obj-$(CONFIG_HASH_KUNIT_TEST) += test_hash.o
@@ -99,7 +101,6 @@ obj-$(CONFIG_TEST_HMM) += test_hmm.o
 obj-$(CONFIG_TEST_FREE_PAGES) += test_free_pages.o
 obj-$(CONFIG_KPROBES_SANITY_TEST) += test_kprobes.o
 obj-$(CONFIG_TEST_REF_TRACKER) += test_ref_tracker.o
-obj-$(CONFIG_TEST_CPUMASK) += test_cpumask.o
 CFLAGS_test_fprobe.o += $(CC_FLAGS_FTRACE)
 obj-$(CONFIG_FPROBE_SANITY_TEST) += test_fprobe.o
 #
index 8baeb37..f0ae119 100644 (file)
@@ -109,7 +109,6 @@ void __init free_bootmem_cpumask_var(cpumask_var_t mask)
 }
 #endif
 
-#if NR_CPUS > 1
 /**
  * cpumask_local_spread - select the i'th cpu with local numa cpu's first
  * @i: index number
@@ -197,4 +196,3 @@ unsigned int cpumask_any_distribute(const struct cpumask *srcp)
        return next;
 }
 EXPORT_SYMBOL(cpumask_any_distribute);
-#endif /* NR_CPUS */
similarity index 58%
rename from lib/test_cpumask.c
rename to lib/cpumask_kunit.c
index a31a162..ecbeec7 100644 (file)
@@ -9,6 +9,10 @@
 #include <linux/cpu.h>
 #include <linux/cpumask.h>
 
+#define MASK_MSG(m) \
+       "%s contains %sCPUs %*pbl", #m, (cpumask_weight(m) ? "" : "no "), \
+       nr_cpumask_bits, cpumask_bits(m)
+
 #define EXPECT_FOR_EACH_CPU_EQ(test, mask)                     \
        do {                                                    \
                const cpumask_t *m = (mask);                    \
@@ -16,7 +20,7 @@
                int cpu, iter = 0;                              \
                for_each_cpu(cpu, m)                            \
                        iter++;                                 \
-               KUNIT_EXPECT_EQ((test), mask_weight, iter);     \
+               KUNIT_EXPECT_EQ_MSG((test), mask_weight, iter, MASK_MSG(mask)); \
        } while (0)
 
 #define EXPECT_FOR_EACH_CPU_NOT_EQ(test, mask)                                 \
@@ -26,7 +30,7 @@
                int cpu, iter = 0;                                              \
                for_each_cpu_not(cpu, m)                                        \
                        iter++;                                                 \
-               KUNIT_EXPECT_EQ((test), nr_cpu_ids - mask_weight, iter);        \
+               KUNIT_EXPECT_EQ_MSG((test), nr_cpu_ids - mask_weight, iter, MASK_MSG(mask));    \
        } while (0)
 
 #define EXPECT_FOR_EACH_CPU_WRAP_EQ(test, mask)                        \
@@ -36,7 +40,7 @@
                int cpu, iter = 0;                              \
                for_each_cpu_wrap(cpu, m, nr_cpu_ids / 2)       \
                        iter++;                                 \
-               KUNIT_EXPECT_EQ((test), mask_weight, iter);     \
+               KUNIT_EXPECT_EQ_MSG((test), mask_weight, iter, MASK_MSG(mask)); \
        } while (0)
 
 #define EXPECT_FOR_EACH_CPU_BUILTIN_EQ(test, name)             \
@@ -45,7 +49,7 @@
                int cpu, iter = 0;                              \
                for_each_##name##_cpu(cpu)                      \
                        iter++;                                 \
-               KUNIT_EXPECT_EQ((test), mask_weight, iter);     \
+               KUNIT_EXPECT_EQ_MSG((test), mask_weight, iter, MASK_MSG(cpu_##name##_mask));    \
        } while (0)
 
 static cpumask_t mask_empty;
@@ -53,37 +57,43 @@ static cpumask_t mask_all;
 
 static void test_cpumask_weight(struct kunit *test)
 {
-       KUNIT_EXPECT_TRUE(test, cpumask_empty(&mask_empty));
-       KUNIT_EXPECT_TRUE(test, cpumask_full(cpu_possible_mask));
-       KUNIT_EXPECT_TRUE(test, cpumask_full(&mask_all));
+       KUNIT_EXPECT_TRUE_MSG(test, cpumask_empty(&mask_empty), MASK_MSG(&mask_empty));
+       KUNIT_EXPECT_TRUE_MSG(test, cpumask_full(&mask_all), MASK_MSG(&mask_all));
 
-       KUNIT_EXPECT_EQ(test, 0, cpumask_weight(&mask_empty));
-       KUNIT_EXPECT_EQ(test, nr_cpu_ids, cpumask_weight(cpu_possible_mask));
-       KUNIT_EXPECT_EQ(test, nr_cpumask_bits, cpumask_weight(&mask_all));
+       KUNIT_EXPECT_EQ_MSG(test, 0, cpumask_weight(&mask_empty), MASK_MSG(&mask_empty));
+       KUNIT_EXPECT_EQ_MSG(test, nr_cpu_ids, cpumask_weight(cpu_possible_mask),
+                           MASK_MSG(cpu_possible_mask));
+       KUNIT_EXPECT_EQ_MSG(test, nr_cpumask_bits, cpumask_weight(&mask_all), MASK_MSG(&mask_all));
 }
 
 static void test_cpumask_first(struct kunit *test)
 {
-       KUNIT_EXPECT_LE(test, nr_cpu_ids, cpumask_first(&mask_empty));
-       KUNIT_EXPECT_EQ(test, 0, cpumask_first(cpu_possible_mask));
+       KUNIT_EXPECT_LE_MSG(test, nr_cpu_ids, cpumask_first(&mask_empty), MASK_MSG(&mask_empty));
+       KUNIT_EXPECT_EQ_MSG(test, 0, cpumask_first(cpu_possible_mask), MASK_MSG(cpu_possible_mask));
 
-       KUNIT_EXPECT_EQ(test, 0, cpumask_first_zero(&mask_empty));
-       KUNIT_EXPECT_LE(test, nr_cpu_ids, cpumask_first_zero(cpu_possible_mask));
+       KUNIT_EXPECT_EQ_MSG(test, 0, cpumask_first_zero(&mask_empty), MASK_MSG(&mask_empty));
+       KUNIT_EXPECT_LE_MSG(test, nr_cpu_ids, cpumask_first_zero(cpu_possible_mask),
+                           MASK_MSG(cpu_possible_mask));
 }
 
 static void test_cpumask_last(struct kunit *test)
 {
-       KUNIT_EXPECT_LE(test, nr_cpumask_bits, cpumask_last(&mask_empty));
-       KUNIT_EXPECT_EQ(test, nr_cpumask_bits - 1, cpumask_last(cpu_possible_mask));
+       KUNIT_EXPECT_LE_MSG(test, nr_cpumask_bits, cpumask_last(&mask_empty),
+                           MASK_MSG(&mask_empty));
+       KUNIT_EXPECT_EQ_MSG(test, nr_cpu_ids - 1, cpumask_last(cpu_possible_mask),
+                           MASK_MSG(cpu_possible_mask));
 }
 
 static void test_cpumask_next(struct kunit *test)
 {
-       KUNIT_EXPECT_EQ(test, 0, cpumask_next_zero(-1, &mask_empty));
-       KUNIT_EXPECT_LE(test, nr_cpu_ids, cpumask_next_zero(-1, cpu_possible_mask));
-
-       KUNIT_EXPECT_LE(test, nr_cpu_ids, cpumask_next(-1, &mask_empty));
-       KUNIT_EXPECT_EQ(test, 0, cpumask_next(-1, cpu_possible_mask));
+       KUNIT_EXPECT_EQ_MSG(test, 0, cpumask_next_zero(-1, &mask_empty), MASK_MSG(&mask_empty));
+       KUNIT_EXPECT_LE_MSG(test, nr_cpu_ids, cpumask_next_zero(-1, cpu_possible_mask),
+                           MASK_MSG(cpu_possible_mask));
+
+       KUNIT_EXPECT_LE_MSG(test, nr_cpu_ids, cpumask_next(-1, &mask_empty),
+                           MASK_MSG(&mask_empty));
+       KUNIT_EXPECT_EQ_MSG(test, 0, cpumask_next(-1, cpu_possible_mask),
+                           MASK_MSG(cpu_possible_mask));
 }
 
 static void test_cpumask_iterators(struct kunit *test)
index 9ff549f..47816af 100644 (file)
@@ -33,7 +33,6 @@ config CRYPTO_ARCH_HAVE_LIB_CHACHA
 
 config CRYPTO_LIB_CHACHA_GENERIC
        tristate
-       select XOR_BLOCKS
        help
          This symbol can be depended upon by arch implementations of the
          ChaCha library interface that require the generic code as a
index e01a93f..ce945c1 100644 (file)
  */
 int ___ratelimit(struct ratelimit_state *rs, const char *func)
 {
+       /* Paired with WRITE_ONCE() in .proc_handler().
+        * Changing two values seperately could be inconsistent
+        * and some message could be lost.  (See: net_ratelimit_state).
+        */
+       int interval = READ_ONCE(rs->interval);
+       int burst = READ_ONCE(rs->burst);
        unsigned long flags;
        int ret;
 
-       if (!rs->interval)
+       if (!interval)
                return 1;
 
        /*
@@ -44,7 +50,7 @@ int ___ratelimit(struct ratelimit_state *rs, const char *func)
        if (!rs->begin)
                rs->begin = jiffies;
 
-       if (time_is_before_jiffies(rs->begin + rs->interval)) {
+       if (time_is_before_jiffies(rs->begin + interval)) {
                if (rs->missed) {
                        if (!(rs->flags & RATELIMIT_MSG_ON_RELEASE)) {
                                printk_deferred(KERN_WARNING
@@ -56,7 +62,7 @@ int ___ratelimit(struct ratelimit_state *rs, const char *func)
                rs->begin   = jiffies;
                rs->printed = 0;
        }
-       if (rs->burst && rs->burst > rs->printed) {
+       if (burst && burst > rs->printed) {
                rs->printed++;
                ret = 1;
        } else {
index 95550b8..de65cb1 100644 (file)
@@ -260,10 +260,10 @@ void wb_wakeup_delayed(struct bdi_writeback *wb)
        unsigned long timeout;
 
        timeout = msecs_to_jiffies(dirty_writeback_interval * 10);
-       spin_lock_bh(&wb->work_lock);
+       spin_lock_irq(&wb->work_lock);
        if (test_bit(WB_registered, &wb->state))
                queue_delayed_work(bdi_wq, &wb->dwork, timeout);
-       spin_unlock_bh(&wb->work_lock);
+       spin_unlock_irq(&wb->work_lock);
 }
 
 static void wb_update_bandwidth_workfn(struct work_struct *work)
@@ -334,12 +334,12 @@ static void cgwb_remove_from_bdi_list(struct bdi_writeback *wb);
 static void wb_shutdown(struct bdi_writeback *wb)
 {
        /* Make sure nobody queues further work */
-       spin_lock_bh(&wb->work_lock);
+       spin_lock_irq(&wb->work_lock);
        if (!test_and_clear_bit(WB_registered, &wb->state)) {
-               spin_unlock_bh(&wb->work_lock);
+               spin_unlock_irq(&wb->work_lock);
                return;
        }
-       spin_unlock_bh(&wb->work_lock);
+       spin_unlock_irq(&wb->work_lock);
 
        cgwb_remove_from_bdi_list(wb);
        /*
index f18a631..b1efebf 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/memblock.h>
 #include <linux/bootmem_info.h>
 #include <linux/memory_hotplug.h>
+#include <linux/kmemleak.h>
 
 void get_page_bootmem(unsigned long info, struct page *page, unsigned long type)
 {
@@ -33,6 +34,7 @@ void put_page_bootmem(struct page *page)
                ClearPagePrivate(page);
                set_page_private(page, 0);
                INIT_LIST_HEAD(&page->lru);
+               kmemleak_free_part(page_to_virt(page), PAGE_SIZE);
                free_reserved_page(page);
        }
 }
index cb8a7e9..cfdf631 100644 (file)
@@ -818,6 +818,9 @@ static int dbgfs_mk_context(char *name)
                return -ENOENT;
 
        new_dir = debugfs_create_dir(name, root);
+       /* Below check is required for a potential duplicated name case */
+       if (IS_ERR(new_dir))
+               return PTR_ERR(new_dir);
        dbgfs_dirs[dbgfs_nr_ctxs] = new_dir;
 
        new_ctx = dbgfs_new_ctx();
index 7328251..5abdaf4 100644 (file)
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -478,14 +478,42 @@ static int follow_pfn_pte(struct vm_area_struct *vma, unsigned long address,
        return -EEXIST;
 }
 
-/*
- * FOLL_FORCE can write to even unwritable pte's, but only
- * after we've gone through a COW cycle and they are dirty.
- */
-static inline bool can_follow_write_pte(pte_t pte, unsigned int flags)
+/* FOLL_FORCE can write to even unwritable PTEs in COW mappings. */
+static inline bool can_follow_write_pte(pte_t pte, struct page *page,
+                                       struct vm_area_struct *vma,
+                                       unsigned int flags)
 {
-       return pte_write(pte) ||
-               ((flags & FOLL_FORCE) && (flags & FOLL_COW) && pte_dirty(pte));
+       /* If the pte is writable, we can write to the page. */
+       if (pte_write(pte))
+               return true;
+
+       /* Maybe FOLL_FORCE is set to override it? */
+       if (!(flags & FOLL_FORCE))
+               return false;
+
+       /* But FOLL_FORCE has no effect on shared mappings */
+       if (vma->vm_flags & (VM_MAYSHARE | VM_SHARED))
+               return false;
+
+       /* ... or read-only private ones */
+       if (!(vma->vm_flags & VM_MAYWRITE))
+               return false;
+
+       /* ... or already writable ones that just need to take a write fault */
+       if (vma->vm_flags & VM_WRITE)
+               return false;
+
+       /*
+        * See can_change_pte_writable(): we broke COW and could map the page
+        * writable if we have an exclusive anonymous page ...
+        */
+       if (!page || !PageAnon(page) || !PageAnonExclusive(page))
+               return false;
+
+       /* ... and a write-fault isn't required for other reasons. */
+       if (vma_soft_dirty_enabled(vma) && !pte_soft_dirty(pte))
+               return false;
+       return !userfaultfd_pte_wp(vma, pte);
 }
 
 static struct page *follow_page_pte(struct vm_area_struct *vma,
@@ -528,12 +556,19 @@ retry:
        }
        if ((flags & FOLL_NUMA) && pte_protnone(pte))
                goto no_page;
-       if ((flags & FOLL_WRITE) && !can_follow_write_pte(pte, flags)) {
-               pte_unmap_unlock(ptep, ptl);
-               return NULL;
-       }
 
        page = vm_normal_page(vma, address, pte);
+
+       /*
+        * We only care about anon pages in can_follow_write_pte() and don't
+        * have to worry about pte_devmap() because they are never anon.
+        */
+       if ((flags & FOLL_WRITE) &&
+           !can_follow_write_pte(pte, page, vma, flags)) {
+               page = NULL;
+               goto out;
+       }
+
        if (!page && pte_devmap(pte) && (flags & (FOLL_GET | FOLL_PIN))) {
                /*
                 * Only return device mapping pages in the FOLL_GET or FOLL_PIN
@@ -986,17 +1021,6 @@ static int faultin_page(struct vm_area_struct *vma,
                return -EBUSY;
        }
 
-       /*
-        * The VM_FAULT_WRITE bit tells us that do_wp_page has broken COW when
-        * necessary, even if maybe_mkwrite decided not to set pte_write. We
-        * can thus safely do subsequent page lookups as if they were reads.
-        * But only do so when looping for pte_write is futile: in some cases
-        * userspace may also be wanting to write to the gotten user page,
-        * which a read fault here might prevent (a readonly page might get
-        * reCOWed by userspace write).
-        */
-       if ((ret & VM_FAULT_WRITE) && !(vma->vm_flags & VM_WRITE))
-               *flags |= FOLL_COW;
        return 0;
 }
 
index 8a7c1b3..e9414ee 100644 (file)
@@ -1040,12 +1040,6 @@ struct page *follow_devmap_pmd(struct vm_area_struct *vma, unsigned long addr,
 
        assert_spin_locked(pmd_lockptr(mm, pmd));
 
-       /*
-        * When we COW a devmap PMD entry, we split it into PTEs, so we should
-        * not be in this function with `flags & FOLL_COW` set.
-        */
-       WARN_ONCE(flags & FOLL_COW, "mm: In follow_devmap_pmd with FOLL_COW set");
-
        /* FOLL_GET and FOLL_PIN are mutually exclusive. */
        if (WARN_ON_ONCE((flags & (FOLL_PIN | FOLL_GET)) ==
                         (FOLL_PIN | FOLL_GET)))
@@ -1395,14 +1389,42 @@ fallback:
        return VM_FAULT_FALLBACK;
 }
 
-/*
- * FOLL_FORCE can write to even unwritable pmd's, but only
- * after we've gone through a COW cycle and they are dirty.
- */
-static inline bool can_follow_write_pmd(pmd_t pmd, unsigned int flags)
+/* FOLL_FORCE can write to even unwritable PMDs in COW mappings. */
+static inline bool can_follow_write_pmd(pmd_t pmd, struct page *page,
+                                       struct vm_area_struct *vma,
+                                       unsigned int flags)
 {
-       return pmd_write(pmd) ||
-              ((flags & FOLL_FORCE) && (flags & FOLL_COW) && pmd_dirty(pmd));
+       /* If the pmd is writable, we can write to the page. */
+       if (pmd_write(pmd))
+               return true;
+
+       /* Maybe FOLL_FORCE is set to override it? */
+       if (!(flags & FOLL_FORCE))
+               return false;
+
+       /* But FOLL_FORCE has no effect on shared mappings */
+       if (vma->vm_flags & (VM_MAYSHARE | VM_SHARED))
+               return false;
+
+       /* ... or read-only private ones */
+       if (!(vma->vm_flags & VM_MAYWRITE))
+               return false;
+
+       /* ... or already writable ones that just need to take a write fault */
+       if (vma->vm_flags & VM_WRITE)
+               return false;
+
+       /*
+        * See can_change_pte_writable(): we broke COW and could map the page
+        * writable if we have an exclusive anonymous page ...
+        */
+       if (!page || !PageAnon(page) || !PageAnonExclusive(page))
+               return false;
+
+       /* ... and a write-fault isn't required for other reasons. */
+       if (vma_soft_dirty_enabled(vma) && !pmd_soft_dirty(pmd))
+               return false;
+       return !userfaultfd_huge_pmd_wp(vma, pmd);
 }
 
 struct page *follow_trans_huge_pmd(struct vm_area_struct *vma,
@@ -1411,12 +1433,16 @@ struct page *follow_trans_huge_pmd(struct vm_area_struct *vma,
                                   unsigned int flags)
 {
        struct mm_struct *mm = vma->vm_mm;
-       struct page *page = NULL;
+       struct page *page;
 
        assert_spin_locked(pmd_lockptr(mm, pmd));
 
-       if (flags & FOLL_WRITE && !can_follow_write_pmd(*pmd, flags))
-               goto out;
+       page = pmd_page(*pmd);
+       VM_BUG_ON_PAGE(!PageHead(page) && !is_zone_device_page(page), page);
+
+       if ((flags & FOLL_WRITE) &&
+           !can_follow_write_pmd(*pmd, page, vma, flags))
+               return NULL;
 
        /* Avoid dumping huge zero page */
        if ((flags & FOLL_DUMP) && is_huge_zero_pmd(*pmd))
@@ -1424,10 +1450,7 @@ struct page *follow_trans_huge_pmd(struct vm_area_struct *vma,
 
        /* Full NUMA hinting faults to serialise migration in fault paths */
        if ((flags & FOLL_NUMA) && pmd_protnone(*pmd))
-               goto out;
-
-       page = pmd_page(*pmd);
-       VM_BUG_ON_PAGE(!PageHead(page) && !is_zone_device_page(page), page);
+               return NULL;
 
        if (!pmd_write(*pmd) && gup_must_unshare(flags, page))
                return ERR_PTR(-EMLINK);
@@ -1444,7 +1467,6 @@ struct page *follow_trans_huge_pmd(struct vm_area_struct *vma,
        page += (addr & ~HPAGE_PMD_MASK) >> PAGE_SHIFT;
        VM_BUG_ON_PAGE(!PageCompound(page) && !is_zone_device_page(page), page);
 
-out:
        return page;
 }
 
index 0aee2f3..e070b85 100644 (file)
@@ -5241,6 +5241,21 @@ static vm_fault_t hugetlb_wp(struct mm_struct *mm, struct vm_area_struct *vma,
        VM_BUG_ON(unshare && (flags & FOLL_WRITE));
        VM_BUG_ON(!unshare && !(flags & FOLL_WRITE));
 
+       /*
+        * hugetlb does not support FOLL_FORCE-style write faults that keep the
+        * PTE mapped R/O such as maybe_mkwrite() would do.
+        */
+       if (WARN_ON_ONCE(!unshare && !(vma->vm_flags & VM_WRITE)))
+               return VM_FAULT_SIGSEGV;
+
+       /* Let's take out MAP_SHARED mappings first. */
+       if (vma->vm_flags & VM_MAYSHARE) {
+               if (unlikely(unshare))
+                       return 0;
+               set_huge_ptep_writable(vma, haddr, ptep);
+               return 0;
+       }
+
        pte = huge_ptep_get(ptep);
        old_page = pte_page(pte);
 
@@ -5781,12 +5796,11 @@ vm_fault_t hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
         * If we are going to COW/unshare the mapping later, we examine the
         * pending reservations for this page now. This will ensure that any
         * allocations necessary to record that reservation occur outside the
-        * spinlock. For private mappings, we also lookup the pagecache
-        * page now as it is used to determine if a reservation has been
-        * consumed.
+        * spinlock. Also lookup the pagecache page now as it is used to
+        * determine if a reservation has been consumed.
         */
        if ((flags & (FAULT_FLAG_WRITE|FAULT_FLAG_UNSHARE)) &&
-           !huge_pte_write(entry)) {
+           !(vma->vm_flags & VM_MAYSHARE) && !huge_pte_write(entry)) {
                if (vma_needs_reservation(h, vma, haddr) < 0) {
                        ret = VM_FAULT_OOM;
                        goto out_mutex;
@@ -5794,9 +5808,7 @@ vm_fault_t hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
                /* Just decrements count, does not deallocate */
                vma_end_reservation(h, vma, haddr);
 
-               if (!(vma->vm_flags & VM_MAYSHARE))
-                       pagecache_page = hugetlbfs_pagecache_page(h,
-                                                               vma, haddr);
+               pagecache_page = hugetlbfs_pagecache_page(h, vma, haddr);
        }
 
        ptl = huge_pte_lock(h, mm, ptep);
@@ -6029,7 +6041,7 @@ int hugetlb_mcopy_atomic_pte(struct mm_struct *dst_mm,
        if (!huge_pte_none_mostly(huge_ptep_get(dst_pte)))
                goto out_release_unlock;
 
-       if (vm_shared) {
+       if (page_in_pagecache) {
                page_dup_file_rmap(page, true);
        } else {
                ClearHPageRestoreReserve(page);
index c035020..9d780f4 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1646,8 +1646,11 @@ int vma_wants_writenotify(struct vm_area_struct *vma, pgprot_t vm_page_prot)
            pgprot_val(vm_pgprot_modify(vm_page_prot, vm_flags)))
                return 0;
 
-       /* Do we need to track softdirty? */
-       if (vma_soft_dirty_enabled(vma))
+       /*
+        * Do we need to track softdirty? hugetlb does not support softdirty
+        * tracking yet.
+        */
+       if (vma_soft_dirty_enabled(vma) && !is_vm_hugetlb_page(vma))
                return 1;
 
        /* Specialty mapping? */
index 3a23dde..bc6bddd 100644 (file)
@@ -196,10 +196,11 @@ static unsigned long change_pte_range(struct mmu_gather *tlb,
                        pages++;
                } else if (is_swap_pte(oldpte)) {
                        swp_entry_t entry = pte_to_swp_entry(oldpte);
-                       struct page *page = pfn_swap_entry_to_page(entry);
                        pte_t newpte;
 
                        if (is_writable_migration_entry(entry)) {
+                               struct page *page = pfn_swap_entry_to_page(entry);
+
                                /*
                                 * A protection check is difficult so
                                 * just be safe and disable write
index d0d466a..032a7bf 100644 (file)
@@ -2892,6 +2892,7 @@ static void wb_inode_writeback_start(struct bdi_writeback *wb)
 
 static void wb_inode_writeback_end(struct bdi_writeback *wb)
 {
+       unsigned long flags;
        atomic_dec(&wb->writeback_inodes);
        /*
         * Make sure estimate of writeback throughput gets updated after
@@ -2900,7 +2901,10 @@ static void wb_inode_writeback_end(struct bdi_writeback *wb)
         * that if multiple inodes end writeback at a similar time, they get
         * batched into one bandwidth update.
         */
-       queue_delayed_work(bdi_wq, &wb->bw_dwork, BANDWIDTH_INTERVAL);
+       spin_lock_irqsave(&wb->work_lock, flags);
+       if (test_bit(WB_registered, &wb->state))
+               queue_delayed_work(bdi_wq, &wb->bw_dwork, BANDWIDTH_INTERVAL);
+       spin_unlock_irqrestore(&wb->work_lock, flags);
 }
 
 bool __folio_end_writeback(struct folio *folio)
index 9b3db11..fa7a3d2 100644 (file)
@@ -110,7 +110,7 @@ static int walk_pmd_range(pud_t *pud, unsigned long addr, unsigned long end,
        do {
 again:
                next = pmd_addr_end(addr, end);
-               if (pmd_none(*pmd) || (!walk->vma && !walk->no_vma)) {
+               if (pmd_none(*pmd)) {
                        if (ops->pte_hole)
                                err = ops->pte_hole(addr, next, depth, walk);
                        if (err)
@@ -171,7 +171,7 @@ static int walk_pud_range(p4d_t *p4d, unsigned long addr, unsigned long end,
        do {
  again:
                next = pud_addr_end(addr, end);
-               if (pud_none(*pud) || (!walk->vma && !walk->no_vma)) {
+               if (pud_none(*pud)) {
                        if (ops->pte_hole)
                                err = ops->pte_hole(addr, next, depth, walk);
                        if (err)
@@ -366,19 +366,19 @@ static int __walk_page_range(unsigned long start, unsigned long end,
        struct vm_area_struct *vma = walk->vma;
        const struct mm_walk_ops *ops = walk->ops;
 
-       if (vma && ops->pre_vma) {
+       if (ops->pre_vma) {
                err = ops->pre_vma(start, end, walk);
                if (err)
                        return err;
        }
 
-       if (vma && is_vm_hugetlb_page(vma)) {
+       if (is_vm_hugetlb_page(vma)) {
                if (ops->hugetlb_entry)
                        err = walk_hugetlb_range(start, end, walk);
        } else
                err = walk_pgd_range(start, end, walk);
 
-       if (vma && ops->post_vma)
+       if (ops->post_vma)
                ops->post_vma(walk);
 
        return err;
@@ -450,9 +450,13 @@ int walk_page_range(struct mm_struct *mm, unsigned long start,
                if (!vma) { /* after the last vma */
                        walk.vma = NULL;
                        next = end;
+                       if (ops->pte_hole)
+                               err = ops->pte_hole(start, next, -1, &walk);
                } else if (start < vma->vm_start) { /* outside vma */
                        walk.vma = NULL;
                        next = min(end, vma->vm_start);
+                       if (ops->pte_hole)
+                               err = ops->pte_hole(start, next, -1, &walk);
                } else { /* inside vma */
                        walk.vma = vma;
                        next = min(end, vma->vm_end);
@@ -470,9 +474,8 @@ int walk_page_range(struct mm_struct *mm, unsigned long start,
                        }
                        if (err < 0)
                                break;
-               }
-               if (walk.vma || walk.ops->pte_hole)
                        err = __walk_page_range(start, next, &walk);
+               }
                if (err)
                        break;
        } while (start = next, start < end);
@@ -501,9 +504,9 @@ int walk_page_range_novma(struct mm_struct *mm, unsigned long start,
        if (start >= end || !walk.mm)
                return -EINVAL;
 
-       mmap_assert_locked(walk.mm);
+       mmap_assert_write_locked(walk.mm);
 
-       return __walk_page_range(start, end, &walk);
+       return walk_pgd_range(start, end, &walk);
 }
 
 int walk_page_vma(struct vm_area_struct *vma, const struct mm_walk_ops *ops,
index eea3d28..8adab45 100644 (file)
@@ -152,13 +152,13 @@ void ptdump_walk_pgd(struct ptdump_state *st, struct mm_struct *mm, pgd_t *pgd)
 {
        const struct ptdump_range *range = st->range;
 
-       mmap_read_lock(mm);
+       mmap_write_lock(mm);
        while (range->start != range->end) {
                walk_page_range_novma(mm, range->start, range->end,
                                      &ptdump_ops, pgd, st);
                range++;
        }
-       mmap_read_unlock(mm);
+       mmap_write_unlock(mm);
 
        /* Flush out the last page */
        st->note_page(st, 0, -1, 0);
index edc06c5..93d5a6f 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -93,7 +93,8 @@ static inline struct anon_vma *anon_vma_alloc(void)
        anon_vma = kmem_cache_alloc(anon_vma_cachep, GFP_KERNEL);
        if (anon_vma) {
                atomic_set(&anon_vma->refcount, 1);
-               anon_vma->degree = 1;   /* Reference for first vma */
+               anon_vma->num_children = 0;
+               anon_vma->num_active_vmas = 0;
                anon_vma->parent = anon_vma;
                /*
                 * Initialise the anon_vma root to point to itself. If called
@@ -201,6 +202,7 @@ int __anon_vma_prepare(struct vm_area_struct *vma)
                anon_vma = anon_vma_alloc();
                if (unlikely(!anon_vma))
                        goto out_enomem_free_avc;
+               anon_vma->num_children++; /* self-parent link for new root */
                allocated = anon_vma;
        }
 
@@ -210,8 +212,7 @@ int __anon_vma_prepare(struct vm_area_struct *vma)
        if (likely(!vma->anon_vma)) {
                vma->anon_vma = anon_vma;
                anon_vma_chain_link(vma, avc, anon_vma);
-               /* vma reference or self-parent link for new root */
-               anon_vma->degree++;
+               anon_vma->num_active_vmas++;
                allocated = NULL;
                avc = NULL;
        }
@@ -296,19 +297,19 @@ int anon_vma_clone(struct vm_area_struct *dst, struct vm_area_struct *src)
                anon_vma_chain_link(dst, avc, anon_vma);
 
                /*
-                * Reuse existing anon_vma if its degree lower than two,
-                * that means it has no vma and only one anon_vma child.
+                * Reuse existing anon_vma if it has no vma and only one
+                * anon_vma child.
                 *
-                * Do not choose parent anon_vma, otherwise first child
-                * will always reuse it. Root anon_vma is never reused:
+                * Root anon_vma is never reused:
                 * it has self-parent reference and at least one child.
                 */
                if (!dst->anon_vma && src->anon_vma &&
-                   anon_vma != src->anon_vma && anon_vma->degree < 2)
+                   anon_vma->num_children < 2 &&
+                   anon_vma->num_active_vmas == 0)
                        dst->anon_vma = anon_vma;
        }
        if (dst->anon_vma)
-               dst->anon_vma->degree++;
+               dst->anon_vma->num_active_vmas++;
        unlock_anon_vma_root(root);
        return 0;
 
@@ -358,6 +359,7 @@ int anon_vma_fork(struct vm_area_struct *vma, struct vm_area_struct *pvma)
        anon_vma = anon_vma_alloc();
        if (!anon_vma)
                goto out_error;
+       anon_vma->num_active_vmas++;
        avc = anon_vma_chain_alloc(GFP_KERNEL);
        if (!avc)
                goto out_error_free_anon_vma;
@@ -378,7 +380,7 @@ int anon_vma_fork(struct vm_area_struct *vma, struct vm_area_struct *pvma)
        vma->anon_vma = anon_vma;
        anon_vma_lock_write(anon_vma);
        anon_vma_chain_link(vma, avc, anon_vma);
-       anon_vma->parent->degree++;
+       anon_vma->parent->num_children++;
        anon_vma_unlock_write(anon_vma);
 
        return 0;
@@ -410,7 +412,7 @@ void unlink_anon_vmas(struct vm_area_struct *vma)
                 * to free them outside the lock.
                 */
                if (RB_EMPTY_ROOT(&anon_vma->rb_root.rb_root)) {
-                       anon_vma->parent->degree--;
+                       anon_vma->parent->num_children--;
                        continue;
                }
 
@@ -418,7 +420,7 @@ void unlink_anon_vmas(struct vm_area_struct *vma)
                anon_vma_chain_free(avc);
        }
        if (vma->anon_vma) {
-               vma->anon_vma->degree--;
+               vma->anon_vma->num_active_vmas--;
 
                /*
                 * vma would still be needed after unlink, and anon_vma will be prepared
@@ -436,7 +438,8 @@ void unlink_anon_vmas(struct vm_area_struct *vma)
        list_for_each_entry_safe(avc, next, &vma->anon_vma_chain, same_vma) {
                struct anon_vma *anon_vma = avc->anon_vma;
 
-               VM_WARN_ON(anon_vma->degree);
+               VM_WARN_ON(anon_vma->num_children);
+               VM_WARN_ON(anon_vma->num_active_vmas);
                put_anon_vma(anon_vma);
 
                list_del(&avc->same_vma);
index 5783f11..42e5888 100644 (file)
@@ -1659,7 +1659,9 @@ static int shmem_replace_page(struct page **pagep, gfp_t gfp,
                new = page_folio(newpage);
                mem_cgroup_migrate(old, new);
                __inc_lruvec_page_state(newpage, NR_FILE_PAGES);
+               __inc_lruvec_page_state(newpage, NR_SHMEM);
                __dec_lruvec_page_state(oldpage, NR_FILE_PAGES);
+               __dec_lruvec_page_state(oldpage, NR_SHMEM);
        }
        xa_unlock_irq(&swap_mapping->i_pages);
 
@@ -1780,6 +1782,7 @@ static int shmem_swapin_folio(struct inode *inode, pgoff_t index,
 
        if (shmem_should_replace_folio(folio, gfp)) {
                error = shmem_replace_page(&page, gfp, info, index);
+               folio = page_folio(page);
                if (error)
                        goto failed;
        }
@@ -2281,16 +2284,34 @@ static int shmem_mmap(struct file *file, struct vm_area_struct *vma)
        return 0;
 }
 
-/* Mask out flags that are inappropriate for the given type of inode. */
-static unsigned shmem_mask_flags(umode_t mode, __u32 flags)
+#ifdef CONFIG_TMPFS_XATTR
+static int shmem_initxattrs(struct inode *, const struct xattr *, void *);
+
+/*
+ * chattr's fsflags are unrelated to extended attributes,
+ * but tmpfs has chosen to enable them under the same config option.
+ */
+static void shmem_set_inode_flags(struct inode *inode, unsigned int fsflags)
+{
+       unsigned int i_flags = 0;
+
+       if (fsflags & FS_NOATIME_FL)
+               i_flags |= S_NOATIME;
+       if (fsflags & FS_APPEND_FL)
+               i_flags |= S_APPEND;
+       if (fsflags & FS_IMMUTABLE_FL)
+               i_flags |= S_IMMUTABLE;
+       /*
+        * But FS_NODUMP_FL does not require any action in i_flags.
+        */
+       inode_set_flags(inode, i_flags, S_NOATIME | S_APPEND | S_IMMUTABLE);
+}
+#else
+static void shmem_set_inode_flags(struct inode *inode, unsigned int fsflags)
 {
-       if (S_ISDIR(mode))
-               return flags;
-       else if (S_ISREG(mode))
-               return flags & SHMEM_REG_FLMASK;
-       else
-               return flags & SHMEM_OTHER_FLMASK;
 }
+#define shmem_initxattrs NULL
+#endif
 
 static struct inode *shmem_get_inode(struct super_block *sb, struct inode *dir,
                                     umode_t mode, dev_t dev, unsigned long flags)
@@ -2319,7 +2340,8 @@ static struct inode *shmem_get_inode(struct super_block *sb, struct inode *dir,
                info->i_crtime = inode->i_mtime;
                info->fsflags = (dir == NULL) ? 0 :
                        SHMEM_I(dir)->fsflags & SHMEM_FL_INHERITED;
-               info->fsflags = shmem_mask_flags(mode, info->fsflags);
+               if (info->fsflags)
+                       shmem_set_inode_flags(inode, info->fsflags);
                INIT_LIST_HEAD(&info->shrinklist);
                INIT_LIST_HEAD(&info->swaplist);
                simple_xattrs_init(&info->xattrs);
@@ -2468,12 +2490,6 @@ out_unacct_blocks:
 static const struct inode_operations shmem_symlink_inode_operations;
 static const struct inode_operations shmem_short_symlink_operations;
 
-#ifdef CONFIG_TMPFS_XATTR
-static int shmem_initxattrs(struct inode *, const struct xattr *, void *);
-#else
-#define shmem_initxattrs NULL
-#endif
-
 static int
 shmem_write_begin(struct file *file, struct address_space *mapping,
                        loff_t pos, unsigned len,
@@ -2826,12 +2842,13 @@ static long shmem_fallocate(struct file *file, int mode, loff_t offset,
 
        if (!(mode & FALLOC_FL_KEEP_SIZE) && offset + len > inode->i_size)
                i_size_write(inode, offset + len);
-       inode->i_ctime = current_time(inode);
 undone:
        spin_lock(&inode->i_lock);
        inode->i_private = NULL;
        spin_unlock(&inode->i_lock);
 out:
+       if (!error)
+               file_modified(file);
        inode_unlock(inode);
        return error;
 }
@@ -3179,18 +3196,13 @@ static int shmem_fileattr_set(struct user_namespace *mnt_userns,
 
        if (fileattr_has_fsx(fa))
                return -EOPNOTSUPP;
+       if (fa->flags & ~SHMEM_FL_USER_MODIFIABLE)
+               return -EOPNOTSUPP;
 
        info->fsflags = (info->fsflags & ~SHMEM_FL_USER_MODIFIABLE) |
                (fa->flags & SHMEM_FL_USER_MODIFIABLE);
 
-       inode->i_flags &= ~(S_APPEND | S_IMMUTABLE | S_NOATIME);
-       if (info->fsflags & FS_APPEND_FL)
-               inode->i_flags |= S_APPEND;
-       if (info->fsflags & FS_IMMUTABLE_FL)
-               inode->i_flags |= S_IMMUTABLE;
-       if (info->fsflags & FS_NOATIME_FL)
-               inode->i_flags |= S_NOATIME;
-
+       shmem_set_inode_flags(inode, info->fsflags);
        inode->i_ctime = current_time(inode);
        return 0;
 }
index 1799664..07b9482 100644 (file)
@@ -392,6 +392,28 @@ kmem_cache_create(const char *name, unsigned int size, unsigned int align,
 }
 EXPORT_SYMBOL(kmem_cache_create);
 
+#ifdef SLAB_SUPPORTS_SYSFS
+/*
+ * For a given kmem_cache, kmem_cache_destroy() should only be called
+ * once or there will be a use-after-free problem. The actual deletion
+ * and release of the kobject does not need slab_mutex or cpu_hotplug_lock
+ * protection. So they are now done without holding those locks.
+ *
+ * Note that there will be a slight delay in the deletion of sysfs files
+ * if kmem_cache_release() is called indrectly from a work function.
+ */
+static void kmem_cache_release(struct kmem_cache *s)
+{
+       sysfs_slab_unlink(s);
+       sysfs_slab_release(s);
+}
+#else
+static void kmem_cache_release(struct kmem_cache *s)
+{
+       slab_kmem_cache_release(s);
+}
+#endif
+
 static void slab_caches_to_rcu_destroy_workfn(struct work_struct *work)
 {
        LIST_HEAD(to_destroy);
@@ -418,11 +440,7 @@ static void slab_caches_to_rcu_destroy_workfn(struct work_struct *work)
        list_for_each_entry_safe(s, s2, &to_destroy, list) {
                debugfs_slab_release(s);
                kfence_shutdown_cache(s);
-#ifdef SLAB_SUPPORTS_SYSFS
-               sysfs_slab_release(s);
-#else
-               slab_kmem_cache_release(s);
-#endif
+               kmem_cache_release(s);
        }
 }
 
@@ -437,20 +455,11 @@ static int shutdown_cache(struct kmem_cache *s)
        list_del(&s->list);
 
        if (s->flags & SLAB_TYPESAFE_BY_RCU) {
-#ifdef SLAB_SUPPORTS_SYSFS
-               sysfs_slab_unlink(s);
-#endif
                list_add_tail(&s->list, &slab_caches_to_rcu_destroy);
                schedule_work(&slab_caches_to_rcu_destroy_work);
        } else {
                kfence_shutdown_cache(s);
                debugfs_slab_release(s);
-#ifdef SLAB_SUPPORTS_SYSFS
-               sysfs_slab_unlink(s);
-               sysfs_slab_release(s);
-#else
-               slab_kmem_cache_release(s);
-#endif
        }
 
        return 0;
@@ -465,14 +474,16 @@ void slab_kmem_cache_release(struct kmem_cache *s)
 
 void kmem_cache_destroy(struct kmem_cache *s)
 {
+       int refcnt;
+
        if (unlikely(!s) || !kasan_check_byte(s))
                return;
 
        cpus_read_lock();
        mutex_lock(&slab_mutex);
 
-       s->refcount--;
-       if (s->refcount)
+       refcnt = --s->refcount;
+       if (refcnt)
                goto out_unlock;
 
        WARN(shutdown_cache(s),
@@ -481,6 +492,8 @@ void kmem_cache_destroy(struct kmem_cache *s)
 out_unlock:
        mutex_unlock(&slab_mutex);
        cpus_read_unlock();
+       if (!refcnt && !(s->flags & SLAB_TYPESAFE_BY_RCU))
+               kmem_cache_release(s);
 }
 EXPORT_SYMBOL(kmem_cache_destroy);
 
index 07d3bef..7327b25 100644 (file)
@@ -703,14 +703,29 @@ ssize_t mcopy_continue(struct mm_struct *dst_mm, unsigned long start,
                              mmap_changing, 0);
 }
 
+void uffd_wp_range(struct mm_struct *dst_mm, struct vm_area_struct *dst_vma,
+                  unsigned long start, unsigned long len, bool enable_wp)
+{
+       struct mmu_gather tlb;
+       pgprot_t newprot;
+
+       if (enable_wp)
+               newprot = vm_get_page_prot(dst_vma->vm_flags & ~(VM_WRITE));
+       else
+               newprot = vm_get_page_prot(dst_vma->vm_flags);
+
+       tlb_gather_mmu(&tlb, dst_mm);
+       change_protection(&tlb, dst_vma, start, start + len, newprot,
+                         enable_wp ? MM_CP_UFFD_WP : MM_CP_UFFD_WP_RESOLVE);
+       tlb_finish_mmu(&tlb);
+}
+
 int mwriteprotect_range(struct mm_struct *dst_mm, unsigned long start,
                        unsigned long len, bool enable_wp,
                        atomic_t *mmap_changing)
 {
        struct vm_area_struct *dst_vma;
        unsigned long page_mask;
-       struct mmu_gather tlb;
-       pgprot_t newprot;
        int err;
 
        /*
@@ -750,15 +765,7 @@ int mwriteprotect_range(struct mm_struct *dst_mm, unsigned long start,
                        goto out_unlock;
        }
 
-       if (enable_wp)
-               newprot = vm_get_page_prot(dst_vma->vm_flags & ~(VM_WRITE));
-       else
-               newprot = vm_get_page_prot(dst_vma->vm_flags);
-
-       tlb_gather_mmu(&tlb, dst_mm);
-       change_protection(&tlb, dst_vma, start, start + len, newprot,
-                         enable_wp ? MM_CP_UFFD_WP : MM_CP_UFFD_WP_RESOLVE);
-       tlb_finish_mmu(&tlb);
+       uffd_wp_range(dst_mm, dst_vma, start, len, enable_wp);
 
        err = 0;
 out_unlock:
index 373d273..90af9a8 100644 (file)
@@ -1168,8 +1168,15 @@ int fragmentation_index(struct zone *zone, unsigned int order)
 #define TEXT_FOR_HIGHMEM(xx)
 #endif
 
+#ifdef CONFIG_ZONE_DEVICE
+#define TEXT_FOR_DEVICE(xx) xx "_device",
+#else
+#define TEXT_FOR_DEVICE(xx)
+#endif
+
 #define TEXTS_FOR_ZONES(xx) TEXT_FOR_DMA(xx) TEXT_FOR_DMA32(xx) xx "_normal", \
-                                       TEXT_FOR_HIGHMEM(xx) xx "_movable",
+                                       TEXT_FOR_HIGHMEM(xx) xx "_movable", \
+                                       TEXT_FOR_DEVICE(xx)
 
 const char * const vmstat_text[] = {
        /* enum zone_stat_item counters */
index 34f784a..907c9b1 100644 (file)
@@ -1487,7 +1487,7 @@ void zs_free(struct zs_pool *pool, unsigned long handle)
        struct size_class *class;
        enum fullness_group fullness;
 
-       if (unlikely(!handle))
+       if (IS_ERR_OR_NULL((void *)handle))
                return;
 
        /*
index 485c814..6643c9c 100644 (file)
@@ -4179,6 +4179,17 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, void *data,
                }
        }
 
+       if (i == ARRAY_SIZE(hci_cc_table)) {
+               /* Unknown opcode, assume byte 0 contains the status, so
+                * that e.g. __hci_cmd_sync() properly returns errors
+                * for vendor specific commands send by HCI drivers.
+                * If a vendor doesn't actually follow this convention we may
+                * need to introduce a vendor CC table in order to properly set
+                * the status.
+                */
+               *status = skb->data[0];
+       }
+
        handle_cmd_cnt_and_timer(hdev, ev->ncmd);
 
        hci_req_cmd_complete(hdev, *opcode, *status, req_complete,
@@ -5790,7 +5801,7 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
         */
        hci_dev_clear_flag(hdev, HCI_LE_ADV);
 
-       conn = hci_lookup_le_connect(hdev);
+       conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
        if (!conn) {
                /* In case of error status and there is no connection pending
                 * just unlock as there is nothing to cleanup.
index e6d804b..fbd5613 100644 (file)
@@ -3018,12 +3018,6 @@ static const struct hci_init_stage amp_init2[] = {
 /* Read Buffer Size (ACL mtu, max pkt, etc.) */
 static int hci_read_buffer_size_sync(struct hci_dev *hdev)
 {
-       /* Use Read LE Buffer Size V2 if supported */
-       if (hdev->commands[41] & 0x20)
-               return __hci_cmd_sync_status(hdev,
-                                            HCI_OP_LE_READ_BUFFER_SIZE_V2,
-                                            0, NULL, HCI_CMD_TIMEOUT);
-
        return __hci_cmd_sync_status(hdev, HCI_OP_READ_BUFFER_SIZE,
                                     0, NULL, HCI_CMD_TIMEOUT);
 }
@@ -3237,6 +3231,12 @@ static const struct hci_init_stage hci_init2[] = {
 /* Read LE Buffer Size */
 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)
+               return __hci_cmd_sync_status(hdev,
+                                            HCI_OP_LE_READ_BUFFER_SIZE_V2,
+                                            0, NULL, HCI_CMD_TIMEOUT);
+
        return __hci_cmd_sync_status(hdev, HCI_OP_LE_READ_BUFFER_SIZE,
                                     0, NULL, HCI_CMD_TIMEOUT);
 }
@@ -4773,9 +4773,11 @@ int hci_abort_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, u8 reason)
                /* Cleanup hci_conn object if it cannot be cancelled as it
                 * likelly means the controller and host stack are out of sync.
                 */
-               if (err)
+               if (err) {
+                       hci_dev_lock(hdev);
                        hci_conn_failed(conn, err);
-
+                       hci_dev_unlock(hdev);
+               }
                return err;
        case BT_CONNECT2:
                return hci_reject_conn_sync(hdev, conn, reason);
@@ -5288,17 +5290,21 @@ int hci_suspend_sync(struct hci_dev *hdev)
        /* Prevent disconnects from causing scanning to be re-enabled */
        hci_pause_scan_sync(hdev);
 
-       /* Soft disconnect everything (power off) */
-       err = hci_disconnect_all_sync(hdev, HCI_ERROR_REMOTE_POWER_OFF);
-       if (err) {
-               /* Set state to BT_RUNNING so resume doesn't notify */
-               hdev->suspend_state = BT_RUNNING;
-               hci_resume_sync(hdev);
-               return err;
-       }
+       if (hci_conn_count(hdev)) {
+               /* Soft disconnect everything (power off) */
+               err = hci_disconnect_all_sync(hdev, HCI_ERROR_REMOTE_POWER_OFF);
+               if (err) {
+                       /* Set state to BT_RUNNING so resume doesn't notify */
+                       hdev->suspend_state = BT_RUNNING;
+                       hci_resume_sync(hdev);
+                       return err;
+               }
 
-       /* Update event mask so only the allowed event can wakeup the host */
-       hci_set_event_mask_sync(hdev);
+               /* Update event mask so only the allowed event can wakeup the
+                * host.
+                */
+               hci_set_event_mask_sync(hdev);
+       }
 
        /* Only configure accept list if disconnect succeeded and wake
         * isn't being prevented.
index 5940744..cc20e70 100644 (file)
@@ -83,14 +83,14 @@ static void hidp_copy_session(struct hidp_session *session, struct hidp_conninfo
                ci->product = session->input->id.product;
                ci->version = session->input->id.version;
                if (session->input->name)
-                       strlcpy(ci->name, session->input->name, 128);
+                       strscpy(ci->name, session->input->name, 128);
                else
-                       strlcpy(ci->name, "HID Boot Device", 128);
+                       strscpy(ci->name, "HID Boot Device", 128);
        } else if (session->hid) {
                ci->vendor  = session->hid->vendor;
                ci->product = session->hid->product;
                ci->version = session->hid->version;
-               strlcpy(ci->name, session->hid->name, 128);
+               strscpy(ci->name, session->hid->name, 128);
        }
 }
 
index ced8ad4..613039b 100644 (file)
@@ -1309,7 +1309,7 @@ static int iso_sock_shutdown(struct socket *sock, int how)
        struct sock *sk = sock->sk;
        int err = 0;
 
-       BT_DBG("sock %p, sk %p", sock, sk);
+       BT_DBG("sock %p, sk %p, how %d", sock, sk, how);
 
        if (!sk)
                return 0;
@@ -1317,17 +1317,32 @@ static int iso_sock_shutdown(struct socket *sock, int how)
        sock_hold(sk);
        lock_sock(sk);
 
-       if (!sk->sk_shutdown) {
-               sk->sk_shutdown = SHUTDOWN_MASK;
-               iso_sock_clear_timer(sk);
-               __iso_sock_close(sk);
-
-               if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime &&
-                   !(current->flags & PF_EXITING))
-                       err = bt_sock_wait_state(sk, BT_CLOSED,
-                                                sk->sk_lingertime);
+       switch (how) {
+       case SHUT_RD:
+               if (sk->sk_shutdown & RCV_SHUTDOWN)
+                       goto unlock;
+               sk->sk_shutdown |= RCV_SHUTDOWN;
+               break;
+       case SHUT_WR:
+               if (sk->sk_shutdown & SEND_SHUTDOWN)
+                       goto unlock;
+               sk->sk_shutdown |= SEND_SHUTDOWN;
+               break;
+       case SHUT_RDWR:
+               if (sk->sk_shutdown & SHUTDOWN_MASK)
+                       goto unlock;
+               sk->sk_shutdown |= SHUTDOWN_MASK;
+               break;
        }
 
+       iso_sock_clear_timer(sk);
+       __iso_sock_close(sk);
+
+       if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime &&
+           !(current->flags & PF_EXITING))
+               err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime);
+
+unlock:
        release_sock(sk);
        sock_put(sk);
 
index cbe0cae..2c9de67 100644 (file)
@@ -1992,11 +1992,11 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm,
                        src_match = !bacmp(&c->src, src);
                        dst_match = !bacmp(&c->dst, dst);
                        if (src_match && dst_match) {
-                               c = l2cap_chan_hold_unless_zero(c);
-                               if (c) {
-                                       read_unlock(&chan_list_lock);
-                                       return c;
-                               }
+                               if (!l2cap_chan_hold_unless_zero(c))
+                                       continue;
+
+                               read_unlock(&chan_list_lock);
+                               return c;
                        }
 
                        /* Closest match */
index 6e31023..72e6595 100644 (file)
@@ -4547,6 +4547,22 @@ static int set_exp_feature(struct sock *sk, struct hci_dev *hdev,
                               MGMT_STATUS_NOT_SUPPORTED);
 }
 
+static u32 get_params_flags(struct hci_dev *hdev,
+                           struct hci_conn_params *params)
+{
+       u32 flags = hdev->conn_flags;
+
+       /* Devices using RPAs can only be programmed in the acceptlist if
+        * LL Privacy has been enable otherwise they cannot mark
+        * HCI_CONN_FLAG_REMOTE_WAKEUP.
+        */
+       if ((flags & HCI_CONN_FLAG_REMOTE_WAKEUP) && !use_ll_privacy(hdev) &&
+           hci_find_irk_by_addr(hdev, &params->addr, params->addr_type))
+               flags &= ~HCI_CONN_FLAG_REMOTE_WAKEUP;
+
+       return flags;
+}
+
 static int get_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
                            u16 data_len)
 {
@@ -4578,10 +4594,10 @@ static int get_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
        } else {
                params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
                                                le_addr_type(cp->addr.type));
-
                if (!params)
                        goto done;
 
+               supported_flags = get_params_flags(hdev, params);
                current_flags = params->flags;
        }
 
@@ -4649,38 +4665,35 @@ static int set_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
                        bt_dev_warn(hdev, "No such BR/EDR device %pMR (0x%x)",
                                    &cp->addr.bdaddr, cp->addr.type);
                }
-       } else {
-               params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
-                                               le_addr_type(cp->addr.type));
-               if (params) {
-                       /* Devices using RPAs can only be programmed in the
-                        * acceptlist LL Privacy has been enable otherwise they
-                        * cannot mark HCI_CONN_FLAG_REMOTE_WAKEUP.
-                        */
-                       if ((current_flags & HCI_CONN_FLAG_REMOTE_WAKEUP) &&
-                           !use_ll_privacy(hdev) &&
-                           hci_find_irk_by_addr(hdev, &params->addr,
-                                                params->addr_type)) {
-                               bt_dev_warn(hdev,
-                                           "Cannot set wakeable for RPA");
-                               goto unlock;
-                       }
 
-                       params->flags = current_flags;
-                       status = MGMT_STATUS_SUCCESS;
+               goto unlock;
+       }
 
-                       /* Update passive scan if HCI_CONN_FLAG_DEVICE_PRIVACY
-                        * has been set.
-                        */
-                       if (params->flags & HCI_CONN_FLAG_DEVICE_PRIVACY)
-                               hci_update_passive_scan(hdev);
-               } else {
-                       bt_dev_warn(hdev, "No such LE device %pMR (0x%x)",
-                                   &cp->addr.bdaddr,
-                                   le_addr_type(cp->addr.type));
-               }
+       params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
+                                       le_addr_type(cp->addr.type));
+       if (!params) {
+               bt_dev_warn(hdev, "No such LE device %pMR (0x%x)",
+                           &cp->addr.bdaddr, le_addr_type(cp->addr.type));
+               goto unlock;
        }
 
+       supported_flags = get_params_flags(hdev, params);
+
+       if ((supported_flags | current_flags) != supported_flags) {
+               bt_dev_warn(hdev, "Bad flag given (0x%x) vs supported (0x%0x)",
+                           current_flags, supported_flags);
+               goto unlock;
+       }
+
+       params->flags = current_flags;
+       status = MGMT_STATUS_SUCCESS;
+
+       /* Update passive scan if HCI_CONN_FLAG_DEVICE_PRIVACY
+        * has been set.
+        */
+       if (params->flags & HCI_CONN_FLAG_DEVICE_PRIVACY)
+               hci_update_passive_scan(hdev);
+
 unlock:
        hci_dev_unlock(hdev);
 
@@ -5054,7 +5067,6 @@ static int remove_adv_monitor(struct sock *sk, struct hci_dev *hdev,
                else
                        status = MGMT_STATUS_FAILED;
 
-               mgmt_pending_remove(cmd);
                goto unlock;
        }
 
index ff47790..f20f437 100644 (file)
@@ -384,6 +384,7 @@ static int br_nf_pre_routing_finish(struct net *net, struct sock *sk, struct sk_
                                /* - Bridged-and-DNAT'ed traffic doesn't
                                 *   require ip_forwarding. */
                                if (rt->dst.dev == dev) {
+                                       skb_dst_drop(skb);
                                        skb_dst_set(skb, &rt->dst);
                                        goto bridged_dnat;
                                }
@@ -413,6 +414,7 @@ bridged_dnat:
                        kfree_skb(skb);
                        return 0;
                }
+               skb_dst_drop(skb);
                skb_dst_set_noref(skb, &rt->dst);
        }
 
index e4e0c83..6b07f30 100644 (file)
@@ -197,6 +197,7 @@ static int br_nf_pre_routing_finish_ipv6(struct net *net, struct sock *sk, struc
                        kfree_skb(skb);
                        return 0;
                }
+               skb_dst_drop(skb);
                skb_dst_set_noref(skb, &rt->dst);
        }
 
index 1a11064..8f19253 100644 (file)
@@ -36,18 +36,10 @@ static struct ebt_replace_kernel initial_table = {
        .entries        = (char *)&initial_chain,
 };
 
-static int check(const struct ebt_table_info *info, unsigned int valid_hooks)
-{
-       if (valid_hooks & ~(1 << NF_BR_BROUTING))
-               return -EINVAL;
-       return 0;
-}
-
 static const struct ebt_table broute_table = {
        .name           = "broute",
        .table          = &initial_table,
        .valid_hooks    = 1 << NF_BR_BROUTING,
-       .check          = check,
        .me             = THIS_MODULE,
 };
 
index cb94943..278f324 100644 (file)
@@ -43,18 +43,10 @@ static struct ebt_replace_kernel initial_table = {
        .entries        = (char *)initial_chains,
 };
 
-static int check(const struct ebt_table_info *info, unsigned int valid_hooks)
-{
-       if (valid_hooks & ~FILTER_VALID_HOOKS)
-               return -EINVAL;
-       return 0;
-}
-
 static const struct ebt_table frame_filter = {
        .name           = "filter",
        .table          = &initial_table,
        .valid_hooks    = FILTER_VALID_HOOKS,
-       .check          = check,
        .me             = THIS_MODULE,
 };
 
index 5ee0531..9066f7f 100644 (file)
@@ -43,18 +43,10 @@ static struct ebt_replace_kernel initial_table = {
        .entries        = (char *)initial_chains,
 };
 
-static int check(const struct ebt_table_info *info, unsigned int valid_hooks)
-{
-       if (valid_hooks & ~NAT_VALID_HOOKS)
-               return -EINVAL;
-       return 0;
-}
-
 static const struct ebt_table frame_nat = {
        .name           = "nat",
        .table          = &initial_table,
        .valid_hooks    = NAT_VALID_HOOKS,
-       .check          = check,
        .me             = THIS_MODULE,
 };
 
index f2dbefb..9a0ae59 100644 (file)
@@ -1040,8 +1040,7 @@ static int do_replace_finish(struct net *net, struct ebt_replace *repl,
                goto free_iterate;
        }
 
-       /* the table doesn't like it */
-       if (t->check && (ret = t->check(newinfo, repl->valid_hooks)))
+       if (repl->valid_hooks != t->valid_hooks)
                goto free_unlock;
 
        if (repl->num_counters && repl->num_counters != t->private->nentries) {
@@ -1231,11 +1230,6 @@ int ebt_register_table(struct net *net, const struct ebt_table *input_table,
        if (ret != 0)
                goto free_chainstack;
 
-       if (table->check && table->check(newinfo, table->valid_hooks)) {
-               ret = -EINVAL;
-               goto free_chainstack;
-       }
-
        table->private = newinfo;
        rwlock_init(&table->lock);
        mutex_lock(&ebt_mutex);
diff --git a/net/core/.gitignore b/net/core/.gitignore
deleted file mode 100644 (file)
index df1e743..0000000
+++ /dev/null
@@ -1 +0,0 @@
-dropreason_str.c
index e8ce3bd..5857cec 100644 (file)
@@ -5,7 +5,7 @@
 
 obj-y := sock.o request_sock.o skbuff.o datagram.o stream.o scm.o \
         gen_stats.o gen_estimator.o net_namespace.o secure_seq.o \
-        flow_dissector.o dropreason_str.o
+        flow_dissector.o
 
 obj-$(CONFIG_SYSCTL) += sysctl_net_core.o
 
@@ -40,23 +40,3 @@ obj-$(CONFIG_NET_SOCK_MSG) += skmsg.o
 obj-$(CONFIG_BPF_SYSCALL) += sock_map.o
 obj-$(CONFIG_BPF_SYSCALL) += bpf_sk_storage.o
 obj-$(CONFIG_OF)       += of_net.o
-
-clean-files := dropreason_str.c
-
-quiet_cmd_dropreason_str = GEN     $@
-cmd_dropreason_str = awk -F ',' 'BEGIN{ print "\#include <net/dropreason.h>\n"; \
-       print "const char * const drop_reasons[] = {" }\
-       /^enum skb_drop/ { dr=1; }\
-       /^\};/ { dr=0; }\
-       /^\tSKB_DROP_REASON_/ {\
-               if (dr) {\
-                       sub(/\tSKB_DROP_REASON_/, "", $$1);\
-                       printf "\t[SKB_DROP_REASON_%s] = \"%s\",\n", $$1, $$1;\
-               }\
-       }\
-       END{ print "};" }' $< > $@
-
-$(obj)/dropreason_str.c: $(srctree)/include/net/dropreason.h
-       $(call cmd,dropreason_str)
-
-$(obj)/dropreason_str.o: $(obj)/dropreason_str.c
index 1b7f385..94374d5 100644 (file)
@@ -310,11 +310,12 @@ BPF_CALL_2(bpf_sk_storage_delete, struct bpf_map *, map, struct sock *, sk)
 static int bpf_sk_storage_charge(struct bpf_local_storage_map *smap,
                                 void *owner, u32 size)
 {
+       int optmem_max = READ_ONCE(sysctl_optmem_max);
        struct sock *sk = (struct sock *)owner;
 
        /* same check as in sock_kmalloc() */
-       if (size <= sysctl_optmem_max &&
-           atomic_read(&sk->sk_omem_alloc) + size < sysctl_optmem_max) {
+       if (size <= optmem_max &&
+           atomic_read(&sk->sk_omem_alloc) + size < optmem_max) {
                atomic_add(size, &sk->sk_omem_alloc);
                return 0;
        }
index 7255531..e4ff2db 100644 (file)
@@ -677,7 +677,7 @@ int __zerocopy_sg_from_iter(struct msghdr *msg, struct sock *sk,
                                page_ref_sub(last_head, refs);
                                refs = 0;
                        }
-                       skb_fill_page_desc(skb, frag++, head, start, size);
+                       skb_fill_page_desc_noacc(skb, frag++, head, start, size);
                }
                if (refs)
                        page_ref_sub(last_head, refs);
index 716df64..56c8b09 100644 (file)
@@ -4624,7 +4624,7 @@ static bool skb_flow_limit(struct sk_buff *skb, unsigned int qlen)
        struct softnet_data *sd;
        unsigned int old_flow, new_flow;
 
-       if (qlen < (netdev_max_backlog >> 1))
+       if (qlen < (READ_ONCE(netdev_max_backlog) >> 1))
                return false;
 
        sd = this_cpu_ptr(&softnet_data);
@@ -4672,7 +4672,7 @@ static int enqueue_to_backlog(struct sk_buff *skb, int cpu,
        if (!netif_running(skb->dev))
                goto drop;
        qlen = skb_queue_len(&sd->input_pkt_queue);
-       if (qlen <= netdev_max_backlog && !skb_flow_limit(skb, qlen)) {
+       if (qlen <= READ_ONCE(netdev_max_backlog) && !skb_flow_limit(skb, qlen)) {
                if (qlen) {
 enqueue:
                        __skb_queue_tail(&sd->input_pkt_queue, skb);
@@ -4928,7 +4928,7 @@ static int netif_rx_internal(struct sk_buff *skb)
 {
        int ret;
 
-       net_timestamp_check(netdev_tstamp_prequeue, skb);
+       net_timestamp_check(READ_ONCE(netdev_tstamp_prequeue), skb);
 
        trace_netif_rx(skb);
 
@@ -5281,7 +5281,7 @@ static int __netif_receive_skb_core(struct sk_buff **pskb, bool pfmemalloc,
        int ret = NET_RX_DROP;
        __be16 type;
 
-       net_timestamp_check(!netdev_tstamp_prequeue, skb);
+       net_timestamp_check(!READ_ONCE(netdev_tstamp_prequeue), skb);
 
        trace_netif_receive_skb(skb);
 
@@ -5664,7 +5664,7 @@ static int netif_receive_skb_internal(struct sk_buff *skb)
 {
        int ret;
 
-       net_timestamp_check(netdev_tstamp_prequeue, skb);
+       net_timestamp_check(READ_ONCE(netdev_tstamp_prequeue), skb);
 
        if (skb_defer_rx_timestamp(skb))
                return NET_RX_SUCCESS;
@@ -5694,7 +5694,7 @@ void netif_receive_skb_list_internal(struct list_head *head)
 
        INIT_LIST_HEAD(&sublist);
        list_for_each_entry_safe(skb, next, head, list) {
-               net_timestamp_check(netdev_tstamp_prequeue, skb);
+               net_timestamp_check(READ_ONCE(netdev_tstamp_prequeue), skb);
                skb_list_del_init(skb);
                if (!skb_defer_rx_timestamp(skb))
                        list_add_tail(&skb->list, &sublist);
@@ -5918,7 +5918,7 @@ static int process_backlog(struct napi_struct *napi, int quota)
                net_rps_action_and_irq_enable(sd);
        }
 
-       napi->weight = dev_rx_weight;
+       napi->weight = READ_ONCE(dev_rx_weight);
        while (again) {
                struct sk_buff *skb;
 
@@ -6665,8 +6665,8 @@ static __latent_entropy void net_rx_action(struct softirq_action *h)
 {
        struct softnet_data *sd = this_cpu_ptr(&softnet_data);
        unsigned long time_limit = jiffies +
-               usecs_to_jiffies(netdev_budget_usecs);
-       int budget = netdev_budget;
+               usecs_to_jiffies(READ_ONCE(netdev_budget_usecs));
+       int budget = READ_ONCE(netdev_budget);
        LIST_HEAD(list);
        LIST_HEAD(repoll);
 
@@ -10284,7 +10284,7 @@ static struct net_device *netdev_wait_allrefs_any(struct list_head *list)
                                return dev;
 
                if (time_after(jiffies, warning_time +
-                              netdev_unregister_timeout_secs * HZ)) {
+                              READ_ONCE(netdev_unregister_timeout_secs) * HZ)) {
                        list_for_each_entry(dev, list, todo_list) {
                                pr_emerg("unregister_netdevice: waiting for %s to become free. Usage count = %d\n",
                                         dev->name, netdev_refcnt_read(dev));
index e8508aa..c191db8 100644 (file)
@@ -1214,10 +1214,11 @@ void sk_filter_uncharge(struct sock *sk, struct sk_filter *fp)
 static bool __sk_filter_charge(struct sock *sk, struct sk_filter *fp)
 {
        u32 filter_size = bpf_prog_size(fp->prog->len);
+       int optmem_max = READ_ONCE(sysctl_optmem_max);
 
        /* same check as in sock_kmalloc() */
-       if (filter_size <= sysctl_optmem_max &&
-           atomic_read(&sk->sk_omem_alloc) + filter_size < sysctl_optmem_max) {
+       if (filter_size <= optmem_max &&
+           atomic_read(&sk->sk_omem_alloc) + filter_size < optmem_max) {
                atomic_add(filter_size, &sk->sk_omem_alloc);
                return true;
        }
@@ -1548,7 +1549,7 @@ int sk_reuseport_attach_filter(struct sock_fprog *fprog, struct sock *sk)
        if (IS_ERR(prog))
                return PTR_ERR(prog);
 
-       if (bpf_prog_size(prog->len) > sysctl_optmem_max)
+       if (bpf_prog_size(prog->len) > READ_ONCE(sysctl_optmem_max))
                err = -ENOMEM;
        else
                err = reuseport_attach_prog(sk, prog);
@@ -1615,7 +1616,7 @@ int sk_reuseport_attach_bpf(u32 ufd, struct sock *sk)
                }
        } else {
                /* BPF_PROG_TYPE_SOCKET_FILTER */
-               if (bpf_prog_size(prog->len) > sysctl_optmem_max) {
+               if (bpf_prog_size(prog->len) > READ_ONCE(sysctl_optmem_max)) {
                        err = -ENOMEM;
                        goto err_prog_put;
                }
@@ -5034,14 +5035,14 @@ static int __bpf_setsockopt(struct sock *sk, int level, int optname,
                /* Only some socketops are supported */
                switch (optname) {
                case SO_RCVBUF:
-                       val = min_t(u32, val, sysctl_rmem_max);
+                       val = min_t(u32, val, READ_ONCE(sysctl_rmem_max));
                        val = min_t(int, val, INT_MAX / 2);
                        sk->sk_userlocks |= SOCK_RCVBUF_LOCK;
                        WRITE_ONCE(sk->sk_rcvbuf,
                                   max_t(int, val * 2, SOCK_MIN_RCVBUF));
                        break;
                case SO_SNDBUF:
-                       val = min_t(u32, val, sysctl_wmem_max);
+                       val = min_t(u32, val, READ_ONCE(sysctl_wmem_max));
                        val = min_t(int, val, INT_MAX / 2);
                        sk->sk_userlocks |= SOCK_SNDBUF_LOCK;
                        WRITE_ONCE(sk->sk_sndbuf,
index a10335b..c8d137e 100644 (file)
@@ -345,7 +345,7 @@ static void gnet_stats_add_queue_cpu(struct gnet_stats_queue *qstats,
        for_each_possible_cpu(i) {
                const struct gnet_stats_queue *qcpu = per_cpu_ptr(q, i);
 
-               qstats->qlen += qcpu->backlog;
+               qstats->qlen += qcpu->qlen;
                qstats->backlog += qcpu->backlog;
                qstats->drops += qcpu->drops;
                qstats->requeues += qcpu->requeues;
index 541c7a7..21619c7 100644 (file)
@@ -26,7 +26,7 @@ int gro_cells_receive(struct gro_cells *gcells, struct sk_buff *skb)
 
        cell = this_cpu_ptr(gcells->cells);
 
-       if (skb_queue_len(&cell->napi_skbs) > netdev_max_backlog) {
+       if (skb_queue_len(&cell->napi_skbs) > READ_ONCE(netdev_max_backlog)) {
 drop:
                dev_core_stats_rx_dropped_inc(dev);
                kfree_skb(skb);
index 6a8c259..78cc8fb 100644 (file)
@@ -307,11 +307,35 @@ static int neigh_del_timer(struct neighbour *n)
        return 0;
 }
 
-static void pneigh_queue_purge(struct sk_buff_head *list)
+static void pneigh_queue_purge(struct sk_buff_head *list, struct net *net)
 {
+       struct sk_buff_head tmp;
+       unsigned long flags;
        struct sk_buff *skb;
 
-       while ((skb = skb_dequeue(list)) != NULL) {
+       skb_queue_head_init(&tmp);
+       spin_lock_irqsave(&list->lock, flags);
+       skb = skb_peek(list);
+       while (skb != NULL) {
+               struct sk_buff *skb_next = skb_peek_next(skb, list);
+               struct net_device *dev = skb->dev;
+
+               if (net == NULL || net_eq(dev_net(dev), net)) {
+                       struct in_device *in_dev;
+
+                       rcu_read_lock();
+                       in_dev = __in_dev_get_rcu(dev);
+                       if (in_dev)
+                               in_dev->arp_parms->qlen--;
+                       rcu_read_unlock();
+                       __skb_unlink(skb, list);
+                       __skb_queue_tail(&tmp, skb);
+               }
+               skb = skb_next;
+       }
+       spin_unlock_irqrestore(&list->lock, flags);
+
+       while ((skb = __skb_dequeue(&tmp))) {
                dev_put(skb->dev);
                kfree_skb(skb);
        }
@@ -385,9 +409,9 @@ static int __neigh_ifdown(struct neigh_table *tbl, struct net_device *dev,
        write_lock_bh(&tbl->lock);
        neigh_flush_dev(tbl, dev, skip_perm);
        pneigh_ifdown_and_unlock(tbl, dev);
-
-       del_timer_sync(&tbl->proxy_timer);
-       pneigh_queue_purge(&tbl->proxy_queue);
+       pneigh_queue_purge(&tbl->proxy_queue, dev_net(dev));
+       if (skb_queue_empty_lockless(&tbl->proxy_queue))
+               del_timer_sync(&tbl->proxy_timer);
        return 0;
 }
 
@@ -1597,8 +1621,15 @@ static void neigh_proxy_process(struct timer_list *t)
 
                if (tdif <= 0) {
                        struct net_device *dev = skb->dev;
+                       struct in_device *in_dev;
 
+                       rcu_read_lock();
+                       in_dev = __in_dev_get_rcu(dev);
+                       if (in_dev)
+                               in_dev->arp_parms->qlen--;
+                       rcu_read_unlock();
                        __skb_unlink(skb, &tbl->proxy_queue);
+
                        if (tbl->proxy_redo && netif_running(dev)) {
                                rcu_read_lock();
                                tbl->proxy_redo(skb);
@@ -1623,7 +1654,7 @@ void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
        unsigned long sched_next = jiffies +
                        prandom_u32_max(NEIGH_VAR(p, PROXY_DELAY));
 
-       if (tbl->proxy_queue.qlen > NEIGH_VAR(p, PROXY_QLEN)) {
+       if (p->qlen > NEIGH_VAR(p, PROXY_QLEN)) {
                kfree_skb(skb);
                return;
        }
@@ -1639,6 +1670,7 @@ void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
        skb_dst_drop(skb);
        dev_hold(skb->dev);
        __skb_queue_tail(&tbl->proxy_queue, skb);
+       p->qlen++;
        mod_timer(&tbl->proxy_timer, sched_next);
        spin_unlock(&tbl->proxy_queue.lock);
 }
@@ -1671,6 +1703,7 @@ struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
                refcount_set(&p->refcnt, 1);
                p->reachable_time =
                                neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
+               p->qlen = 0;
                netdev_hold(dev, &p->dev_tracker, GFP_KERNEL);
                p->dev = dev;
                write_pnet(&p->net, net);
@@ -1736,6 +1769,7 @@ void neigh_table_init(int index, struct neigh_table *tbl)
        refcount_set(&tbl->parms.refcnt, 1);
        tbl->parms.reachable_time =
                          neigh_rand_reach_time(NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME));
+       tbl->parms.qlen = 0;
 
        tbl->stats = alloc_percpu(struct neigh_statistics);
        if (!tbl->stats)
@@ -1787,7 +1821,7 @@ int neigh_table_clear(int index, struct neigh_table *tbl)
        cancel_delayed_work_sync(&tbl->managed_work);
        cancel_delayed_work_sync(&tbl->gc_work);
        del_timer_sync(&tbl->proxy_timer);
-       pneigh_queue_purge(&tbl->proxy_queue);
+       pneigh_queue_purge(&tbl->proxy_queue, NULL);
        neigh_ifdown(tbl, NULL);
        if (atomic_read(&tbl->entries))
                pr_crit("neighbour leakage\n");
index ac45328..4b5b15c 100644 (file)
@@ -6070,6 +6070,7 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
        if (kind == RTNL_KIND_DEL && (nlh->nlmsg_flags & NLM_F_BULK) &&
            !(flags & RTNL_FLAG_BULK_DEL_SUPPORTED)) {
                NL_SET_ERR_MSG(extack, "Bulk delete is not supported");
+               module_put(owner);
                goto err_unlock;
        }
 
index 974bbbb..417463d 100644 (file)
@@ -91,7 +91,11 @@ static struct kmem_cache *skbuff_ext_cache __ro_after_init;
 int sysctl_max_skb_frags __read_mostly = MAX_SKB_FRAGS;
 EXPORT_SYMBOL(sysctl_max_skb_frags);
 
-/* The array 'drop_reasons' is auto-generated in dropreason_str.c */
+#undef FN
+#define FN(reason) [SKB_DROP_REASON_##reason] = #reason,
+const char * const drop_reasons[] = {
+       DEFINE_DROP_REASON(FN, FN)
+};
 EXPORT_SYMBOL(drop_reasons);
 
 /**
@@ -4205,9 +4209,8 @@ normal:
                                SKB_GSO_CB(nskb)->csum_start =
                                        skb_headroom(nskb) + doffset;
                        } else {
-                               skb_copy_bits(head_skb, offset,
-                                             skb_put(nskb, len),
-                                             len);
+                               if (skb_copy_bits(head_skb, offset, skb_put(nskb, len), len))
+                                       goto err;
                        }
                        continue;
                }
@@ -4798,7 +4801,7 @@ static bool skb_may_tx_timestamp(struct sock *sk, bool tsonly)
 {
        bool ret;
 
-       if (likely(sysctl_tstamp_allow_data || tsonly))
+       if (likely(READ_ONCE(sysctl_tstamp_allow_data) || tsonly))
                return true;
 
        read_lock_bh(&sk->sk_callback_lock);
index f47338d..188f855 100644 (file)
@@ -461,7 +461,7 @@ int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg,
 
                        if (copied == len)
                                break;
-               } while (!sg_is_last(sge));
+               } while ((i != msg_rx->sg.end) && !sg_is_last(sge));
 
                if (unlikely(peek)) {
                        msg_rx = sk_psock_next_msg(psock, msg_rx);
@@ -471,7 +471,7 @@ int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg,
                }
 
                msg_rx->sg.start = i;
-               if (!sge->length && sg_is_last(sge)) {
+               if (!sge->length && (i == msg_rx->sg.end || sg_is_last(sge))) {
                        msg_rx = sk_psock_dequeue_msg(psock);
                        kfree_sk_msg(msg_rx);
                }
@@ -1194,8 +1194,9 @@ static int sk_psock_verdict_recv(struct sock *sk, struct sk_buff *skb)
                ret = bpf_prog_run_pin_on_cpu(prog, skb);
                ret = sk_psock_map_verd(ret, skb_bpf_redirect_fetch(skb));
        }
-       if (sk_psock_verdict_apply(psock, skb, ret) < 0)
-               len = 0;
+       ret = sk_psock_verdict_apply(psock, skb, ret);
+       if (ret < 0)
+               len = ret;
 out:
        rcu_read_unlock();
        return len;
index 4cb957d..788c137 100644 (file)
@@ -1101,7 +1101,7 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
                 * play 'guess the biggest size' games. RCVBUF/SNDBUF
                 * are treated in BSD as hints
                 */
-               val = min_t(u32, val, sysctl_wmem_max);
+               val = min_t(u32, val, READ_ONCE(sysctl_wmem_max));
 set_sndbuf:
                /* Ensure val * 2 fits into an int, to prevent max_t()
                 * from treating it as a negative value.
@@ -1133,7 +1133,7 @@ set_sndbuf:
                 * play 'guess the biggest size' games. RCVBUF/SNDBUF
                 * are treated in BSD as hints
                 */
-               __sock_set_rcvbuf(sk, min_t(u32, val, sysctl_rmem_max));
+               __sock_set_rcvbuf(sk, min_t(u32, val, READ_ONCE(sysctl_rmem_max)));
                break;
 
        case SO_RCVBUFFORCE:
@@ -2536,7 +2536,7 @@ struct sk_buff *sock_omalloc(struct sock *sk, unsigned long size,
 
        /* small safe race: SKB_TRUESIZE may differ from final skb->truesize */
        if (atomic_read(&sk->sk_omem_alloc) + SKB_TRUESIZE(size) >
-           sysctl_optmem_max)
+           READ_ONCE(sysctl_optmem_max))
                return NULL;
 
        skb = alloc_skb(size, priority);
@@ -2554,8 +2554,10 @@ struct sk_buff *sock_omalloc(struct sock *sk, unsigned long size,
  */
 void *sock_kmalloc(struct sock *sk, int size, gfp_t priority)
 {
-       if ((unsigned int)size <= sysctl_optmem_max &&
-           atomic_read(&sk->sk_omem_alloc) + size < sysctl_optmem_max) {
+       int optmem_max = READ_ONCE(sysctl_optmem_max);
+
+       if ((unsigned int)size <= optmem_max &&
+           atomic_read(&sk->sk_omem_alloc) + size < optmem_max) {
                void *mem;
                /* First do the add, to avoid the race if kmalloc
                 * might sleep.
@@ -3309,8 +3311,8 @@ void sock_init_data(struct socket *sock, struct sock *sk)
        timer_setup(&sk->sk_timer, NULL, 0);
 
        sk->sk_allocation       =       GFP_KERNEL;
-       sk->sk_rcvbuf           =       sysctl_rmem_default;
-       sk->sk_sndbuf           =       sysctl_wmem_default;
+       sk->sk_rcvbuf           =       READ_ONCE(sysctl_rmem_default);
+       sk->sk_sndbuf           =       READ_ONCE(sysctl_wmem_default);
        sk->sk_state            =       TCP_CLOSE;
        sk_set_socket(sk, sock);
 
@@ -3365,7 +3367,7 @@ void sock_init_data(struct socket *sock, struct sock *sk)
 
 #ifdef CONFIG_NET_RX_BUSY_POLL
        sk->sk_napi_id          =       0;
-       sk->sk_ll_usec          =       sysctl_net_busy_read;
+       sk->sk_ll_usec          =       READ_ONCE(sysctl_net_busy_read);
 #endif
 
        sk->sk_max_pacing_rate = ~0UL;
index 71a1359..7258915 100644 (file)
@@ -234,14 +234,17 @@ static int set_default_qdisc(struct ctl_table *table, int write,
 static int proc_do_dev_weight(struct ctl_table *table, int write,
                           void *buffer, size_t *lenp, loff_t *ppos)
 {
-       int ret;
+       static DEFINE_MUTEX(dev_weight_mutex);
+       int ret, weight;
 
+       mutex_lock(&dev_weight_mutex);
        ret = proc_dointvec(table, write, buffer, lenp, ppos);
-       if (ret != 0)
-               return ret;
-
-       dev_rx_weight = weight_p * dev_weight_rx_bias;
-       dev_tx_weight = weight_p * dev_weight_tx_bias;
+       if (!ret && write) {
+               weight = READ_ONCE(weight_p);
+               WRITE_ONCE(dev_rx_weight, weight * dev_weight_rx_bias);
+               WRITE_ONCE(dev_tx_weight, weight * dev_weight_tx_bias);
+       }
+       mutex_unlock(&dev_weight_mutex);
 
        return ret;
 }
index 2dd76eb..a8895ee 100644 (file)
@@ -145,11 +145,14 @@ int dsa_port_set_state(struct dsa_port *dp, u8 state, bool do_fast_age)
 static void dsa_port_set_state_now(struct dsa_port *dp, u8 state,
                                   bool do_fast_age)
 {
+       struct dsa_switch *ds = dp->ds;
        int err;
 
        err = dsa_port_set_state(dp, state, do_fast_age);
-       if (err)
-               pr_err("DSA: failed to set STP state %u (%d)\n", state, err);
+       if (err && err != -EOPNOTSUPP) {
+               dev_err(ds->dev, "port %d failed to set STP state %u: %pe\n",
+                       dp->index, state, ERR_PTR(err));
+       }
 }
 
 int dsa_port_set_mst_state(struct dsa_port *dp,
index ad6a666..1291c24 100644 (file)
@@ -2484,7 +2484,7 @@ static int dsa_slave_changeupper(struct net_device *dev,
                        if (!err)
                                dsa_bridge_mtu_normalization(dp);
                        if (err == -EOPNOTSUPP) {
-                               if (!extack->_msg)
+                               if (extack && !extack->_msg)
                                        NL_SET_ERR_MSG_MOD(extack,
                                                           "Offloading not supported");
                                err = 0;
index eb204ad..846588c 100644 (file)
@@ -45,7 +45,7 @@ static struct sk_buff *hellcreek_rcv(struct sk_buff *skb,
 
        skb->dev = dsa_master_find_slave(dev, 0, port);
        if (!skb->dev) {
-               netdev_warn(dev, "Failed to get source port: %d\n", port);
+               netdev_warn_once(dev, "Failed to get source port: %d\n", port);
                return NULL;
        }
 
index 92b778e..e8b9a92 100644 (file)
@@ -2682,23 +2682,27 @@ static __net_init int devinet_init_net(struct net *net)
 #endif
 
        if (!net_eq(net, &init_net)) {
-               if (IS_ENABLED(CONFIG_SYSCTL) &&
-                   sysctl_devconf_inherit_init_net == 3) {
+               switch (net_inherit_devconf()) {
+               case 3:
                        /* copy from the current netns */
                        memcpy(all, current->nsproxy->net_ns->ipv4.devconf_all,
                               sizeof(ipv4_devconf));
                        memcpy(dflt,
                               current->nsproxy->net_ns->ipv4.devconf_dflt,
                               sizeof(ipv4_devconf_dflt));
-               } else if (!IS_ENABLED(CONFIG_SYSCTL) ||
-                          sysctl_devconf_inherit_init_net != 2) {
-                       /* inherit == 0 or 1: copy from init_net */
+                       break;
+               case 0:
+               case 1:
+                       /* copy from init_net */
                        memcpy(all, init_net.ipv4.devconf_all,
                               sizeof(ipv4_devconf));
                        memcpy(dflt, init_net.ipv4.devconf_dflt,
                               sizeof(ipv4_devconf_dflt));
+                       break;
+               case 2:
+                       /* use compiled values */
+                       break;
                }
-               /* else inherit == 2: use compiled values */
        }
 
 #ifdef CONFIG_SYSCTL
index f361d3d..943edf4 100644 (file)
@@ -389,7 +389,7 @@ static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
        dev_match = dev_match || (res.type == RTN_LOCAL &&
                                  dev == net->loopback_dev);
        if (dev_match) {
-               ret = FIB_RES_NHC(res)->nhc_scope >= RT_SCOPE_HOST;
+               ret = FIB_RES_NHC(res)->nhc_scope >= RT_SCOPE_LINK;
                return ret;
        }
        if (no_addr)
@@ -401,7 +401,7 @@ static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
        ret = 0;
        if (fib_lookup(net, &fl4, &res, FIB_LOOKUP_IGNORE_LINKSTATE) == 0) {
                if (res.type == RTN_UNICAST)
-                       ret = FIB_RES_NHC(res)->nhc_scope >= RT_SCOPE_HOST;
+                       ret = FIB_RES_NHC(res)->nhc_scope >= RT_SCOPE_LINK;
        }
        return ret;
 
index 5c58e21..f866d62 100644 (file)
@@ -609,7 +609,7 @@ static int gre_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
        ip_tunnel_init_flow(&fl4, IPPROTO_GRE, key->u.ipv4.dst, key->u.ipv4.src,
                            tunnel_id_to_key32(key->tun_id),
                            key->tos & ~INET_ECN_MASK, dev_net(dev), 0,
-                           skb->mark, skb_get_hash(skb));
+                           skb->mark, skb_get_hash(skb), key->flow_flags);
        rt = ip_route_output_key(dev_net(dev), &fl4);
        if (IS_ERR(rt))
                return PTR_ERR(rt);
index d7bd1da..04e2034 100644 (file)
@@ -1730,7 +1730,7 @@ void ip_send_unicast_reply(struct sock *sk, struct sk_buff *skb,
 
        sk->sk_protocol = ip_hdr(skb)->protocol;
        sk->sk_bound_dev_if = arg->bound_dev_if;
-       sk->sk_sndbuf = sysctl_wmem_default;
+       sk->sk_sndbuf = READ_ONCE(sysctl_wmem_default);
        ipc.sockc.mark = fl4.flowi4_mark;
        err = ip_append_data(sk, &fl4, ip_reply_glue_bits, arg->iov->iov_base,
                             len, 0, &ipc, &rt, MSG_DONTWAIT);
index a8a323e..e49a61a 100644 (file)
@@ -772,7 +772,7 @@ static int ip_set_mcast_msfilter(struct sock *sk, sockptr_t optval, int optlen)
 
        if (optlen < GROUP_FILTER_SIZE(0))
                return -EINVAL;
-       if (optlen > sysctl_optmem_max)
+       if (optlen > READ_ONCE(sysctl_optmem_max))
                return -ENOBUFS;
 
        gsf = memdup_sockptr(optval, optlen);
@@ -808,7 +808,7 @@ static int compat_ip_set_mcast_msfilter(struct sock *sk, sockptr_t optval,
 
        if (optlen < size0)
                return -EINVAL;
-       if (optlen > sysctl_optmem_max - 4)
+       if (optlen > READ_ONCE(sysctl_optmem_max) - 4)
                return -ENOBUFS;
 
        p = kmalloc(optlen + 4, GFP_KERNEL);
@@ -1233,7 +1233,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, int optname,
 
                if (optlen < IP_MSFILTER_SIZE(0))
                        goto e_inval;
-               if (optlen > sysctl_optmem_max) {
+               if (optlen > READ_ONCE(sysctl_optmem_max)) {
                        err = -ENOBUFS;
                        break;
                }
index e65e948..019f3b0 100644 (file)
@@ -295,7 +295,7 @@ static int ip_tunnel_bind_dev(struct net_device *dev)
                ip_tunnel_init_flow(&fl4, iph->protocol, iph->daddr,
                                    iph->saddr, tunnel->parms.o_key,
                                    RT_TOS(iph->tos), dev_net(dev),
-                                   tunnel->parms.link, tunnel->fwmark, 0);
+                                   tunnel->parms.link, tunnel->fwmark, 0, 0);
                rt = ip_route_output_key(tunnel->net, &fl4);
 
                if (!IS_ERR(rt)) {
@@ -570,7 +570,8 @@ void ip_md_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
        }
        ip_tunnel_init_flow(&fl4, proto, key->u.ipv4.dst, key->u.ipv4.src,
                            tunnel_id_to_key32(key->tun_id), RT_TOS(tos),
-                           dev_net(dev), 0, skb->mark, skb_get_hash(skb));
+                           dev_net(dev), 0, skb->mark, skb_get_hash(skb),
+                           key->flow_flags);
        if (tunnel->encap.type != TUNNEL_ENCAP_NONE)
                goto tx_error;
 
@@ -729,7 +730,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
        ip_tunnel_init_flow(&fl4, protocol, dst, tnl_params->saddr,
                            tunnel->parms.o_key, RT_TOS(tos),
                            dev_net(dev), tunnel->parms.link,
-                           tunnel->fwmark, skb_get_hash(skb));
+                           tunnel->fwmark, skb_get_hash(skb), 0);
 
        if (ip_tunnel_encap(skb, tunnel, &protocol, &fl4) < 0)
                goto tx_error;
index 970e9a2..6cdfce6 100644 (file)
@@ -1000,7 +1000,7 @@ new_segment:
 
        i = skb_shinfo(skb)->nr_frags;
        can_coalesce = skb_can_coalesce(skb, i, page, offset);
-       if (!can_coalesce && i >= sysctl_max_skb_frags) {
+       if (!can_coalesce && i >= READ_ONCE(sysctl_max_skb_frags)) {
                tcp_mark_push(tp, skb);
                goto new_segment;
        }
@@ -1015,7 +1015,7 @@ new_segment:
                skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], copy);
        } else {
                get_page(page);
-               skb_fill_page_desc(skb, i, page, offset, copy);
+               skb_fill_page_desc_noacc(skb, i, page, offset, copy);
        }
 
        if (!(flags & MSG_NO_SHARED_FRAGS))
@@ -1354,7 +1354,7 @@ new_segment:
 
                        if (!skb_can_coalesce(skb, i, pfrag->page,
                                              pfrag->offset)) {
-                               if (i >= sysctl_max_skb_frags) {
+                               if (i >= READ_ONCE(sysctl_max_skb_frags)) {
                                        tcp_mark_push(tp, skb);
                                        goto new_segment;
                                }
@@ -1567,17 +1567,11 @@ static int tcp_peek_sndq(struct sock *sk, struct msghdr *msg, int len)
  * calculation of whether or not we must ACK for the sake of
  * a window update.
  */
-void tcp_cleanup_rbuf(struct sock *sk, int copied)
+static void __tcp_cleanup_rbuf(struct sock *sk, int copied)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        bool time_to_ack = false;
 
-       struct sk_buff *skb = skb_peek(&sk->sk_receive_queue);
-
-       WARN(skb && !before(tp->copied_seq, TCP_SKB_CB(skb)->end_seq),
-            "cleanup rbuf bug: copied %X seq %X rcvnxt %X\n",
-            tp->copied_seq, TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt);
-
        if (inet_csk_ack_scheduled(sk)) {
                const struct inet_connection_sock *icsk = inet_csk(sk);
 
@@ -1623,6 +1617,17 @@ void tcp_cleanup_rbuf(struct sock *sk, int copied)
                tcp_send_ack(sk);
 }
 
+void tcp_cleanup_rbuf(struct sock *sk, int copied)
+{
+       struct sk_buff *skb = skb_peek(&sk->sk_receive_queue);
+       struct tcp_sock *tp = tcp_sk(sk);
+
+       WARN(skb && !before(tp->copied_seq, TCP_SKB_CB(skb)->end_seq),
+            "cleanup rbuf bug: copied %X seq %X rcvnxt %X\n",
+            tp->copied_seq, TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt);
+       __tcp_cleanup_rbuf(sk, copied);
+}
+
 static void tcp_eat_recv_skb(struct sock *sk, struct sk_buff *skb)
 {
        __skb_unlink(skb, &sk->sk_receive_queue);
@@ -1756,34 +1761,26 @@ int tcp_read_skb(struct sock *sk, skb_read_actor_t recv_actor)
        if (sk->sk_state == TCP_LISTEN)
                return -ENOTCONN;
 
-       while ((skb = tcp_recv_skb(sk, seq, &offset)) != NULL) {
-               int used;
-
-               __skb_unlink(skb, &sk->sk_receive_queue);
-               used = recv_actor(sk, skb);
-               if (used <= 0) {
-                       if (!copied)
-                               copied = used;
-                       break;
-               }
-               seq += used;
-               copied += used;
+       skb = tcp_recv_skb(sk, seq, &offset);
+       if (!skb)
+               return 0;
 
-               if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) {
-                       consume_skb(skb);
+       __skb_unlink(skb, &sk->sk_receive_queue);
+       WARN_ON(!skb_set_owner_sk_safe(skb, sk));
+       copied = recv_actor(sk, skb);
+       if (copied >= 0) {
+               seq += copied;
+               if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN)
                        ++seq;
-                       break;
-               }
-               consume_skb(skb);
-               break;
        }
+       consume_skb(skb);
        WRITE_ONCE(tp->copied_seq, seq);
 
        tcp_rcv_space_adjust(sk);
 
        /* Clean up data we have read: This will do ACK frames. */
        if (copied > 0)
-               tcp_cleanup_rbuf(sk, copied);
+               __tcp_cleanup_rbuf(sk, copied);
 
        return copied;
 }
index ab5f0ea..bc2ea12 100644 (file)
@@ -2513,6 +2513,21 @@ static inline bool tcp_may_undo(const struct tcp_sock *tp)
        return tp->undo_marker && (!tp->undo_retrans || tcp_packet_delayed(tp));
 }
 
+static bool tcp_is_non_sack_preventing_reopen(struct sock *sk)
+{
+       struct tcp_sock *tp = tcp_sk(sk);
+
+       if (tp->snd_una == tp->high_seq && tcp_is_reno(tp)) {
+               /* Hold old state until something *above* high_seq
+                * is ACKed. For Reno it is MUST to prevent false
+                * fast retransmits (RFC2582). SACK TCP is safe. */
+               if (!tcp_any_retrans_done(sk))
+                       tp->retrans_stamp = 0;
+               return true;
+       }
+       return false;
+}
+
 /* People celebrate: "We love our President!" */
 static bool tcp_try_undo_recovery(struct sock *sk)
 {
@@ -2535,14 +2550,8 @@ static bool tcp_try_undo_recovery(struct sock *sk)
        } else if (tp->rack.reo_wnd_persist) {
                tp->rack.reo_wnd_persist--;
        }
-       if (tp->snd_una == tp->high_seq && tcp_is_reno(tp)) {
-               /* Hold old state until something *above* high_seq
-                * is ACKed. For Reno it is MUST to prevent false
-                * fast retransmits (RFC2582). SACK TCP is safe. */
-               if (!tcp_any_retrans_done(sk))
-                       tp->retrans_stamp = 0;
+       if (tcp_is_non_sack_preventing_reopen(sk))
                return true;
-       }
        tcp_set_ca_state(sk, TCP_CA_Open);
        tp->is_sack_reneg = 0;
        return false;
@@ -2578,6 +2587,8 @@ static bool tcp_try_undo_loss(struct sock *sk, bool frto_undo)
                        NET_INC_STATS(sock_net(sk),
                                        LINUX_MIB_TCPSPURIOUSRTOS);
                inet_csk(sk)->icsk_retransmits = 0;
+               if (tcp_is_non_sack_preventing_reopen(sk))
+                       return true;
                if (frto_undo || tcp_is_sack(tp)) {
                        tcp_set_ca_state(sk, TCP_CA_Open);
                        tp->is_sack_reneg = 0;
@@ -3614,12 +3625,9 @@ bool tcp_oow_rate_limited(struct net *net, const struct sk_buff *skb,
 /* RFC 5961 7 [ACK Throttling] */
 static void tcp_send_challenge_ack(struct sock *sk)
 {
-       /* unprotected vars, we dont care of overwrites */
-       static u32 challenge_timestamp;
-       static unsigned int challenge_count;
        struct tcp_sock *tp = tcp_sk(sk);
        struct net *net = sock_net(sk);
-       u32 count, now;
+       u32 count, now, ack_limit;
 
        /* First check our per-socket dupack rate limit. */
        if (__tcp_oow_rate_limited(net,
@@ -3627,18 +3635,22 @@ static void tcp_send_challenge_ack(struct sock *sk)
                                   &tp->last_oow_ack_time))
                return;
 
+       ack_limit = READ_ONCE(net->ipv4.sysctl_tcp_challenge_ack_limit);
+       if (ack_limit == INT_MAX)
+               goto send_ack;
+
        /* Then check host-wide RFC 5961 rate limit. */
        now = jiffies / HZ;
-       if (now != challenge_timestamp) {
-               u32 ack_limit = READ_ONCE(net->ipv4.sysctl_tcp_challenge_ack_limit);
+       if (now != READ_ONCE(net->ipv4.tcp_challenge_timestamp)) {
                u32 half = (ack_limit + 1) >> 1;
 
-               challenge_timestamp = now;
-               WRITE_ONCE(challenge_count, half + prandom_u32_max(ack_limit));
+               WRITE_ONCE(net->ipv4.tcp_challenge_timestamp, now);
+               WRITE_ONCE(net->ipv4.tcp_challenge_count, half + prandom_u32_max(ack_limit));
        }
-       count = READ_ONCE(challenge_count);
+       count = READ_ONCE(net->ipv4.tcp_challenge_count);
        if (count > 0) {
-               WRITE_ONCE(challenge_count, count - 1);
+               WRITE_ONCE(net->ipv4.tcp_challenge_count, count - 1);
+send_ack:
                NET_INC_STATS(net, LINUX_MIB_TCPCHALLENGEACK);
                tcp_send_ack(sk);
        }
index 0c83780..5b019ba 100644 (file)
@@ -3139,8 +3139,10 @@ static int __net_init tcp_sk_init(struct net *net)
        net->ipv4.sysctl_tcp_tso_win_divisor = 3;
        /* Default TSQ limit of 16 TSO segments */
        net->ipv4.sysctl_tcp_limit_output_bytes = 16 * 65536;
-       /* rfc5961 challenge ack rate limiting */
-       net->ipv4.sysctl_tcp_challenge_ack_limit = 1000;
+
+       /* rfc5961 challenge ack rate limiting, per net-ns, disabled by default. */
+       net->ipv4.sysctl_tcp_challenge_ack_limit = INT_MAX;
+
        net->ipv4.sysctl_tcp_min_tso_segs = 2;
        net->ipv4.sysctl_tcp_tso_rtt_log = 9;  /* 2^9 = 512 usec */
        net->ipv4.sysctl_tcp_min_rtt_wlen = 300;
index 78b654f..290019d 100644 (file)
@@ -239,7 +239,7 @@ void tcp_select_initial_window(const struct sock *sk, int __space, __u32 mss,
        if (wscale_ok) {
                /* Set window scaling on max possible window */
                space = max_t(u32, space, READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_rmem[2]));
-               space = max_t(u32, space, sysctl_rmem_max);
+               space = max_t(u32, space, READ_ONCE(sysctl_rmem_max));
                space = min_t(u32, space, *window_clamp);
                *rcv_wscale = clamp_t(int, ilog2(space) - 15,
                                      0, TCP_MAX_WSCALE);
index 34eda97..cd72158 100644 (file)
@@ -783,6 +783,8 @@ int __udp4_lib_err(struct sk_buff *skb, u32 info, struct udp_table *udptable)
         */
        if (tunnel) {
                /* ...not for tunnels though: we don't have a sending socket */
+               if (udp_sk(sk)->encap_err_rcv)
+                       udp_sk(sk)->encap_err_rcv(sk, skb, iph->ihl << 2);
                goto out;
        }
        if (!inet->recverr) {
index 8efaf8c..8242c89 100644 (file)
@@ -72,6 +72,7 @@ void setup_udp_tunnel_sock(struct net *net, struct socket *sock,
 
        udp_sk(sk)->encap_type = cfg->encap_type;
        udp_sk(sk)->encap_rcv = cfg->encap_rcv;
+       udp_sk(sk)->encap_err_rcv = cfg->encap_err_rcv;
        udp_sk(sk)->encap_err_lookup = cfg->encap_err_lookup;
        udp_sk(sk)->encap_destroy = cfg->encap_destroy;
        udp_sk(sk)->gro_receive = cfg->gro_receive;
index b624e3d..10ce86b 100644 (file)
@@ -3557,11 +3557,15 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
                fallthrough;
        case NETDEV_UP:
        case NETDEV_CHANGE:
-               if (dev->flags & IFF_SLAVE)
+               if (idev && idev->cnf.disable_ipv6)
                        break;
 
-               if (idev && idev->cnf.disable_ipv6)
+               if (dev->flags & IFF_SLAVE) {
+                       if (event == NETDEV_UP && !IS_ERR_OR_NULL(idev) &&
+                           dev->flags & IFF_UP && dev->flags & IFF_MULTICAST)
+                               ipv6_mc_up(idev);
                        break;
+               }
 
                if (event == NETDEV_UP) {
                        /* restore routes for permanent addresses */
@@ -7162,9 +7166,8 @@ static int __net_init addrconf_init_net(struct net *net)
        if (!dflt)
                goto err_alloc_dflt;
 
-       if (IS_ENABLED(CONFIG_SYSCTL) &&
-           !net_eq(net, &init_net)) {
-               switch (sysctl_devconf_inherit_init_net) {
+       if (!net_eq(net, &init_net)) {
+               switch (net_inherit_devconf()) {
                case 1:  /* copy from init_net */
                        memcpy(all, init_net.ipv6.devconf_all,
                               sizeof(ipv6_devconf));
index 3fda563..79c6a82 100644 (file)
@@ -1517,7 +1517,7 @@ static void ip6_tnl_link_config(struct ip6_tnl *t)
  *   ip6_tnl_change() updates the tunnel parameters
  **/
 
-static int
+static void
 ip6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p)
 {
        t->parms.laddr = p->laddr;
@@ -1531,29 +1531,25 @@ ip6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p)
        t->parms.fwmark = p->fwmark;
        dst_cache_reset(&t->dst_cache);
        ip6_tnl_link_config(t);
-       return 0;
 }
 
-static int ip6_tnl_update(struct ip6_tnl *t, struct __ip6_tnl_parm *p)
+static void ip6_tnl_update(struct ip6_tnl *t, struct __ip6_tnl_parm *p)
 {
        struct net *net = t->net;
        struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
-       int err;
 
        ip6_tnl_unlink(ip6n, t);
        synchronize_net();
-       err = ip6_tnl_change(t, p);
+       ip6_tnl_change(t, p);
        ip6_tnl_link(ip6n, t);
        netdev_state_change(t->dev);
-       return err;
 }
 
-static int ip6_tnl0_update(struct ip6_tnl *t, struct __ip6_tnl_parm *p)
+static void ip6_tnl0_update(struct ip6_tnl *t, struct __ip6_tnl_parm *p)
 {
        /* for default tnl0 device allow to change only the proto */
        t->parms.proto = p->proto;
        netdev_state_change(t->dev);
-       return 0;
 }
 
 static void
@@ -1667,9 +1663,9 @@ ip6_tnl_siocdevprivate(struct net_device *dev, struct ifreq *ifr,
                        } else
                                t = netdev_priv(dev);
                        if (dev == ip6n->fb_tnl_dev)
-                               err = ip6_tnl0_update(t, &p1);
+                               ip6_tnl0_update(t, &p1);
                        else
-                               err = ip6_tnl_update(t, &p1);
+                               ip6_tnl_update(t, &p1);
                }
                if (!IS_ERR(t)) {
                        err = 0;
@@ -2091,7 +2087,8 @@ static int ip6_tnl_changelink(struct net_device *dev, struct nlattr *tb[],
        } else
                t = netdev_priv(dev);
 
-       return ip6_tnl_update(t, &p);
+       ip6_tnl_update(t, &p);
+       return 0;
 }
 
 static void ip6_tnl_dellink(struct net_device *dev, struct list_head *head)
index 222f6bf..e0dcc7a 100644 (file)
@@ -210,7 +210,7 @@ static int ipv6_set_mcast_msfilter(struct sock *sk, sockptr_t optval,
 
        if (optlen < GROUP_FILTER_SIZE(0))
                return -EINVAL;
-       if (optlen > sysctl_optmem_max)
+       if (optlen > READ_ONCE(sysctl_optmem_max))
                return -ENOBUFS;
 
        gsf = memdup_sockptr(optval, optlen);
@@ -244,7 +244,7 @@ static int compat_ipv6_set_mcast_msfilter(struct sock *sk, sockptr_t optval,
 
        if (optlen < size0)
                return -EINVAL;
-       if (optlen > sysctl_optmem_max - 4)
+       if (optlen > READ_ONCE(sysctl_optmem_max) - 4)
                return -ENOBUFS;
 
        p = kmalloc(optlen + 4, GFP_KERNEL);
index 9845369..3a55349 100644 (file)
@@ -1378,6 +1378,9 @@ static void ndisc_router_discovery(struct sk_buff *skb)
        if (!rt && lifetime) {
                ND_PRINTK(3, info, "RA: adding default router\n");
 
+               if (neigh)
+                       neigh_release(neigh);
+
                rt = rt6_add_dflt_router(net, &ipv6_hdr(skb)->saddr,
                                         skb->dev, pref, defrtr_usr_metric);
                if (!rt) {
index 7dd3629..38db006 100644 (file)
@@ -86,7 +86,6 @@ static int nf_ct_frag6_sysctl_register(struct net *net)
        table[1].extra2 = &nf_frag->fqdir->high_thresh;
        table[2].data   = &nf_frag->fqdir->high_thresh;
        table[2].extra1 = &nf_frag->fqdir->low_thresh;
-       table[2].extra2 = &nf_frag->fqdir->high_thresh;
 
        hdr = register_net_sysctl(net, "net/netfilter", table);
        if (hdr == NULL)
index 73aaabf..0b0e34d 100644 (file)
@@ -191,6 +191,11 @@ static int seg6_genl_sethmac(struct sk_buff *skb, struct genl_info *info)
                goto out_unlock;
        }
 
+       if (slen > nla_len(info->attrs[SEG6_ATTR_SECRET])) {
+               err = -EINVAL;
+               goto out_unlock;
+       }
+
        if (hinfo) {
                err = seg6_hmac_info_del(net, hmackeyid);
                if (err)
index 16c176e..3366d6a 100644 (file)
@@ -616,8 +616,11 @@ int __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
        }
 
        /* Tunnels don't have an application socket: don't pass errors back */
-       if (tunnel)
+       if (tunnel) {
+               if (udp_sk(sk)->encap_err_rcv)
+                       udp_sk(sk)->encap_err_rcv(sk, skb, offset);
                goto out;
+       }
 
        if (!np->recverr) {
                if (!harderr || sk->sk_state != TCP_ESTABLISHED)
index 71899e5..1215c86 100644 (file)
@@ -1412,12 +1412,6 @@ static int kcm_attach(struct socket *sock, struct socket *csock,
        psock->sk = csk;
        psock->bpf_prog = prog;
 
-       err = strp_init(&psock->strp, csk, &cb);
-       if (err) {
-               kmem_cache_free(kcm_psockp, psock);
-               goto out;
-       }
-
        write_lock_bh(&csk->sk_callback_lock);
 
        /* Check if sk_user_data is already by KCM or someone else.
@@ -1425,13 +1419,18 @@ static int kcm_attach(struct socket *sock, struct socket *csock,
         */
        if (csk->sk_user_data) {
                write_unlock_bh(&csk->sk_callback_lock);
-               strp_stop(&psock->strp);
-               strp_done(&psock->strp);
                kmem_cache_free(kcm_psockp, psock);
                err = -EALREADY;
                goto out;
        }
 
+       err = strp_init(&psock->strp, csk, &cb);
+       if (err) {
+               write_unlock_bh(&csk->sk_callback_lock);
+               kmem_cache_free(kcm_psockp, psock);
+               goto out;
+       }
+
        psock->save_data_ready = csk->sk_data_ready;
        psock->save_write_space = csk->sk_write_space;
        psock->save_state_change = csk->sk_state_change;
index fda2dcc..c85df5b 100644 (file)
@@ -1697,9 +1697,12 @@ static int pfkey_register(struct sock *sk, struct sk_buff *skb, const struct sad
                pfk->registered |= (1<<hdr->sadb_msg_satype);
        }
 
+       mutex_lock(&pfkey_mutex);
        xfrm_probe_algs();
 
        supp_skb = compose_sadb_supported(hdr, GFP_KERNEL | __GFP_ZERO);
+       mutex_unlock(&pfkey_mutex);
+
        if (!supp_skb) {
                if (hdr->sadb_msg_satype != SADB_SATYPE_UNSPEC)
                        pfk->registered &= ~(1<<hdr->sadb_msg_satype);
index d56890e..9b283bb 100644 (file)
@@ -530,6 +530,10 @@ int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata)
 
        sdata_assert_lock(sdata);
 
+       /* When not connected/joined, sending CSA doesn't make sense. */
+       if (ifibss->state != IEEE80211_IBSS_MLME_JOINED)
+               return -ENOLINK;
+
        /* update cfg80211 bss information with the new channel */
        if (!is_zero_ether_addr(ifibss->bssid)) {
                cbss = cfg80211_get_bss(sdata->local->hw.wiphy,
index 3d4ab71..5265d2b 100644 (file)
@@ -3420,11 +3420,11 @@ static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata,
                ieee80211_link_info_change_notify(sdata, &sdata->deflink,
                                                  BSS_CHANGED_BSSID);
                sdata->u.mgd.flags = 0;
+
                mutex_lock(&sdata->local->mtx);
                ieee80211_link_release_channel(&sdata->deflink);
-               mutex_unlock(&sdata->local->mtx);
-
                ieee80211_vif_set_links(sdata, 0);
+               mutex_unlock(&sdata->local->mtx);
        }
 
        cfg80211_put_bss(sdata->local->hw.wiphy, auth_data->bss);
@@ -3462,10 +3462,6 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata,
                sdata->u.mgd.flags = 0;
                sdata->vif.bss_conf.mu_mimo_owner = false;
 
-               mutex_lock(&sdata->local->mtx);
-               ieee80211_link_release_channel(&sdata->deflink);
-               mutex_unlock(&sdata->local->mtx);
-
                if (status != ASSOC_REJECTED) {
                        struct cfg80211_assoc_failure data = {
                                .timeout = status == ASSOC_TIMEOUT,
@@ -3484,7 +3480,10 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata,
                        cfg80211_assoc_failure(sdata->dev, &data);
                }
 
+               mutex_lock(&sdata->local->mtx);
+               ieee80211_link_release_channel(&sdata->deflink);
                ieee80211_vif_set_links(sdata, 0);
+               mutex_unlock(&sdata->local->mtx);
        }
 
        kfree(assoc_data);
@@ -6509,6 +6508,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
        return 0;
 
 out_err:
+       ieee80211_link_release_channel(&sdata->deflink);
        ieee80211_vif_set_links(sdata, 0);
        return err;
 }
index 57df21e..45d7e71 100644 (file)
@@ -4074,6 +4074,7 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid)
                .link_id = -1,
        };
        struct tid_ampdu_rx *tid_agg_rx;
+       u8 link_id;
 
        tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
        if (!tid_agg_rx)
@@ -4093,6 +4094,9 @@ 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]);
 
        ieee80211_rx_handlers(&rx, &frames);
 }
index fa8ddf5..c4f2aeb 100644 (file)
@@ -469,16 +469,19 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
        scan_req = rcu_dereference_protected(local->scan_req,
                                             lockdep_is_held(&local->mtx));
 
-       if (scan_req != local->int_scan_req) {
-               local->scan_info.aborted = aborted;
-               cfg80211_scan_done(scan_req, &local->scan_info);
-       }
        RCU_INIT_POINTER(local->scan_req, NULL);
        RCU_INIT_POINTER(local->scan_sdata, NULL);
 
        local->scanning = 0;
        local->scan_chandef.chan = NULL;
 
+       synchronize_rcu();
+
+       if (scan_req != local->int_scan_req) {
+               local->scan_info.aborted = aborted;
+               cfg80211_scan_done(scan_req, &local->scan_info);
+       }
+
        /* Set power back to normal operating levels. */
        ieee80211_hw_config(local, 0);
 
index cb23da9..58998d8 100644 (file)
@@ -494,7 +494,7 @@ __sta_info_alloc(struct ieee80211_sub_if_data *sdata,
        sta->sdata = sdata;
 
        if (sta_info_alloc_link(local, &sta->deflink, gfp))
-               return NULL;
+               goto free;
 
        if (link_id >= 0) {
                sta_info_add_link(sta, link_id, &sta->deflink,
@@ -2316,9 +2316,9 @@ static inline u64 sta_get_tidstats_msdu(struct ieee80211_sta_rx_stats *rxstats,
        u64 value;
 
        do {
-               start = u64_stats_fetch_begin(&rxstats->syncp);
+               start = u64_stats_fetch_begin_irq(&rxstats->syncp);
                value = rxstats->msdu[tid];
-       } while (u64_stats_fetch_retry(&rxstats->syncp, start));
+       } while (u64_stats_fetch_retry_irq(&rxstats->syncp, start));
 
        return value;
 }
@@ -2384,9 +2384,9 @@ static inline u64 sta_get_stats_bytes(struct ieee80211_sta_rx_stats *rxstats)
        u64 value;
 
        do {
-               start = u64_stats_fetch_begin(&rxstats->syncp);
+               start = u64_stats_fetch_begin_irq(&rxstats->syncp);
                value = rxstats->bytes;
-       } while (u64_stats_fetch_retry(&rxstats->syncp, start));
+       } while (u64_stats_fetch_retry_irq(&rxstats->syncp, start));
 
        return value;
 }
index 45df993..bf7fe6c 100644 (file)
@@ -5885,6 +5885,7 @@ int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,
        rcu_read_lock();
        err = ieee80211_lookup_ra_sta(sdata, skb, &sta);
        if (err) {
+               dev_kfree_skb(skb);
                rcu_read_unlock();
                return err;
        }
@@ -5899,7 +5900,7 @@ int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,
                 * for MLO STA, the SA should be the AP MLD address, but
                 * the link ID has been selected already
                 */
-               if (sta->sta.mlo)
+               if (sta && sta->sta.mlo)
                        memcpy(ehdr->h_source, sdata->vif.addr, ETH_ALEN);
        }
        rcu_read_unlock();
index 93ec2f3..20f742b 100644 (file)
@@ -351,7 +351,7 @@ static u8 ccmp_gcmp_aad(struct sk_buff *skb, u8 *aad)
         * FC | A1 | A2 | A3 | SC | [A4] | [QC] */
        put_unaligned_be16(len_a, &aad[0]);
        put_unaligned(mask_fc, (__le16 *)&aad[2]);
-       memcpy(&aad[4], &hdr->addr1, 3 * ETH_ALEN);
+       memcpy(&aad[4], &hdr->addrs, 3 * ETH_ALEN);
 
        /* Mask Seq#, leave Frag# */
        aad[22] = *((u8 *) &hdr->seq_ctrl) & 0x0f;
@@ -792,7 +792,7 @@ static void bip_aad(struct sk_buff *skb, u8 *aad)
                                IEEE80211_FCTL_MOREDATA);
        put_unaligned(mask_fc, (__le16 *) &aad[0]);
        /* A1 || A2 || A3 */
-       memcpy(aad + 2, &hdr->addr1, 3 * ETH_ALEN);
+       memcpy(aad + 2, &hdr->addrs, 3 * ETH_ALEN);
 }
 
 
index b8ce846..c439125 100644 (file)
@@ -44,7 +44,7 @@ ieee802154_subif_frame(struct ieee802154_sub_if_data *sdata,
 
        switch (mac_cb(skb)->dest.mode) {
        case IEEE802154_ADDR_NONE:
-               if (mac_cb(skb)->dest.mode != IEEE802154_ADDR_NONE)
+               if (hdr->source.mode != IEEE802154_ADDR_NONE)
                        /* FIXME: check if we are PAN coordinator */
                        skb->pkt_type = PACKET_OTHERHOST;
                else
index 35b5f80..b52afe3 100644 (file)
@@ -1079,9 +1079,9 @@ static void mpls_get_stats(struct mpls_dev *mdev,
 
                p = per_cpu_ptr(mdev->stats, i);
                do {
-                       start = u64_stats_fetch_begin(&p->syncp);
+                       start = u64_stats_fetch_begin_irq(&p->syncp);
                        local = p->stats;
-               } while (u64_stats_fetch_retry(&p->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&p->syncp, start));
 
                stats->rx_packets       += local.rx_packets;
                stats->rx_bytes         += local.rx_bytes;
index da42575..d398f38 100644 (file)
@@ -1263,7 +1263,7 @@ static int mptcp_sendmsg_frag(struct sock *sk, struct sock *ssk,
 
                i = skb_shinfo(skb)->nr_frags;
                can_coalesce = skb_can_coalesce(skb, i, dfrag->page, offset);
-               if (!can_coalesce && i >= sysctl_max_skb_frags) {
+               if (!can_coalesce && i >= READ_ONCE(sysctl_max_skb_frags)) {
                        tcp_mark_push(tcp_sk(ssk), skb);
                        goto alloc_skb;
                }
index 22f15eb..4b8d046 100644 (file)
@@ -144,7 +144,6 @@ config NF_CONNTRACK_ZONES
 
 config NF_CONNTRACK_PROCFS
        bool "Supply CT list in procfs (OBSOLETE)"
-       default y
        depends on PROC_FS
        help
        This option enables for the list of known conntrack entries
index 9d43277..a56fd0b 100644 (file)
@@ -1280,12 +1280,12 @@ static void set_sock_size(struct sock *sk, int mode, int val)
        lock_sock(sk);
        if (mode) {
                val = clamp_t(int, val, (SOCK_MIN_SNDBUF + 1) / 2,
-                             sysctl_wmem_max);
+                             READ_ONCE(sysctl_wmem_max));
                sk->sk_sndbuf = val * 2;
                sk->sk_userlocks |= SOCK_SNDBUF_LOCK;
        } else {
                val = clamp_t(int, val, (SOCK_MIN_RCVBUF + 1) / 2,
-                             sysctl_rmem_max);
+                             READ_ONCE(sysctl_rmem_max));
                sk->sk_rcvbuf = val * 2;
                sk->sk_userlocks |= SOCK_RCVBUF_LOCK;
        }
index 71c2f4f..1357a27 100644 (file)
@@ -1782,7 +1782,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
                }
                spin_unlock_bh(&nf_conntrack_expect_lock);
        }
-       if (!exp)
+       if (!exp && tmpl)
                __nf_ct_try_assign_helper(ct, tmpl, GFP_ATOMIC);
 
        /* Other CPU might have obtained a pointer to this object before it was
@@ -2068,10 +2068,6 @@ void nf_conntrack_alter_reply(struct nf_conn *ct,
        ct->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply;
        if (ct->master || (help && !hlist_empty(&help->expectations)))
                return;
-
-       rcu_read_lock();
-       __nf_ct_try_assign_helper(ct, NULL, GFP_ATOMIC);
-       rcu_read_unlock();
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_alter_reply);
 
@@ -2797,7 +2793,6 @@ int nf_conntrack_init_net(struct net *net)
        nf_conntrack_acct_pernet_init(net);
        nf_conntrack_tstamp_pernet_init(net);
        nf_conntrack_ecache_pernet_init(net);
-       nf_conntrack_helper_pernet_init(net);
        nf_conntrack_proto_pernet_init(net);
 
        return 0;
index a414274..0d9332e 100644 (file)
@@ -34,11 +34,6 @@ MODULE_DESCRIPTION("ftp connection tracking helper");
 MODULE_ALIAS("ip_conntrack_ftp");
 MODULE_ALIAS_NFCT_HELPER(HELPER_NAME);
 
-/* This is slow, but it's simple. --RR */
-static char *ftp_buffer;
-
-static DEFINE_SPINLOCK(nf_ftp_lock);
-
 #define MAX_PORTS 8
 static u_int16_t ports[MAX_PORTS];
 static unsigned int ports_c;
@@ -398,6 +393,9 @@ static int help(struct sk_buff *skb,
                return NF_ACCEPT;
        }
 
+       if (unlikely(skb_linearize(skb)))
+               return NF_DROP;
+
        th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);
        if (th == NULL)
                return NF_ACCEPT;
@@ -411,12 +409,8 @@ static int help(struct sk_buff *skb,
        }
        datalen = skb->len - dataoff;
 
-       spin_lock_bh(&nf_ftp_lock);
-       fb_ptr = skb_header_pointer(skb, dataoff, datalen, ftp_buffer);
-       if (!fb_ptr) {
-               spin_unlock_bh(&nf_ftp_lock);
-               return NF_ACCEPT;
-       }
+       spin_lock_bh(&ct->lock);
+       fb_ptr = skb->data + dataoff;
 
        ends_in_nl = (fb_ptr[datalen - 1] == '\n');
        seq = ntohl(th->seq) + datalen;
@@ -544,7 +538,7 @@ out_update_nl:
        if (ends_in_nl)
                update_nl_seq(ct, seq, ct_ftp_info, dir, skb);
  out:
-       spin_unlock_bh(&nf_ftp_lock);
+       spin_unlock_bh(&ct->lock);
        return ret;
 }
 
@@ -571,7 +565,6 @@ static const struct nf_conntrack_expect_policy ftp_exp_policy = {
 static void __exit nf_conntrack_ftp_fini(void)
 {
        nf_conntrack_helpers_unregister(ftp, ports_c * 2);
-       kfree(ftp_buffer);
 }
 
 static int __init nf_conntrack_ftp_init(void)
@@ -580,10 +573,6 @@ static int __init nf_conntrack_ftp_init(void)
 
        NF_CT_HELPER_BUILD_BUG_ON(sizeof(struct nf_ct_ftp_master));
 
-       ftp_buffer = kmalloc(65536, GFP_KERNEL);
-       if (!ftp_buffer)
-               return -ENOMEM;
-
        if (ports_c == 0)
                ports[ports_c++] = FTP_PORT;
 
@@ -603,7 +592,6 @@ static int __init nf_conntrack_ftp_init(void)
        ret = nf_conntrack_helpers_register(ftp, ports_c * 2);
        if (ret < 0) {
                pr_err("failed to register helpers\n");
-               kfree(ftp_buffer);
                return ret;
        }
 
index bb76305..5a9bce2 100644 (file)
@@ -34,6 +34,8 @@
 #include <net/netfilter/nf_conntrack_zones.h>
 #include <linux/netfilter/nf_conntrack_h323.h>
 
+#define H323_MAX_SIZE 65535
+
 /* Parameters */
 static unsigned int default_rrq_ttl __read_mostly = 300;
 module_param(default_rrq_ttl, uint, 0600);
@@ -86,6 +88,9 @@ static int get_tpkt_data(struct sk_buff *skb, unsigned int protoff,
        if (tcpdatalen <= 0)    /* No TCP data */
                goto clear_out;
 
+       if (tcpdatalen > H323_MAX_SIZE)
+               tcpdatalen = H323_MAX_SIZE;
+
        if (*data == NULL) {    /* first TPKT */
                /* Get first TPKT pointer */
                tpkt = skb_header_pointer(skb, tcpdataoff, tcpdatalen,
@@ -1169,6 +1174,9 @@ static unsigned char *get_udp_data(struct sk_buff *skb, unsigned int protoff,
        if (dataoff >= skb->len)
                return NULL;
        *datalen = skb->len - dataoff;
+       if (*datalen > H323_MAX_SIZE)
+               *datalen = H323_MAX_SIZE;
+
        return skb_header_pointer(skb, dataoff, *datalen, h323_buffer);
 }
 
@@ -1770,7 +1778,7 @@ static int __init nf_conntrack_h323_init(void)
 
        NF_CT_HELPER_BUILD_BUG_ON(sizeof(struct nf_ct_h323_master));
 
-       h323_buffer = kmalloc(65536, GFP_KERNEL);
+       h323_buffer = kmalloc(H323_MAX_SIZE + 1, GFP_KERNEL);
        if (!h323_buffer)
                return -ENOMEM;
        ret = h323_helper_init();
index e96b322..ff737a7 100644 (file)
@@ -35,11 +35,6 @@ unsigned int nf_ct_helper_hsize __read_mostly;
 EXPORT_SYMBOL_GPL(nf_ct_helper_hsize);
 static unsigned int nf_ct_helper_count __read_mostly;
 
-static bool nf_ct_auto_assign_helper __read_mostly = false;
-module_param_named(nf_conntrack_helper, nf_ct_auto_assign_helper, bool, 0644);
-MODULE_PARM_DESC(nf_conntrack_helper,
-                "Enable automatic conntrack helper assignment (default 0)");
-
 static DEFINE_MUTEX(nf_ct_nat_helpers_mutex);
 static struct list_head nf_ct_nat_helpers __read_mostly;
 
@@ -51,24 +46,6 @@ static unsigned int helper_hash(const struct nf_conntrack_tuple *tuple)
                (__force __u16)tuple->src.u.all) % nf_ct_helper_hsize;
 }
 
-static struct nf_conntrack_helper *
-__nf_ct_helper_find(const struct nf_conntrack_tuple *tuple)
-{
-       struct nf_conntrack_helper *helper;
-       struct nf_conntrack_tuple_mask mask = { .src.u.all = htons(0xFFFF) };
-       unsigned int h;
-
-       if (!nf_ct_helper_count)
-               return NULL;
-
-       h = helper_hash(tuple);
-       hlist_for_each_entry_rcu(helper, &nf_ct_helper_hash[h], hnode) {
-               if (nf_ct_tuple_src_mask_cmp(tuple, &helper->tuple, &mask))
-                       return helper;
-       }
-       return NULL;
-}
-
 struct nf_conntrack_helper *
 __nf_conntrack_helper_find(const char *name, u16 l3num, u8 protonum)
 {
@@ -209,33 +186,11 @@ nf_ct_helper_ext_add(struct nf_conn *ct, gfp_t gfp)
 }
 EXPORT_SYMBOL_GPL(nf_ct_helper_ext_add);
 
-static struct nf_conntrack_helper *
-nf_ct_lookup_helper(struct nf_conn *ct, struct net *net)
-{
-       struct nf_conntrack_net *cnet = nf_ct_pernet(net);
-
-       if (!cnet->sysctl_auto_assign_helper) {
-               if (cnet->auto_assign_helper_warned)
-                       return NULL;
-               if (!__nf_ct_helper_find(&ct->tuplehash[IP_CT_DIR_REPLY].tuple))
-                       return NULL;
-               pr_info("nf_conntrack: default automatic helper assignment "
-                       "has been turned off for security reasons and CT-based "
-                       "firewall rule not found. Use the iptables CT target "
-                       "to attach helpers instead.\n");
-               cnet->auto_assign_helper_warned = true;
-               return NULL;
-       }
-
-       return __nf_ct_helper_find(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
-}
-
 int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl,
                              gfp_t flags)
 {
        struct nf_conntrack_helper *helper = NULL;
        struct nf_conn_help *help;
-       struct net *net = nf_ct_net(ct);
 
        /* We already got a helper explicitly attached. The function
         * nf_conntrack_alter_reply - in case NAT is in use - asks for looking
@@ -246,23 +201,21 @@ int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl,
        if (test_bit(IPS_HELPER_BIT, &ct->status))
                return 0;
 
-       if (tmpl != NULL) {
-               help = nfct_help(tmpl);
-               if (help != NULL) {
-                       helper = rcu_dereference(help->helper);
-                       set_bit(IPS_HELPER_BIT, &ct->status);
-               }
+       if (WARN_ON_ONCE(!tmpl))
+               return 0;
+
+       help = nfct_help(tmpl);
+       if (help != NULL) {
+               helper = rcu_dereference(help->helper);
+               set_bit(IPS_HELPER_BIT, &ct->status);
        }
 
        help = nfct_help(ct);
 
        if (helper == NULL) {
-               helper = nf_ct_lookup_helper(ct, net);
-               if (helper == NULL) {
-                       if (help)
-                               RCU_INIT_POINTER(help->helper, NULL);
-                       return 0;
-               }
+               if (help)
+                       RCU_INIT_POINTER(help->helper, NULL);
+               return 0;
        }
 
        if (help == NULL) {
@@ -545,19 +498,6 @@ void nf_nat_helper_unregister(struct nf_conntrack_nat_helper *nat)
 }
 EXPORT_SYMBOL_GPL(nf_nat_helper_unregister);
 
-void nf_ct_set_auto_assign_helper_warned(struct net *net)
-{
-       nf_ct_pernet(net)->auto_assign_helper_warned = true;
-}
-EXPORT_SYMBOL_GPL(nf_ct_set_auto_assign_helper_warned);
-
-void nf_conntrack_helper_pernet_init(struct net *net)
-{
-       struct nf_conntrack_net *cnet = nf_ct_pernet(net);
-
-       cnet->sysctl_auto_assign_helper = nf_ct_auto_assign_helper;
-}
-
 int nf_conntrack_helper_init(void)
 {
        nf_ct_helper_hsize = 1; /* gets rounded up to use one page */
index 08ee4e7..992decb 100644 (file)
@@ -39,6 +39,7 @@ unsigned int (*nf_nat_irc_hook)(struct sk_buff *skb,
 EXPORT_SYMBOL_GPL(nf_nat_irc_hook);
 
 #define HELPER_NAME "irc"
+#define MAX_SEARCH_SIZE        4095
 
 MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
 MODULE_DESCRIPTION("IRC (DCC) connection tracking helper");
@@ -121,6 +122,7 @@ static int help(struct sk_buff *skb, unsigned int protoff,
        int i, ret = NF_ACCEPT;
        char *addr_beg_p, *addr_end_p;
        typeof(nf_nat_irc_hook) nf_nat_irc;
+       unsigned int datalen;
 
        /* If packet is coming from IRC server */
        if (dir == IP_CT_DIR_REPLY)
@@ -140,8 +142,12 @@ static int help(struct sk_buff *skb, unsigned int protoff,
        if (dataoff >= skb->len)
                return NF_ACCEPT;
 
+       datalen = skb->len - dataoff;
+       if (datalen > MAX_SEARCH_SIZE)
+               datalen = MAX_SEARCH_SIZE;
+
        spin_lock_bh(&irc_buffer_lock);
-       ib_ptr = skb_header_pointer(skb, dataoff, skb->len - dataoff,
+       ib_ptr = skb_header_pointer(skb, dataoff, datalen,
                                    irc_buffer);
        if (!ib_ptr) {
                spin_unlock_bh(&irc_buffer_lock);
@@ -149,7 +155,7 @@ static int help(struct sk_buff *skb, unsigned int protoff,
        }
 
        data = ib_ptr;
-       data_limit = ib_ptr + skb->len - dataoff;
+       data_limit = ib_ptr + datalen;
 
        /* strlen("\1DCC SENT t AAAAAAAA P\1\n")=24
         * 5+MINMATCHLEN+strlen("t AAAAAAAA P\1\n")=14 */
@@ -188,8 +194,9 @@ static int help(struct sk_buff *skb, unsigned int protoff,
 
                        /* dcc_ip can be the internal OR external (NAT'ed) IP */
                        tuple = &ct->tuplehash[dir].tuple;
-                       if (tuple->src.u3.ip != dcc_ip &&
-                           tuple->dst.u3.ip != dcc_ip) {
+                       if ((tuple->src.u3.ip != dcc_ip &&
+                            ct->tuplehash[!dir].tuple.dst.u3.ip != dcc_ip) ||
+                           dcc_port == 0) {
                                net_warn_ratelimited("Forged DCC command from %pI4: %pI4:%u\n",
                                                     &tuple->src.u3.ip,
                                                     &dcc_ip, dcc_port);
@@ -251,7 +258,7 @@ static int __init nf_conntrack_irc_init(void)
        irc_exp_policy.max_expected = max_dcc_channels;
        irc_exp_policy.timeout = dcc_timeout;
 
-       irc_buffer = kmalloc(65536, GFP_KERNEL);
+       irc_buffer = kmalloc(MAX_SEARCH_SIZE + 1, GFP_KERNEL);
        if (!irc_buffer)
                return -ENOMEM;
 
index 04169b5..7562b21 100644 (file)
@@ -2298,11 +2298,6 @@ ctnetlink_create_conntrack(struct net *net,
                        ct->status |= IPS_HELPER;
                        RCU_INIT_POINTER(help->helper, helper);
                }
-       } else {
-               /* try an implicit helper assignation */
-               err = __nf_ct_try_assign_helper(ct, NULL, GFP_ATOMIC);
-               if (err < 0)
-                       goto err2;
        }
 
        err = ctnetlink_setup_nat(ct, cda);
index a63b51d..a634c72 100644 (file)
@@ -655,6 +655,37 @@ static bool tcp_in_window(struct nf_conn *ct,
                    tn->tcp_be_liberal)
                        res = true;
                if (!res) {
+                       bool seq_ok = before(seq, sender->td_maxend + 1);
+
+                       if (!seq_ok) {
+                               u32 overshot = end - sender->td_maxend + 1;
+                               bool ack_ok;
+
+                               ack_ok = after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1);
+
+                               if (in_recv_win &&
+                                   ack_ok &&
+                                   overshot <= receiver->td_maxwin &&
+                                   before(sack, receiver->td_end + 1)) {
+                                       /* Work around TCPs that send more bytes than allowed by
+                                        * the receive window.
+                                        *
+                                        * If the (marked as invalid) packet is allowed to pass by
+                                        * the ruleset and the peer acks this data, then its possible
+                                        * all future packets will trigger 'ACK is over upper bound' check.
+                                        *
+                                        * Thus if only the sequence check fails then do update td_end so
+                                        * possible ACK for this data can update internal state.
+                                        */
+                                       sender->td_end = end;
+                                       sender->flags |= IP_CT_TCP_FLAG_DATA_UNACKNOWLEDGED;
+
+                                       nf_ct_l4proto_log_invalid(skb, ct, hook_state,
+                                                                 "%u bytes more than expected", overshot);
+                                       return res;
+                               }
+                       }
+
                        nf_ct_l4proto_log_invalid(skb, ct, hook_state,
                        "%s",
                        before(seq, sender->td_maxend + 1) ?
index fcb33b1..13dc421 100644 (file)
@@ -34,10 +34,6 @@ MODULE_AUTHOR("Michal Schmidt <mschmidt@redhat.com>");
 MODULE_DESCRIPTION("SANE connection tracking helper");
 MODULE_ALIAS_NFCT_HELPER(HELPER_NAME);
 
-static char *sane_buffer;
-
-static DEFINE_SPINLOCK(nf_sane_lock);
-
 #define MAX_PORTS 8
 static u_int16_t ports[MAX_PORTS];
 static unsigned int ports_c;
@@ -67,14 +63,16 @@ static int help(struct sk_buff *skb,
        unsigned int dataoff, datalen;
        const struct tcphdr *th;
        struct tcphdr _tcph;
-       void *sb_ptr;
        int ret = NF_ACCEPT;
        int dir = CTINFO2DIR(ctinfo);
        struct nf_ct_sane_master *ct_sane_info = nfct_help_data(ct);
        struct nf_conntrack_expect *exp;
        struct nf_conntrack_tuple *tuple;
-       struct sane_request *req;
        struct sane_reply_net_start *reply;
+       union {
+               struct sane_request req;
+               struct sane_reply_net_start repl;
+       } buf;
 
        /* Until there's been traffic both ways, don't look in packets. */
        if (ctinfo != IP_CT_ESTABLISHED &&
@@ -92,59 +90,62 @@ static int help(struct sk_buff *skb,
                return NF_ACCEPT;
 
        datalen = skb->len - dataoff;
-
-       spin_lock_bh(&nf_sane_lock);
-       sb_ptr = skb_header_pointer(skb, dataoff, datalen, sane_buffer);
-       if (!sb_ptr) {
-               spin_unlock_bh(&nf_sane_lock);
-               return NF_ACCEPT;
-       }
-
        if (dir == IP_CT_DIR_ORIGINAL) {
+               const struct sane_request *req;
+
                if (datalen != sizeof(struct sane_request))
-                       goto out;
+                       return NF_ACCEPT;
+
+               req = skb_header_pointer(skb, dataoff, datalen, &buf.req);
+               if (!req)
+                       return NF_ACCEPT;
 
-               req = sb_ptr;
                if (req->RPC_code != htonl(SANE_NET_START)) {
                        /* Not an interesting command */
-                       ct_sane_info->state = SANE_STATE_NORMAL;
-                       goto out;
+                       WRITE_ONCE(ct_sane_info->state, SANE_STATE_NORMAL);
+                       return NF_ACCEPT;
                }
 
                /* We're interested in the next reply */
-               ct_sane_info->state = SANE_STATE_START_REQUESTED;
-               goto out;
+               WRITE_ONCE(ct_sane_info->state, SANE_STATE_START_REQUESTED);
+               return NF_ACCEPT;
        }
 
+       /* IP_CT_DIR_REPLY */
+
        /* Is it a reply to an uninteresting command? */
-       if (ct_sane_info->state != SANE_STATE_START_REQUESTED)
-               goto out;
+       if (READ_ONCE(ct_sane_info->state) != SANE_STATE_START_REQUESTED)
+               return NF_ACCEPT;
 
        /* It's a reply to SANE_NET_START. */
-       ct_sane_info->state = SANE_STATE_NORMAL;
+       WRITE_ONCE(ct_sane_info->state, SANE_STATE_NORMAL);
 
        if (datalen < sizeof(struct sane_reply_net_start)) {
                pr_debug("NET_START reply too short\n");
-               goto out;
+               return NF_ACCEPT;
        }
 
-       reply = sb_ptr;
+       datalen = sizeof(struct sane_reply_net_start);
+
+       reply = skb_header_pointer(skb, dataoff, datalen, &buf.repl);
+       if (!reply)
+               return NF_ACCEPT;
+
        if (reply->status != htonl(SANE_STATUS_SUCCESS)) {
                /* saned refused the command */
                pr_debug("unsuccessful SANE_STATUS = %u\n",
                         ntohl(reply->status));
-               goto out;
+               return NF_ACCEPT;
        }
 
        /* Invalid saned reply? Ignore it. */
        if (reply->zero != 0)
-               goto out;
+               return NF_ACCEPT;
 
        exp = nf_ct_expect_alloc(ct);
        if (exp == NULL) {
                nf_ct_helper_log(skb, ct, "cannot alloc expectation");
-               ret = NF_DROP;
-               goto out;
+               return NF_DROP;
        }
 
        tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
@@ -162,9 +163,6 @@ static int help(struct sk_buff *skb,
        }
 
        nf_ct_expect_put(exp);
-
-out:
-       spin_unlock_bh(&nf_sane_lock);
        return ret;
 }
 
@@ -178,7 +176,6 @@ static const struct nf_conntrack_expect_policy sane_exp_policy = {
 static void __exit nf_conntrack_sane_fini(void)
 {
        nf_conntrack_helpers_unregister(sane, ports_c * 2);
-       kfree(sane_buffer);
 }
 
 static int __init nf_conntrack_sane_init(void)
@@ -187,10 +184,6 @@ static int __init nf_conntrack_sane_init(void)
 
        NF_CT_HELPER_BUILD_BUG_ON(sizeof(struct nf_ct_sane_master));
 
-       sane_buffer = kmalloc(65536, GFP_KERNEL);
-       if (!sane_buffer)
-               return -ENOMEM;
-
        if (ports_c == 0)
                ports[ports_c++] = SANE_PORT;
 
@@ -210,7 +203,6 @@ static int __init nf_conntrack_sane_init(void)
        ret = nf_conntrack_helpers_register(sane, ports_c * 2);
        if (ret < 0) {
                pr_err("failed to register helpers\n");
-               kfree(sane_buffer);
                return ret;
        }
 
index 0589587..4ffe84c 100644 (file)
@@ -561,7 +561,6 @@ enum nf_ct_sysctl_index {
        NF_SYSCTL_CT_LOG_INVALID,
        NF_SYSCTL_CT_EXPECT_MAX,
        NF_SYSCTL_CT_ACCT,
-       NF_SYSCTL_CT_HELPER,
 #ifdef CONFIG_NF_CONNTRACK_EVENTS
        NF_SYSCTL_CT_EVENTS,
 #endif
@@ -680,14 +679,6 @@ static struct ctl_table nf_ct_sysctl_table[] = {
                .extra1         = SYSCTL_ZERO,
                .extra2         = SYSCTL_ONE,
        },
-       [NF_SYSCTL_CT_HELPER] = {
-               .procname       = "nf_conntrack_helper",
-               .maxlen         = sizeof(u8),
-               .mode           = 0644,
-               .proc_handler   = proc_dou8vec_minmax,
-               .extra1         = SYSCTL_ZERO,
-               .extra2         = SYSCTL_ONE,
-       },
 #ifdef CONFIG_NF_CONNTRACK_EVENTS
        [NF_SYSCTL_CT_EVENTS] = {
                .procname       = "nf_conntrack_events",
@@ -1100,7 +1091,6 @@ static int nf_conntrack_standalone_init_sysctl(struct net *net)
        table[NF_SYSCTL_CT_CHECKSUM].data = &net->ct.sysctl_checksum;
        table[NF_SYSCTL_CT_LOG_INVALID].data = &net->ct.sysctl_log_invalid;
        table[NF_SYSCTL_CT_ACCT].data = &net->ct.sysctl_acct;
-       table[NF_SYSCTL_CT_HELPER].data = &cnet->sysctl_auto_assign_helper;
 #ifdef CONFIG_NF_CONNTRACK_EVENTS
        table[NF_SYSCTL_CT_EVENTS].data = &net->ct.sysctl_events;
 #endif
index 765ac77..81c26a9 100644 (file)
@@ -437,12 +437,17 @@ static void nf_flow_offload_gc_step(struct nf_flowtable *flow_table,
        }
 }
 
+void nf_flow_table_gc_run(struct nf_flowtable *flow_table)
+{
+       nf_flow_table_iterate(flow_table, nf_flow_offload_gc_step, NULL);
+}
+
 static void nf_flow_offload_work_gc(struct work_struct *work)
 {
        struct nf_flowtable *flow_table;
 
        flow_table = container_of(work, struct nf_flowtable, gc_work.work);
-       nf_flow_table_iterate(flow_table, nf_flow_offload_gc_step, NULL);
+       nf_flow_table_gc_run(flow_table);
        queue_delayed_work(system_power_efficient_wq, &flow_table->gc_work, HZ);
 }
 
@@ -600,11 +605,11 @@ void nf_flow_table_free(struct nf_flowtable *flow_table)
        mutex_unlock(&flowtable_lock);
 
        cancel_delayed_work_sync(&flow_table->gc_work);
-       nf_flow_table_iterate(flow_table, nf_flow_table_do_cleanup, NULL);
-       nf_flow_table_iterate(flow_table, nf_flow_offload_gc_step, NULL);
        nf_flow_table_offload_flush(flow_table);
-       if (nf_flowtable_hw_offload(flow_table))
-               nf_flow_table_iterate(flow_table, nf_flow_offload_gc_step, NULL);
+       /* ... no more pending work after this stage ... */
+       nf_flow_table_iterate(flow_table, nf_flow_table_do_cleanup, NULL);
+       nf_flow_table_gc_run(flow_table);
+       nf_flow_table_offload_flush_cleanup(flow_table);
        rhashtable_destroy(&flow_table->rhashtable);
 }
 EXPORT_SYMBOL_GPL(nf_flow_table_free);
index 103b6cb..b04645c 100644 (file)
@@ -1074,6 +1074,14 @@ void nf_flow_offload_stats(struct nf_flowtable *flowtable,
        flow_offload_queue_work(offload);
 }
 
+void nf_flow_table_offload_flush_cleanup(struct nf_flowtable *flowtable)
+{
+       if (nf_flowtable_hw_offload(flowtable)) {
+               flush_workqueue(nf_flow_offload_del_wq);
+               nf_flow_table_gc_run(flowtable);
+       }
+}
+
 void nf_flow_table_offload_flush(struct nf_flowtable *flowtable)
 {
        if (nf_flowtable_hw_offload(flowtable)) {
index 3cc8899..8160520 100644 (file)
@@ -32,7 +32,6 @@ static LIST_HEAD(nf_tables_objects);
 static LIST_HEAD(nf_tables_flowtables);
 static LIST_HEAD(nf_tables_destroy_list);
 static DEFINE_SPINLOCK(nf_tables_destroy_list_lock);
-static u64 table_handle;
 
 enum {
        NFT_VALIDATE_SKIP       = 0,
@@ -889,7 +888,7 @@ static int nf_tables_dump_tables(struct sk_buff *skb,
 
        rcu_read_lock();
        nft_net = nft_pernet(net);
-       cb->seq = nft_net->base_seq;
+       cb->seq = READ_ONCE(nft_net->base_seq);
 
        list_for_each_entry_rcu(table, &nft_net->tables, list) {
                if (family != NFPROTO_UNSPEC && family != table->family)
@@ -1235,7 +1234,7 @@ static int nf_tables_newtable(struct sk_buff *skb, const struct nfnl_info *info,
        INIT_LIST_HEAD(&table->flowtables);
        table->family = family;
        table->flags = flags;
-       table->handle = ++table_handle;
+       table->handle = ++nft_net->table_handle;
        if (table->flags & NFT_TABLE_F_OWNER)
                table->nlpid = NETLINK_CB(skb).portid;
 
@@ -1705,7 +1704,7 @@ static int nf_tables_dump_chains(struct sk_buff *skb,
 
        rcu_read_lock();
        nft_net = nft_pernet(net);
-       cb->seq = nft_net->base_seq;
+       cb->seq = READ_ONCE(nft_net->base_seq);
 
        list_for_each_entry_rcu(table, &nft_net->tables, list) {
                if (family != NFPROTO_UNSPEC && family != table->family)
@@ -2167,8 +2166,10 @@ static int nft_basechain_init(struct nft_base_chain *basechain, u8 family,
        chain->flags |= NFT_CHAIN_BASE | flags;
        basechain->policy = NF_ACCEPT;
        if (chain->flags & NFT_CHAIN_HW_OFFLOAD &&
-           !nft_chain_offload_support(basechain))
+           !nft_chain_offload_support(basechain)) {
+               list_splice_init(&basechain->hook_list, &hook->list);
                return -EOPNOTSUPP;
+       }
 
        flow_block_init(&basechain->flow_block);
 
@@ -2196,9 +2197,9 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
                              struct netlink_ext_ack *extack)
 {
        const struct nlattr * const *nla = ctx->nla;
+       struct nft_stats __percpu *stats = NULL;
        struct nft_table *table = ctx->table;
        struct nft_base_chain *basechain;
-       struct nft_stats __percpu *stats;
        struct net *net = ctx->net;
        char name[NFT_NAME_MAXLEN];
        struct nft_rule_blob *blob;
@@ -2236,7 +2237,6 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
                                return PTR_ERR(stats);
                        }
                        rcu_assign_pointer(basechain->stats, stats);
-                       static_branch_inc(&nft_counters_enabled);
                }
 
                err = nft_basechain_init(basechain, family, &hook, flags);
@@ -2319,6 +2319,9 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
                goto err_unregister_hook;
        }
 
+       if (stats)
+               static_branch_inc(&nft_counters_enabled);
+
        table->use++;
 
        return 0;
@@ -2574,6 +2577,9 @@ static int nf_tables_newchain(struct sk_buff *skb, const struct nfnl_info *info,
        nft_ctx_init(&ctx, net, skb, info->nlh, family, table, chain, nla);
 
        if (chain != NULL) {
+               if (chain->flags & NFT_CHAIN_BINDING)
+                       return -EINVAL;
+
                if (info->nlh->nlmsg_flags & NLM_F_EXCL) {
                        NL_SET_BAD_ATTR(extack, attr);
                        return -EEXIST;
@@ -3149,7 +3155,7 @@ static int nf_tables_dump_rules(struct sk_buff *skb,
 
        rcu_read_lock();
        nft_net = nft_pernet(net);
-       cb->seq = nft_net->base_seq;
+       cb->seq = READ_ONCE(nft_net->base_seq);
 
        list_for_each_entry_rcu(table, &nft_net->tables, list) {
                if (family != NFPROTO_UNSPEC && family != table->family)
@@ -3907,7 +3913,7 @@ cont:
                list_for_each_entry(i, &ctx->table->sets, list) {
                        int tmp;
 
-                       if (!nft_is_active_next(ctx->net, set))
+                       if (!nft_is_active_next(ctx->net, i))
                                continue;
                        if (!sscanf(i->name, name, &tmp))
                                continue;
@@ -4133,7 +4139,7 @@ static int nf_tables_dump_sets(struct sk_buff *skb, struct netlink_callback *cb)
 
        rcu_read_lock();
        nft_net = nft_pernet(net);
-       cb->seq = nft_net->base_seq;
+       cb->seq = READ_ONCE(nft_net->base_seq);
 
        list_for_each_entry_rcu(table, &nft_net->tables, list) {
                if (ctx->family != NFPROTO_UNSPEC &&
@@ -4451,6 +4457,11 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info,
                err = nf_tables_set_desc_parse(&desc, nla[NFTA_SET_DESC]);
                if (err < 0)
                        return err;
+
+               if (desc.field_count > 1 && !(flags & NFT_SET_CONCAT))
+                       return -EINVAL;
+       } else if (flags & NFT_SET_CONCAT) {
+               return -EINVAL;
        }
 
        if (nla[NFTA_SET_EXPR] || nla[NFTA_SET_EXPRESSIONS])
@@ -5061,6 +5072,8 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
 
        rcu_read_lock();
        nft_net = nft_pernet(net);
+       cb->seq = READ_ONCE(nft_net->base_seq);
+
        list_for_each_entry_rcu(table, &nft_net->tables, list) {
                if (dump_ctx->ctx.family != NFPROTO_UNSPEC &&
                    dump_ctx->ctx.family != table->family)
@@ -5196,6 +5209,9 @@ static int nft_setelem_parse_flags(const struct nft_set *set,
        if (!(set->flags & NFT_SET_INTERVAL) &&
            *flags & NFT_SET_ELEM_INTERVAL_END)
                return -EINVAL;
+       if ((*flags & (NFT_SET_ELEM_INTERVAL_END | NFT_SET_ELEM_CATCHALL)) ==
+           (NFT_SET_ELEM_INTERVAL_END | NFT_SET_ELEM_CATCHALL))
+               return -EINVAL;
 
        return 0;
 }
@@ -5599,7 +5615,7 @@ int nft_set_elem_expr_clone(const struct nft_ctx *ctx, struct nft_set *set,
 
                err = nft_expr_clone(expr, set->exprs[i]);
                if (err < 0) {
-                       nft_expr_destroy(ctx, expr);
+                       kfree(expr);
                        goto err_expr;
                }
                expr_array[i] = expr;
@@ -5842,6 +5858,24 @@ static void nft_setelem_remove(const struct net *net,
                set->ops->remove(net, set, elem);
 }
 
+static bool nft_setelem_valid_key_end(const struct nft_set *set,
+                                     struct nlattr **nla, u32 flags)
+{
+       if ((set->flags & (NFT_SET_CONCAT | NFT_SET_INTERVAL)) ==
+                         (NFT_SET_CONCAT | NFT_SET_INTERVAL)) {
+               if (flags & NFT_SET_ELEM_INTERVAL_END)
+                       return false;
+               if (!nla[NFTA_SET_ELEM_KEY_END] &&
+                   !(flags & NFT_SET_ELEM_CATCHALL))
+                       return false;
+       } else {
+               if (nla[NFTA_SET_ELEM_KEY_END])
+                       return false;
+       }
+
+       return true;
+}
+
 static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
                            const struct nlattr *attr, u32 nlmsg_flags)
 {
@@ -5892,6 +5926,18 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
                        return -EINVAL;
        }
 
+       if (set->flags & NFT_SET_OBJECT) {
+               if (!nla[NFTA_SET_ELEM_OBJREF] &&
+                   !(flags & NFT_SET_ELEM_INTERVAL_END))
+                       return -EINVAL;
+       } else {
+               if (nla[NFTA_SET_ELEM_OBJREF])
+                       return -EINVAL;
+       }
+
+       if (!nft_setelem_valid_key_end(set, nla, flags))
+               return -EINVAL;
+
        if ((flags & NFT_SET_ELEM_INTERVAL_END) &&
             (nla[NFTA_SET_ELEM_DATA] ||
              nla[NFTA_SET_ELEM_OBJREF] ||
@@ -5899,6 +5945,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
              nla[NFTA_SET_ELEM_EXPIRATION] ||
              nla[NFTA_SET_ELEM_USERDATA] ||
              nla[NFTA_SET_ELEM_EXPR] ||
+             nla[NFTA_SET_ELEM_KEY_END] ||
              nla[NFTA_SET_ELEM_EXPRESSIONS]))
                return -EINVAL;
 
@@ -6029,10 +6076,6 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
        }
 
        if (nla[NFTA_SET_ELEM_OBJREF] != NULL) {
-               if (!(set->flags & NFT_SET_OBJECT)) {
-                       err = -EINVAL;
-                       goto err_parse_key_end;
-               }
                obj = nft_obj_lookup(ctx->net, ctx->table,
                                     nla[NFTA_SET_ELEM_OBJREF],
                                     set->objtype, genmask);
@@ -6325,6 +6368,9 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
        if (!nla[NFTA_SET_ELEM_KEY] && !(flags & NFT_SET_ELEM_CATCHALL))
                return -EINVAL;
 
+       if (!nft_setelem_valid_key_end(set, nla, flags))
+               return -EINVAL;
+
        nft_set_ext_prepare(&tmpl);
 
        if (flags != 0) {
@@ -6941,7 +6987,7 @@ static int nf_tables_dump_obj(struct sk_buff *skb, struct netlink_callback *cb)
 
        rcu_read_lock();
        nft_net = nft_pernet(net);
-       cb->seq = nft_net->base_seq;
+       cb->seq = READ_ONCE(nft_net->base_seq);
 
        list_for_each_entry_rcu(table, &nft_net->tables, list) {
                if (family != NFPROTO_UNSPEC && family != table->family)
@@ -7873,7 +7919,7 @@ static int nf_tables_dump_flowtable(struct sk_buff *skb,
 
        rcu_read_lock();
        nft_net = nft_pernet(net);
-       cb->seq = nft_net->base_seq;
+       cb->seq = READ_ONCE(nft_net->base_seq);
 
        list_for_each_entry_rcu(table, &nft_net->tables, list) {
                if (family != NFPROTO_UNSPEC && family != table->family)
@@ -8806,6 +8852,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
        struct nft_trans_elem *te;
        struct nft_chain *chain;
        struct nft_table *table;
+       unsigned int base_seq;
        LIST_HEAD(adl);
        int err;
 
@@ -8855,9 +8902,12 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
         * Bump generation counter, invalidate any dump in progress.
         * Cannot fail after this point.
         */
-       while (++nft_net->base_seq == 0)
+       base_seq = READ_ONCE(nft_net->base_seq);
+       while (++base_seq == 0)
                ;
 
+       WRITE_ONCE(nft_net->base_seq, base_seq);
+
        /* step 3. Start new generation, rules_gen_X now in use. */
        net->nft.gencursor = nft_gencursor_next(net);
 
@@ -9419,13 +9469,9 @@ static int nf_tables_check_loops(const struct nft_ctx *ctx,
                                break;
                        }
                }
-
-               cond_resched();
        }
 
        list_for_each_entry(set, &ctx->table->sets, list) {
-               cond_resched();
-
                if (!nft_is_active_next(ctx->net, set))
                        continue;
                if (!(set->flags & NFT_SET_MAP) ||
@@ -9667,6 +9713,8 @@ static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
                        return PTR_ERR(chain);
                if (nft_is_base_chain(chain))
                        return -EOPNOTSUPP;
+               if (nft_chain_is_bound(chain))
+                       return -EINVAL;
                if (desc->flags & NFT_DATA_DESC_SETELEM &&
                    chain->flags & NFT_CHAIN_BINDING)
                        return -EINVAL;
index c24b124..9c44518 100644 (file)
@@ -44,6 +44,10 @@ MODULE_DESCRIPTION("Netfilter messages via netlink socket");
 
 static unsigned int nfnetlink_pernet_id __read_mostly;
 
+#ifdef CONFIG_NF_CONNTRACK_EVENTS
+static DEFINE_SPINLOCK(nfnl_grp_active_lock);
+#endif
+
 struct nfnl_net {
        struct sock *nfnl;
 };
@@ -654,6 +658,44 @@ static void nfnetlink_rcv(struct sk_buff *skb)
                netlink_rcv_skb(skb, nfnetlink_rcv_msg);
 }
 
+static void nfnetlink_bind_event(struct net *net, unsigned int group)
+{
+#ifdef CONFIG_NF_CONNTRACK_EVENTS
+       int type, group_bit;
+       u8 v;
+
+       /* All NFNLGRP_CONNTRACK_* group bits fit into u8.
+        * The other groups are not relevant and can be ignored.
+        */
+       if (group >= 8)
+               return;
+
+       type = nfnl_group2type[group];
+
+       switch (type) {
+       case NFNL_SUBSYS_CTNETLINK:
+               break;
+       case NFNL_SUBSYS_CTNETLINK_EXP:
+               break;
+       default:
+               return;
+       }
+
+       group_bit = (1 << group);
+
+       spin_lock(&nfnl_grp_active_lock);
+       v = READ_ONCE(net->ct.ctnetlink_has_listener);
+       if ((v & group_bit) == 0) {
+               v |= group_bit;
+
+               /* read concurrently without nfnl_grp_active_lock held. */
+               WRITE_ONCE(net->ct.ctnetlink_has_listener, v);
+       }
+
+       spin_unlock(&nfnl_grp_active_lock);
+#endif
+}
+
 static int nfnetlink_bind(struct net *net, int group)
 {
        const struct nfnetlink_subsystem *ss;
@@ -670,28 +712,45 @@ static int nfnetlink_bind(struct net *net, int group)
        if (!ss)
                request_module_nowait("nfnetlink-subsys-%d", type);
 
-#ifdef CONFIG_NF_CONNTRACK_EVENTS
-       if (type == NFNL_SUBSYS_CTNETLINK) {
-               nfnl_lock(NFNL_SUBSYS_CTNETLINK);
-               WRITE_ONCE(net->ct.ctnetlink_has_listener, true);
-               nfnl_unlock(NFNL_SUBSYS_CTNETLINK);
-       }
-#endif
+       nfnetlink_bind_event(net, group);
        return 0;
 }
 
 static void nfnetlink_unbind(struct net *net, int group)
 {
 #ifdef CONFIG_NF_CONNTRACK_EVENTS
+       int type, group_bit;
+
        if (group <= NFNLGRP_NONE || group > NFNLGRP_MAX)
                return;
 
-       if (nfnl_group2type[group] == NFNL_SUBSYS_CTNETLINK) {
-               nfnl_lock(NFNL_SUBSYS_CTNETLINK);
-               if (!nfnetlink_has_listeners(net, group))
-                       WRITE_ONCE(net->ct.ctnetlink_has_listener, false);
-               nfnl_unlock(NFNL_SUBSYS_CTNETLINK);
+       type = nfnl_group2type[group];
+
+       switch (type) {
+       case NFNL_SUBSYS_CTNETLINK:
+               break;
+       case NFNL_SUBSYS_CTNETLINK_EXP:
+               break;
+       default:
+               return;
+       }
+
+       /* ctnetlink_has_listener is u8 */
+       if (group >= 8)
+               return;
+
+       group_bit = (1 << group);
+
+       spin_lock(&nfnl_grp_active_lock);
+       if (!nfnetlink_has_listeners(net, group)) {
+               u8 v = READ_ONCE(net->ct.ctnetlink_has_listener);
+
+               v &= ~group_bit;
+
+               /* read concurrently without nfnl_grp_active_lock held. */
+               WRITE_ONCE(net->ct.ctnetlink_has_listener, v);
        }
+       spin_unlock(&nfnl_grp_active_lock);
 #endif
 }
 
index b04995c..a3f01f2 100644 (file)
@@ -1089,9 +1089,6 @@ static int nft_ct_helper_obj_init(const struct nft_ctx *ctx,
        if (err < 0)
                goto err_put_helper;
 
-       /* Avoid the bogus warning, helper will be assigned after CT init */
-       nf_ct_set_auto_assign_helper_warned(ctx->net);
-
        return 0;
 
 err_put_helper:
index 0053a69..89342cc 100644 (file)
@@ -115,9 +115,21 @@ static int nft_osf_validate(const struct nft_ctx *ctx,
                            const struct nft_expr *expr,
                            const struct nft_data **data)
 {
-       return nft_chain_validate_hooks(ctx->chain, (1 << NF_INET_LOCAL_IN) |
-                                                   (1 << NF_INET_PRE_ROUTING) |
-                                                   (1 << NF_INET_FORWARD));
+       unsigned int hooks;
+
+       switch (ctx->family) {
+       case NFPROTO_IPV4:
+       case NFPROTO_IPV6:
+       case NFPROTO_INET:
+               hooks = (1 << NF_INET_LOCAL_IN) |
+                       (1 << NF_INET_PRE_ROUTING) |
+                       (1 << NF_INET_FORWARD);
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       return nft_chain_validate_hooks(ctx->chain, hooks);
 }
 
 static bool nft_osf_reduce(struct nft_regs_track *track,
index 2e7ac00..eb0e40c 100644 (file)
@@ -740,17 +740,23 @@ static int nft_payload_set_init(const struct nft_ctx *ctx,
                                const struct nlattr * const tb[])
 {
        struct nft_payload_set *priv = nft_expr_priv(expr);
+       u32 csum_offset, csum_type = NFT_PAYLOAD_CSUM_NONE;
+       int err;
 
        priv->base        = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_BASE]));
        priv->offset      = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_OFFSET]));
        priv->len         = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_LEN]));
 
        if (tb[NFTA_PAYLOAD_CSUM_TYPE])
-               priv->csum_type =
-                       ntohl(nla_get_be32(tb[NFTA_PAYLOAD_CSUM_TYPE]));
-       if (tb[NFTA_PAYLOAD_CSUM_OFFSET])
-               priv->csum_offset =
-                       ntohl(nla_get_be32(tb[NFTA_PAYLOAD_CSUM_OFFSET]));
+               csum_type = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_CSUM_TYPE]));
+       if (tb[NFTA_PAYLOAD_CSUM_OFFSET]) {
+               err = nft_parse_u32_check(tb[NFTA_PAYLOAD_CSUM_OFFSET], U8_MAX,
+                                         &csum_offset);
+               if (err < 0)
+                       return err;
+
+               priv->csum_offset = csum_offset;
+       }
        if (tb[NFTA_PAYLOAD_CSUM_FLAGS]) {
                u32 flags;
 
@@ -761,7 +767,7 @@ static int nft_payload_set_init(const struct nft_ctx *ctx,
                priv->csum_flags = flags;
        }
 
-       switch (priv->csum_type) {
+       switch (csum_type) {
        case NFT_PAYLOAD_CSUM_NONE:
        case NFT_PAYLOAD_CSUM_INET:
                break;
@@ -775,6 +781,7 @@ static int nft_payload_set_init(const struct nft_ctx *ctx,
        default:
                return -EOPNOTSUPP;
        }
+       priv->csum_type = csum_type;
 
        return nft_parse_register_load(tb[NFTA_PAYLOAD_SREG], &priv->sreg,
                                       priv->len);
@@ -833,6 +840,7 @@ nft_payload_select_ops(const struct nft_ctx *ctx,
 {
        enum nft_payload_bases base;
        unsigned int offset, len;
+       int err;
 
        if (tb[NFTA_PAYLOAD_BASE] == NULL ||
            tb[NFTA_PAYLOAD_OFFSET] == NULL ||
@@ -859,8 +867,13 @@ nft_payload_select_ops(const struct nft_ctx *ctx,
        if (tb[NFTA_PAYLOAD_DREG] == NULL)
                return ERR_PTR(-EINVAL);
 
-       offset = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_OFFSET]));
-       len    = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_LEN]));
+       err = nft_parse_u32_check(tb[NFTA_PAYLOAD_OFFSET], U8_MAX, &offset);
+       if (err < 0)
+               return ERR_PTR(err);
+
+       err = nft_parse_u32_check(tb[NFTA_PAYLOAD_LEN], U8_MAX, &len);
+       if (err < 0)
+               return ERR_PTR(err);
 
        if (len <= 4 && is_power_of_2(len) && IS_ALIGNED(offset, len) &&
            base != NFT_PAYLOAD_LL_HEADER && base != NFT_PAYLOAD_INNER_HEADER)
index 68b2eed..62da25a 100644 (file)
@@ -312,6 +312,13 @@ static int nft_tproxy_dump(struct sk_buff *skb,
        return 0;
 }
 
+static int nft_tproxy_validate(const struct nft_ctx *ctx,
+                              const struct nft_expr *expr,
+                              const struct nft_data **data)
+{
+       return nft_chain_validate_hooks(ctx->chain, 1 << NF_INET_PRE_ROUTING);
+}
+
 static struct nft_expr_type nft_tproxy_type;
 static const struct nft_expr_ops nft_tproxy_ops = {
        .type           = &nft_tproxy_type,
@@ -321,6 +328,7 @@ static const struct nft_expr_ops nft_tproxy_ops = {
        .destroy        = nft_tproxy_destroy,
        .dump           = nft_tproxy_dump,
        .reduce         = NFT_REDUCE_READONLY,
+       .validate       = nft_tproxy_validate,
 };
 
 static struct nft_expr_type nft_tproxy_type __read_mostly = {
index 5edaade..983ade4 100644 (file)
@@ -161,6 +161,7 @@ static const struct nft_expr_ops nft_tunnel_get_ops = {
 
 static struct nft_expr_type nft_tunnel_type __read_mostly = {
        .name           = "tunnel",
+       .family         = NFPROTO_NETDEV,
        .ops            = &nft_tunnel_get_ops,
        .policy         = nft_tunnel_policy,
        .maxattr        = NFTA_TUNNEL_MAX,
index 1afca2a..5701092 100644 (file)
@@ -1174,13 +1174,17 @@ static int ctrl_dumppolicy_start(struct netlink_callback *cb)
                                                             op.policy,
                                                             op.maxattr);
                        if (err)
-                               return err;
+                               goto err_free_state;
                }
        }
 
        if (!ctx->state)
                return -ENODATA;
        return 0;
+
+err_free_state:
+       netlink_policy_dump_free(ctx->state);
+       return err;
 }
 
 static void *ctrl_dumppolicy_prep(struct sk_buff *skb,
index 8d7c900..87e3de0 100644 (file)
@@ -144,7 +144,7 @@ int netlink_policy_dump_add_policy(struct netlink_policy_dump_state **pstate,
 
        err = add_policy(&state, policy, maxtype);
        if (err)
-               return err;
+               goto err_try_undo;
 
        for (policy_idx = 0;
             policy_idx < state->n_alloc && state->policies[policy_idx].policy;
@@ -164,7 +164,7 @@ int netlink_policy_dump_add_policy(struct netlink_policy_dump_state **pstate,
                                                 policy[type].nested_policy,
                                                 policy[type].len);
                                if (err)
-                                       return err;
+                                       goto err_try_undo;
                                break;
                        default:
                                break;
@@ -174,6 +174,16 @@ int netlink_policy_dump_add_policy(struct netlink_policy_dump_state **pstate,
 
        *pstate = state;
        return 0;
+
+err_try_undo:
+       /* Try to preserve reasonable unwind semantics - if we're starting from
+        * scratch clean up fully, otherwise record what we got and caller will.
+        */
+       if (!*pstate)
+               netlink_policy_dump_free(state);
+       else
+               *pstate = state;
+       return err;
 }
 
 static bool
index 7e8a39a..6c9d153 100644 (file)
@@ -1802,7 +1802,7 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
                                ovs_dp_reset_user_features(skb, info);
                }
 
-               goto err_unlock_and_destroy_meters;
+               goto err_destroy_portids;
        }
 
        err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid,
@@ -1817,6 +1817,8 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
        ovs_notify(&dp_datapath_genl_family, reply, info);
        return 0;
 
+err_destroy_portids:
+       kfree(rcu_dereference_raw(dp->upcall_portids));
 err_unlock_and_destroy_meters:
        ovs_unlock();
        ovs_meters_exit(dp);
index 18196e1..9ced13c 100644 (file)
@@ -78,11 +78,6 @@ static int qcom_mhi_qrtr_probe(struct mhi_device *mhi_dev,
        struct qrtr_mhi_dev *qdev;
        int rc;
 
-       /* start channels */
-       rc = mhi_prepare_for_transfer_autoqueue(mhi_dev);
-       if (rc)
-               return rc;
-
        qdev = devm_kzalloc(&mhi_dev->dev, sizeof(*qdev), GFP_KERNEL);
        if (!qdev)
                return -ENOMEM;
@@ -96,6 +91,13 @@ static int qcom_mhi_qrtr_probe(struct mhi_device *mhi_dev,
        if (rc)
                return rc;
 
+       /* start channels */
+       rc = mhi_prepare_for_transfer_autoqueue(mhi_dev);
+       if (rc) {
+               qrtr_endpoint_unregister(&qdev->ep);
+               return rc;
+       }
+
        dev_dbg(qdev->dev, "Qualcomm MHI QRTR driver probed\n");
 
        return 0;
index 6fdedd9..cfbf0e1 100644 (file)
@@ -363,6 +363,7 @@ static int acquire_refill(struct rds_connection *conn)
 static void release_refill(struct rds_connection *conn)
 {
        clear_bit(RDS_RECV_REFILL, &conn->c_flags);
+       smp_mb__after_atomic();
 
        /* We don't use wait_on_bit()/wake_up_bit() because our waking is in a
         * hot path and finding waiters is very rare.  We don't want to walk
index 11c45c8..036d92c 100644 (file)
@@ -96,7 +96,8 @@ static void rose_loopback_timer(struct timer_list *unused)
                }
 
                if (frametype == ROSE_CALL_REQUEST) {
-                       if (!rose_loopback_neigh->dev) {
+                       if (!rose_loopback_neigh->dev &&
+                           !rose_loopback_neigh->loopback) {
                                kfree_skb(skb);
                                continue;
                        }
index 5714360..62c7070 100644 (file)
@@ -982,6 +982,7 @@ void rxrpc_send_keepalive(struct rxrpc_peer *);
 /*
  * peer_event.c
  */
+void rxrpc_encap_err_rcv(struct sock *sk, struct sk_buff *skb, unsigned int udp_offset);
 void rxrpc_error_report(struct sock *);
 void rxrpc_peer_keepalive_worker(struct work_struct *);
 
index f8ecad2..2a93e7b 100644 (file)
@@ -166,7 +166,7 @@ static void rxrpc_resend(struct rxrpc_call *call, unsigned long now_j)
        _enter("{%d,%d}", call->tx_hard_ack, call->tx_top);
 
        now = ktime_get_real();
-       max_age = ktime_sub(now, jiffies_to_usecs(call->peer->rto_j));
+       max_age = ktime_sub_us(now, jiffies_to_usecs(call->peer->rto_j));
 
        spin_lock_bh(&call->lock);
 
index 84d0a41..6401cdf 100644 (file)
@@ -285,8 +285,10 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx,
        _enter("%p,%lx", rx, p->user_call_ID);
 
        limiter = rxrpc_get_call_slot(p, gfp);
-       if (!limiter)
+       if (!limiter) {
+               release_sock(&rx->sk);
                return ERR_PTR(-ERESTARTSYS);
+       }
 
        call = rxrpc_alloc_client_call(rx, srx, gfp, debug_id);
        if (IS_ERR(call)) {
index 96ecb73..38ea98f 100644 (file)
@@ -137,6 +137,7 @@ static int rxrpc_open_socket(struct rxrpc_local *local, struct net *net)
 
        tuncfg.encap_type = UDP_ENCAP_RXRPC;
        tuncfg.encap_rcv = rxrpc_input_packet;
+       tuncfg.encap_err_rcv = rxrpc_encap_err_rcv;
        tuncfg.sk_user_data = local;
        setup_udp_tunnel_sock(net, local->socket, &tuncfg);
 
@@ -405,6 +406,9 @@ static void rxrpc_local_processor(struct work_struct *work)
                container_of(work, struct rxrpc_local, processor);
        bool again;
 
+       if (local->dead)
+               return;
+
        trace_rxrpc_local(local->debug_id, rxrpc_local_processing,
                          refcount_read(&local->ref), NULL);
 
index be03285..32561e9 100644 (file)
 #include <net/sock.h>
 #include <net/af_rxrpc.h>
 #include <net/ip.h>
+#include <net/icmp.h>
 #include "ar-internal.h"
 
+static void rxrpc_adjust_mtu(struct rxrpc_peer *, unsigned int);
 static void rxrpc_store_error(struct rxrpc_peer *, struct sock_exterr_skb *);
 static void rxrpc_distribute_error(struct rxrpc_peer *, int,
                                   enum rxrpc_call_completion);
 
 /*
- * Find the peer associated with an ICMP packet.
+ * Find the peer associated with an ICMPv4 packet.
  */
 static struct rxrpc_peer *rxrpc_lookup_peer_icmp_rcu(struct rxrpc_local *local,
-                                                    const struct sk_buff *skb,
+                                                    struct sk_buff *skb,
+                                                    unsigned int udp_offset,
+                                                    unsigned int *info,
                                                     struct sockaddr_rxrpc *srx)
 {
-       struct sock_exterr_skb *serr = SKB_EXT_ERR(skb);
+       struct iphdr *ip, *ip0 = ip_hdr(skb);
+       struct icmphdr *icmp = icmp_hdr(skb);
+       struct udphdr *udp = (struct udphdr *)(skb->data + udp_offset);
 
-       _enter("");
+       _enter("%u,%u,%u", ip0->protocol, icmp->type, icmp->code);
+
+       switch (icmp->type) {
+       case ICMP_DEST_UNREACH:
+               *info = ntohs(icmp->un.frag.mtu);
+               fallthrough;
+       case ICMP_TIME_EXCEEDED:
+       case ICMP_PARAMETERPROB:
+               ip = (struct iphdr *)((void *)icmp + 8);
+               break;
+       default:
+               return NULL;
+       }
+
+       memset(srx, 0, sizeof(*srx));
+       srx->transport_type = local->srx.transport_type;
+       srx->transport_len = local->srx.transport_len;
+       srx->transport.family = local->srx.transport.family;
+
+       /* Can we see an ICMP4 packet on an ICMP6 listening socket?  and vice
+        * versa?
+        */
+       switch (srx->transport.family) {
+       case AF_INET:
+               srx->transport_len = sizeof(srx->transport.sin);
+               srx->transport.family = AF_INET;
+               srx->transport.sin.sin_port = udp->dest;
+               memcpy(&srx->transport.sin.sin_addr, &ip->daddr,
+                      sizeof(struct in_addr));
+               break;
+
+#ifdef CONFIG_AF_RXRPC_IPV6
+       case AF_INET6:
+               srx->transport_len = sizeof(srx->transport.sin);
+               srx->transport.family = AF_INET;
+               srx->transport.sin.sin_port = udp->dest;
+               memcpy(&srx->transport.sin.sin_addr, &ip->daddr,
+                      sizeof(struct in_addr));
+               break;
+#endif
+
+       default:
+               WARN_ON_ONCE(1);
+               return NULL;
+       }
+
+       _net("ICMP {%pISp}", &srx->transport);
+       return rxrpc_lookup_peer_rcu(local, srx);
+}
+
+#ifdef CONFIG_AF_RXRPC_IPV6
+/*
+ * Find the peer associated with an ICMPv6 packet.
+ */
+static struct rxrpc_peer *rxrpc_lookup_peer_icmp6_rcu(struct rxrpc_local *local,
+                                                     struct sk_buff *skb,
+                                                     unsigned int udp_offset,
+                                                     unsigned int *info,
+                                                     struct sockaddr_rxrpc *srx)
+{
+       struct icmp6hdr *icmp = icmp6_hdr(skb);
+       struct ipv6hdr *ip, *ip0 = ipv6_hdr(skb);
+       struct udphdr *udp = (struct udphdr *)(skb->data + udp_offset);
+
+       _enter("%u,%u,%u", ip0->nexthdr, icmp->icmp6_type, icmp->icmp6_code);
+
+       switch (icmp->icmp6_type) {
+       case ICMPV6_DEST_UNREACH:
+               *info = ntohl(icmp->icmp6_mtu);
+               fallthrough;
+       case ICMPV6_PKT_TOOBIG:
+       case ICMPV6_TIME_EXCEED:
+       case ICMPV6_PARAMPROB:
+               ip = (struct ipv6hdr *)((void *)icmp + 8);
+               break;
+       default:
+               return NULL;
+       }
 
        memset(srx, 0, sizeof(*srx));
        srx->transport_type = local->srx.transport_type;
@@ -43,6 +126,165 @@ static struct rxrpc_peer *rxrpc_lookup_peer_icmp_rcu(struct rxrpc_local *local,
         */
        switch (srx->transport.family) {
        case AF_INET:
+               _net("Rx ICMP6 on v4 sock");
+               srx->transport_len = sizeof(srx->transport.sin);
+               srx->transport.family = AF_INET;
+               srx->transport.sin.sin_port = udp->dest;
+               memcpy(&srx->transport.sin.sin_addr,
+                      &ip->daddr.s6_addr32[3], sizeof(struct in_addr));
+               break;
+       case AF_INET6:
+               _net("Rx ICMP6");
+               srx->transport.sin.sin_port = udp->dest;
+               memcpy(&srx->transport.sin6.sin6_addr, &ip->daddr,
+                      sizeof(struct in6_addr));
+               break;
+       default:
+               WARN_ON_ONCE(1);
+               return NULL;
+       }
+
+       _net("ICMP {%pISp}", &srx->transport);
+       return rxrpc_lookup_peer_rcu(local, srx);
+}
+#endif /* CONFIG_AF_RXRPC_IPV6 */
+
+/*
+ * Handle an error received on the local endpoint as a tunnel.
+ */
+void rxrpc_encap_err_rcv(struct sock *sk, struct sk_buff *skb,
+                        unsigned int udp_offset)
+{
+       struct sock_extended_err ee;
+       struct sockaddr_rxrpc srx;
+       struct rxrpc_local *local;
+       struct rxrpc_peer *peer;
+       unsigned int info = 0;
+       int err;
+       u8 version = ip_hdr(skb)->version;
+       u8 type = icmp_hdr(skb)->type;
+       u8 code = icmp_hdr(skb)->code;
+
+       rcu_read_lock();
+       local = rcu_dereference_sk_user_data(sk);
+       if (unlikely(!local)) {
+               rcu_read_unlock();
+               return;
+       }
+
+       rxrpc_new_skb(skb, rxrpc_skb_received);
+
+       switch (ip_hdr(skb)->version) {
+       case IPVERSION:
+               peer = rxrpc_lookup_peer_icmp_rcu(local, skb, udp_offset,
+                                                 &info, &srx);
+               break;
+#ifdef CONFIG_AF_RXRPC_IPV6
+       case 6:
+               peer = rxrpc_lookup_peer_icmp6_rcu(local, skb, udp_offset,
+                                                  &info, &srx);
+               break;
+#endif
+       default:
+               rcu_read_unlock();
+               return;
+       }
+
+       if (peer && !rxrpc_get_peer_maybe(peer))
+               peer = NULL;
+       if (!peer) {
+               rcu_read_unlock();
+               return;
+       }
+
+       memset(&ee, 0, sizeof(ee));
+
+       switch (version) {
+       case IPVERSION:
+               switch (type) {
+               case ICMP_DEST_UNREACH:
+                       switch (code) {
+                       case ICMP_FRAG_NEEDED:
+                               rxrpc_adjust_mtu(peer, info);
+                               rcu_read_unlock();
+                               rxrpc_put_peer(peer);
+                               return;
+                       default:
+                               break;
+                       }
+
+                       err = EHOSTUNREACH;
+                       if (code <= NR_ICMP_UNREACH) {
+                               /* Might want to do something different with
+                                * non-fatal errors
+                                */
+                               //harderr = icmp_err_convert[code].fatal;
+                               err = icmp_err_convert[code].errno;
+                       }
+                       break;
+
+               case ICMP_TIME_EXCEEDED:
+                       err = EHOSTUNREACH;
+                       break;
+               default:
+                       err = EPROTO;
+                       break;
+               }
+
+               ee.ee_origin = SO_EE_ORIGIN_ICMP;
+               ee.ee_type = type;
+               ee.ee_code = code;
+               ee.ee_errno = err;
+               break;
+
+#ifdef CONFIG_AF_RXRPC_IPV6
+       case 6:
+               switch (type) {
+               case ICMPV6_PKT_TOOBIG:
+                       rxrpc_adjust_mtu(peer, info);
+                       rcu_read_unlock();
+                       rxrpc_put_peer(peer);
+                       return;
+               }
+
+               icmpv6_err_convert(type, code, &err);
+
+               if (err == EACCES)
+                       err = EHOSTUNREACH;
+
+               ee.ee_origin = SO_EE_ORIGIN_ICMP6;
+               ee.ee_type = type;
+               ee.ee_code = code;
+               ee.ee_errno = err;
+               break;
+#endif
+       }
+
+       trace_rxrpc_rx_icmp(peer, &ee, &srx);
+
+       rxrpc_distribute_error(peer, err, RXRPC_CALL_NETWORK_ERROR);
+       rcu_read_unlock();
+       rxrpc_put_peer(peer);
+}
+
+/*
+ * Find the peer associated with a local error.
+ */
+static struct rxrpc_peer *rxrpc_lookup_peer_local_rcu(struct rxrpc_local *local,
+                                                     const struct sk_buff *skb,
+                                                     struct sockaddr_rxrpc *srx)
+{
+       struct sock_exterr_skb *serr = SKB_EXT_ERR(skb);
+
+       _enter("");
+
+       memset(srx, 0, sizeof(*srx));
+       srx->transport_type = local->srx.transport_type;
+       srx->transport_len = local->srx.transport_len;
+       srx->transport.family = local->srx.transport.family;
+
+       switch (srx->transport.family) {
+       case AF_INET:
                srx->transport_len = sizeof(srx->transport.sin);
                srx->transport.family = AF_INET;
                srx->transport.sin.sin_port = serr->port;
@@ -104,10 +346,8 @@ static struct rxrpc_peer *rxrpc_lookup_peer_icmp_rcu(struct rxrpc_local *local,
 /*
  * Handle an MTU/fragmentation problem.
  */
-static void rxrpc_adjust_mtu(struct rxrpc_peer *peer, struct sock_exterr_skb *serr)
+static void rxrpc_adjust_mtu(struct rxrpc_peer *peer, unsigned int mtu)
 {
-       u32 mtu = serr->ee.ee_info;
-
        _net("Rx ICMP Fragmentation Needed (%d)", mtu);
 
        /* wind down the local interface MTU */
@@ -148,7 +388,7 @@ void rxrpc_error_report(struct sock *sk)
        struct sock_exterr_skb *serr;
        struct sockaddr_rxrpc srx;
        struct rxrpc_local *local;
-       struct rxrpc_peer *peer;
+       struct rxrpc_peer *peer = NULL;
        struct sk_buff *skb;
 
        rcu_read_lock();
@@ -172,41 +412,20 @@ void rxrpc_error_report(struct sock *sk)
        }
        rxrpc_new_skb(skb, rxrpc_skb_received);
        serr = SKB_EXT_ERR(skb);
-       if (!skb->len && serr->ee.ee_origin == SO_EE_ORIGIN_TIMESTAMPING) {
-               _leave("UDP empty message");
-               rcu_read_unlock();
-               rxrpc_free_skb(skb, rxrpc_skb_freed);
-               return;
-       }
 
-       peer = rxrpc_lookup_peer_icmp_rcu(local, skb, &srx);
-       if (peer && !rxrpc_get_peer_maybe(peer))
-               peer = NULL;
-       if (!peer) {
-               rcu_read_unlock();
-               rxrpc_free_skb(skb, rxrpc_skb_freed);
-               _leave(" [no peer]");
-               return;
-       }
-
-       trace_rxrpc_rx_icmp(peer, &serr->ee, &srx);
-
-       if ((serr->ee.ee_origin == SO_EE_ORIGIN_ICMP &&
-            serr->ee.ee_type == ICMP_DEST_UNREACH &&
-            serr->ee.ee_code == ICMP_FRAG_NEEDED)) {
-               rxrpc_adjust_mtu(peer, serr);
-               rcu_read_unlock();
-               rxrpc_free_skb(skb, rxrpc_skb_freed);
-               rxrpc_put_peer(peer);
-               _leave(" [MTU update]");
-               return;
+       if (serr->ee.ee_origin == SO_EE_ORIGIN_LOCAL) {
+               peer = rxrpc_lookup_peer_local_rcu(local, skb, &srx);
+               if (peer && !rxrpc_get_peer_maybe(peer))
+                       peer = NULL;
+               if (peer) {
+                       trace_rxrpc_rx_icmp(peer, &serr->ee, &srx);
+                       rxrpc_store_error(peer, serr);
+               }
        }
 
-       rxrpc_store_error(peer, serr);
        rcu_read_unlock();
        rxrpc_free_skb(skb, rxrpc_skb_freed);
        rxrpc_put_peer(peer);
-
        _leave("");
 }
 
index 250f23b..7e39c26 100644 (file)
@@ -771,46 +771,3 @@ call_complete:
        goto out;
 }
 EXPORT_SYMBOL(rxrpc_kernel_recv_data);
-
-/**
- * rxrpc_kernel_get_reply_time - Get timestamp on first reply packet
- * @sock: The socket that the call exists on
- * @call: The call to query
- * @_ts: Where to put the timestamp
- *
- * Retrieve the timestamp from the first DATA packet of the reply if it is
- * in the ring.  Returns true if successful, false if not.
- */
-bool rxrpc_kernel_get_reply_time(struct socket *sock, struct rxrpc_call *call,
-                                ktime_t *_ts)
-{
-       struct sk_buff *skb;
-       rxrpc_seq_t hard_ack, top, seq;
-       bool success = false;
-
-       mutex_lock(&call->user_mutex);
-
-       if (READ_ONCE(call->state) != RXRPC_CALL_CLIENT_RECV_REPLY)
-               goto out;
-
-       hard_ack = call->rx_hard_ack;
-       if (hard_ack != 0)
-               goto out;
-
-       seq = hard_ack + 1;
-       top = smp_load_acquire(&call->rx_top);
-       if (after(seq, top))
-               goto out;
-
-       skb = call->rxtx_buffer[seq & RXRPC_RXTX_BUFF_MASK];
-       if (!skb)
-               goto out;
-
-       *_ts = skb_get_ktime(skb);
-       success = true;
-
-out:
-       mutex_unlock(&call->user_mutex);
-       return success;
-}
-EXPORT_SYMBOL(rxrpc_kernel_get_reply_time);
index 258917a..78fa052 100644 (file)
@@ -540,7 +540,7 @@ static int rxkad_verify_packet_2(struct rxrpc_call *call, struct sk_buff *skb,
         * directly into the target buffer.
         */
        sg = _sg;
-       nsg = skb_shinfo(skb)->nr_frags;
+       nsg = skb_shinfo(skb)->nr_frags + 1;
        if (nsg <= 4) {
                nsg = 4;
        } else {
index 1d38e27..3c3a626 100644 (file)
@@ -51,10 +51,7 @@ static int rxrpc_wait_for_tx_window_intr(struct rxrpc_sock *rx,
                        return sock_intr_errno(*timeo);
 
                trace_rxrpc_transmit(call, rxrpc_transmit_wait);
-               mutex_unlock(&call->user_mutex);
                *timeo = schedule_timeout(*timeo);
-               if (mutex_lock_interruptible(&call->user_mutex) < 0)
-                       return sock_intr_errno(*timeo);
        }
 }
 
@@ -290,37 +287,48 @@ out:
 static int rxrpc_send_data(struct rxrpc_sock *rx,
                           struct rxrpc_call *call,
                           struct msghdr *msg, size_t len,
-                          rxrpc_notify_end_tx_t notify_end_tx)
+                          rxrpc_notify_end_tx_t notify_end_tx,
+                          bool *_dropped_lock)
 {
        struct rxrpc_skb_priv *sp;
        struct sk_buff *skb;
        struct sock *sk = &rx->sk;
+       enum rxrpc_call_state state;
        long timeo;
-       bool more;
-       int ret, copied;
+       bool more = msg->msg_flags & MSG_MORE;
+       int ret, copied = 0;
 
        timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
 
        /* this should be in poll */
        sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk);
 
+reload:
+       ret = -EPIPE;
        if (sk->sk_shutdown & SEND_SHUTDOWN)
-               return -EPIPE;
-
-       more = msg->msg_flags & MSG_MORE;
-
+               goto maybe_error;
+       state = READ_ONCE(call->state);
+       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)
+               goto maybe_error;
+
+       ret = -EMSGSIZE;
        if (call->tx_total_len != -1) {
-               if (len > call->tx_total_len)
-                       return -EMSGSIZE;
-               if (!more && len != call->tx_total_len)
-                       return -EMSGSIZE;
+               if (len - copied > call->tx_total_len)
+                       goto maybe_error;
+               if (!more && len - copied != call->tx_total_len)
+                       goto maybe_error;
        }
 
        skb = call->tx_pending;
        call->tx_pending = NULL;
        rxrpc_see_skb(skb, rxrpc_skb_seen);
 
-       copied = 0;
        do {
                /* Check to see if there's a ping ACK to reply to. */
                if (call->ackr_reason == RXRPC_ACK_PING_RESPONSE)
@@ -331,16 +339,8 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
 
                        _debug("alloc");
 
-                       if (!rxrpc_check_tx_space(call, NULL)) {
-                               ret = -EAGAIN;
-                               if (msg->msg_flags & MSG_DONTWAIT)
-                                       goto maybe_error;
-                               ret = rxrpc_wait_for_tx_window(rx, call,
-                                                              &timeo,
-                                                              msg->msg_flags & MSG_WAITALL);
-                               if (ret < 0)
-                                       goto maybe_error;
-                       }
+                       if (!rxrpc_check_tx_space(call, NULL))
+                               goto wait_for_space;
 
                        /* Work out the maximum size of a packet.  Assume that
                         * the security header is going to be in the padded
@@ -468,6 +468,27 @@ maybe_error:
 efault:
        ret = -EFAULT;
        goto out;
+
+wait_for_space:
+       ret = -EAGAIN;
+       if (msg->msg_flags & MSG_DONTWAIT)
+               goto maybe_error;
+       mutex_unlock(&call->user_mutex);
+       *_dropped_lock = true;
+       ret = rxrpc_wait_for_tx_window(rx, call, &timeo,
+                                      msg->msg_flags & MSG_WAITALL);
+       if (ret < 0)
+               goto maybe_error;
+       if (call->interruptibility == RXRPC_INTERRUPTIBLE) {
+               if (mutex_lock_interruptible(&call->user_mutex) < 0) {
+                       ret = sock_intr_errno(timeo);
+                       goto maybe_error;
+               }
+       } else {
+               mutex_lock(&call->user_mutex);
+       }
+       *_dropped_lock = false;
+       goto reload;
 }
 
 /*
@@ -629,6 +650,7 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
        enum rxrpc_call_state state;
        struct rxrpc_call *call;
        unsigned long now, j;
+       bool dropped_lock = false;
        int ret;
 
        struct rxrpc_send_params p = {
@@ -737,21 +759,13 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
                        ret = rxrpc_send_abort_packet(call);
        } else if (p.command != RXRPC_CMD_SEND_DATA) {
                ret = -EINVAL;
-       } else if (rxrpc_is_client_call(call) &&
-                  state != RXRPC_CALL_CLIENT_SEND_REQUEST) {
-               /* request phase complete for this client call */
-               ret = -EPROTO;
-       } else if (rxrpc_is_service_call(call) &&
-                  state != RXRPC_CALL_SERVER_ACK_REQUEST &&
-                  state != RXRPC_CALL_SERVER_SEND_REPLY) {
-               /* Reply phase not begun or not complete for service call. */
-               ret = -EPROTO;
        } else {
-               ret = rxrpc_send_data(rx, call, msg, len, NULL);
+               ret = rxrpc_send_data(rx, call, msg, len, NULL, &dropped_lock);
        }
 
 out_put_unlock:
-       mutex_unlock(&call->user_mutex);
+       if (!dropped_lock)
+               mutex_unlock(&call->user_mutex);
 error_put:
        rxrpc_put_call(call, rxrpc_call_put);
        _leave(" = %d", ret);
@@ -779,6 +793,7 @@ int rxrpc_kernel_send_data(struct socket *sock, struct rxrpc_call *call,
                           struct msghdr *msg, size_t len,
                           rxrpc_notify_end_tx_t notify_end_tx)
 {
+       bool dropped_lock = false;
        int ret;
 
        _enter("{%d,%s},", call->debug_id, rxrpc_call_states[call->state]);
@@ -796,7 +811,7 @@ int rxrpc_kernel_send_data(struct socket *sock, struct rxrpc_call *call,
        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);
+                                     notify_end_tx, &dropped_lock);
                break;
        case RXRPC_CALL_COMPLETE:
                read_lock_bh(&call->state_lock);
@@ -810,7 +825,8 @@ int rxrpc_kernel_send_data(struct socket *sock, struct rxrpc_call *call,
                break;
        }
 
-       mutex_unlock(&call->user_mutex);
+       if (!dropped_lock)
+               mutex_unlock(&call->user_mutex);
        _leave(" = %d", ret);
        return ret;
 }
index 3f935cb..48712bc 100644 (file)
@@ -424,6 +424,11 @@ static int route4_set_parms(struct net *net, struct tcf_proto *tp,
                        return -EINVAL;
        }
 
+       if (!nhandle) {
+               NL_SET_ERR_MSG(extack, "Replacing with handle of 0 is invalid");
+               return -EINVAL;
+       }
+
        h1 = to_hash(nhandle);
        b = rtnl_dereference(head->table[h1]);
        if (!b) {
@@ -477,6 +482,11 @@ static int route4_change(struct net *net, struct sk_buff *in_skb,
        int err;
        bool new = true;
 
+       if (!handle) {
+               NL_SET_ERR_MSG(extack, "Creating with handle of 0 is invalid");
+               return -EINVAL;
+       }
+
        if (opt == NULL)
                return handle ? -EINVAL : 0;
 
index d47b968..7a8ea03 100644 (file)
@@ -409,7 +409,7 @@ static inline bool qdisc_restart(struct Qdisc *q, int *packets)
 
 void __qdisc_run(struct Qdisc *q)
 {
-       int quota = dev_tx_weight;
+       int quota = READ_ONCE(dev_tx_weight);
        int packets;
 
        while (qdisc_restart(q, &packets)) {
@@ -1122,6 +1122,21 @@ struct Qdisc *dev_graft_qdisc(struct netdev_queue *dev_queue,
 }
 EXPORT_SYMBOL(dev_graft_qdisc);
 
+static void shutdown_scheduler_queue(struct net_device *dev,
+                                    struct netdev_queue *dev_queue,
+                                    void *_qdisc_default)
+{
+       struct Qdisc *qdisc = dev_queue->qdisc_sleeping;
+       struct Qdisc *qdisc_default = _qdisc_default;
+
+       if (qdisc) {
+               rcu_assign_pointer(dev_queue->qdisc, qdisc_default);
+               dev_queue->qdisc_sleeping = qdisc_default;
+
+               qdisc_put(qdisc);
+       }
+}
+
 static void attach_one_default_qdisc(struct net_device *dev,
                                     struct netdev_queue *dev_queue,
                                     void *_unused)
@@ -1169,6 +1184,7 @@ static void attach_default_qdiscs(struct net_device *dev)
        if (qdisc == &noop_qdisc) {
                netdev_warn(dev, "default qdisc (%s) fail, fallback to %s\n",
                            default_qdisc_ops->id, noqueue_qdisc_ops.id);
+               netdev_for_each_tx_queue(dev, shutdown_scheduler_queue, &noop_qdisc);
                dev->priv_flags |= IFF_NO_QUEUE;
                netdev_for_each_tx_queue(dev, attach_one_default_qdisc, NULL);
                qdisc = txq->qdisc_sleeping;
@@ -1447,21 +1463,6 @@ void dev_init_scheduler(struct net_device *dev)
        timer_setup(&dev->watchdog_timer, dev_watchdog, 0);
 }
 
-static void shutdown_scheduler_queue(struct net_device *dev,
-                                    struct netdev_queue *dev_queue,
-                                    void *_qdisc_default)
-{
-       struct Qdisc *qdisc = dev_queue->qdisc_sleeping;
-       struct Qdisc *qdisc_default = _qdisc_default;
-
-       if (qdisc) {
-               rcu_assign_pointer(dev_queue->qdisc, qdisc_default);
-               dev_queue->qdisc_sleeping = qdisc_default;
-
-               qdisc_put(qdisc);
-       }
-}
-
 void dev_shutdown(struct net_device *dev)
 {
        netdev_for_each_tx_queue(dev, shutdown_scheduler_queue, &noop_qdisc);
index 3d061a1..2829455 100644 (file)
@@ -135,15 +135,15 @@ static void increment_one_qlen(u32 sfbhash, u32 slot, struct sfb_sched_data *q)
        }
 }
 
-static void increment_qlen(const struct sk_buff *skb, struct sfb_sched_data *q)
+static void increment_qlen(const struct sfb_skb_cb *cb, struct sfb_sched_data *q)
 {
        u32 sfbhash;
 
-       sfbhash = sfb_hash(skb, 0);
+       sfbhash = cb->hashes[0];
        if (sfbhash)
                increment_one_qlen(sfbhash, 0, q);
 
-       sfbhash = sfb_hash(skb, 1);
+       sfbhash = cb->hashes[1];
        if (sfbhash)
                increment_one_qlen(sfbhash, 1, q);
 }
@@ -281,8 +281,10 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch,
 {
 
        struct sfb_sched_data *q = qdisc_priv(sch);
+       unsigned int len = qdisc_pkt_len(skb);
        struct Qdisc *child = q->qdisc;
        struct tcf_proto *fl;
+       struct sfb_skb_cb cb;
        int i;
        u32 p_min = ~0;
        u32 minqlen = ~0;
@@ -399,11 +401,12 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch,
        }
 
 enqueue:
+       memcpy(&cb, sfb_skb_cb(skb), sizeof(cb));
        ret = qdisc_enqueue(skb, child, to_free);
        if (likely(ret == NET_XMIT_SUCCESS)) {
-               qdisc_qstats_backlog_inc(sch, skb);
+               sch->qstats.backlog += len;
                sch->q.qlen++;
-               increment_qlen(skb, q);
+               increment_qlen(&cb, q);
        } else if (net_xmit_drop_count(ret)) {
                q->stats.childdrop++;
                qdisc_qstats_drop(sch);
index 7210227..36079fd 100644 (file)
@@ -356,6 +356,7 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt,
        struct nlattr *tb[TCA_TBF_MAX + 1];
        struct tc_tbf_qopt *qopt;
        struct Qdisc *child = NULL;
+       struct Qdisc *old = NULL;
        struct psched_ratecfg rate;
        struct psched_ratecfg peak;
        u64 max_size;
@@ -447,7 +448,7 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt,
        sch_tree_lock(sch);
        if (child) {
                qdisc_tree_flush_backlog(q->qdisc);
-               qdisc_put(q->qdisc);
+               old = q->qdisc;
                q->qdisc = child;
        }
        q->limit = qopt->limit;
@@ -467,6 +468,7 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt,
        memcpy(&q->peak, &peak, sizeof(struct psched_ratecfg));
 
        sch_tree_unlock(sch);
+       qdisc_put(old);
        err = 0;
 
        tbf_offload_change(sch);
index 79c1318..0939cc3 100644 (file)
@@ -1855,7 +1855,6 @@ static void smc_listen_out_connected(struct smc_sock *new_smc)
 {
        struct sock *newsmcsk = &new_smc->sk;
 
-       sk_refcnt_debug_inc(newsmcsk);
        if (newsmcsk->sk_state == SMC_INIT)
                newsmcsk->sk_state = SMC_ACTIVE;
 
index ff49a11..ebf56cd 100644 (file)
@@ -757,6 +757,7 @@ int smcr_link_init(struct smc_link_group *lgr, struct smc_link *lnk,
        lnk->lgr = lgr;
        smc_lgr_hold(lgr); /* lgr_put in smcr_link_clear() */
        lnk->link_idx = link_idx;
+       lnk->wr_rx_id_compl = 0;
        smc_ibdev_cnt_inc(lnk);
        smcr_copy_dev_info_to_link(lnk);
        atomic_set(&lnk->conn_cnt, 0);
index fe8b524..285f9bd 100644 (file)
@@ -115,8 +115,10 @@ struct smc_link {
        dma_addr_t              wr_rx_dma_addr; /* DMA address of wr_rx_bufs */
        dma_addr_t              wr_rx_v2_dma_addr; /* DMA address of v2 rx buf*/
        u64                     wr_rx_id;       /* seq # of last recv WR */
+       u64                     wr_rx_id_compl; /* seq # of last completed WR */
        u32                     wr_rx_cnt;      /* number of WR recv buffers */
        unsigned long           wr_rx_tstamp;   /* jiffies when last buf rx */
+       wait_queue_head_t       wr_rx_empty_wait; /* wait for RQ empty */
 
        struct ib_reg_wr        wr_reg;         /* WR register memory region */
        wait_queue_head_t       wr_reg_wait;    /* wait for wr_reg result */
index 26f8f24..b0678a4 100644 (file)
@@ -454,6 +454,7 @@ static inline void smc_wr_rx_process_cqes(struct ib_wc wc[], int num)
 
        for (i = 0; i < num; i++) {
                link = wc[i].qp->qp_context;
+               link->wr_rx_id_compl = wc[i].wr_id;
                if (wc[i].status == IB_WC_SUCCESS) {
                        link->wr_rx_tstamp = jiffies;
                        smc_wr_rx_demultiplex(&wc[i]);
@@ -465,6 +466,8 @@ static inline void smc_wr_rx_process_cqes(struct ib_wc wc[], int num)
                        case IB_WC_RNR_RETRY_EXC_ERR:
                        case IB_WC_WR_FLUSH_ERR:
                                smcr_link_down_cond_sched(link);
+                               if (link->wr_rx_id_compl == link->wr_rx_id)
+                                       wake_up(&link->wr_rx_empty_wait);
                                break;
                        default:
                                smc_wr_rx_post(link); /* refill WR RX */
@@ -639,6 +642,7 @@ void smc_wr_free_link(struct smc_link *lnk)
                return;
        ibdev = lnk->smcibdev->ibdev;
 
+       smc_wr_drain_cq(lnk);
        smc_wr_wakeup_reg_wait(lnk);
        smc_wr_wakeup_tx_wait(lnk);
 
@@ -889,6 +893,7 @@ int smc_wr_create_link(struct smc_link *lnk)
        atomic_set(&lnk->wr_tx_refcnt, 0);
        init_waitqueue_head(&lnk->wr_reg_wait);
        atomic_set(&lnk->wr_reg_refcnt, 0);
+       init_waitqueue_head(&lnk->wr_rx_empty_wait);
        return rc;
 
 dma_unmap:
index a54e90a..45e9b89 100644 (file)
@@ -73,6 +73,11 @@ static inline void smc_wr_tx_link_put(struct smc_link *link)
                wake_up_all(&link->wr_tx_wait);
 }
 
+static inline void smc_wr_drain_cq(struct smc_link *lnk)
+{
+       wait_event(lnk->wr_rx_empty_wait, lnk->wr_rx_id_compl == lnk->wr_rx_id);
+}
+
 static inline void smc_wr_wakeup_tx_wait(struct smc_link *lnk)
 {
        wake_up_all(&lnk->wr_tx_wait);
index 9b27c5e..7378375 100644 (file)
@@ -1801,7 +1801,7 @@ int __sys_listen(int fd, int backlog)
 
        sock = sockfd_lookup_light(fd, &err, &fput_needed);
        if (sock) {
-               somaxconn = sock_net(sock->sk)->core.sysctl_somaxconn;
+               somaxconn = READ_ONCE(sock_net(sock->sk)->core.sysctl_somaxconn);
                if ((unsigned int)backlog > somaxconn)
                        backlog = somaxconn;
 
index b098e70..c284efa 100644 (file)
@@ -1902,7 +1902,7 @@ call_encode(struct rpc_task *task)
                        break;
                case -EKEYEXPIRED:
                        if (!task->tk_cred_retry) {
-                               rpc_exit(task, task->tk_status);
+                               rpc_call_rpcerror(task, task->tk_status);
                        } else {
                                task->tk_action = call_refresh;
                                task->tk_cred_retry--;
@@ -2873,6 +2873,9 @@ int rpc_clnt_test_and_add_xprt(struct rpc_clnt *clnt,
 
        task = rpc_call_null_helper(clnt, xprt, NULL, RPC_TASK_ASYNC,
                        &rpc_cb_add_xprt_call_ops, data);
+       if (IS_ERR(task))
+               return PTR_ERR(task);
+
        data->xps->xps_nunique_destaddr_xprts++;
        rpc_put_task(task);
 success:
index 7330eb9..c65c90a 100644 (file)
@@ -291,8 +291,10 @@ static ssize_t rpc_sysfs_xprt_state_change(struct kobject *kobj,
        int offline = 0, online = 0, remove = 0;
        struct rpc_xprt_switch *xps = rpc_sysfs_xprt_kobj_get_xprt_switch(kobj);
 
-       if (!xprt)
-               return 0;
+       if (!xprt || !xps) {
+               count = 0;
+               goto out_put;
+       }
 
        if (!strncmp(buf, "offline", 7))
                offline = 1;
index d71eec4..f8fae78 100644 (file)
@@ -1179,11 +1179,8 @@ xprt_request_dequeue_receive_locked(struct rpc_task *task)
 {
        struct rpc_rqst *req = task->tk_rqstp;
 
-       if (test_and_clear_bit(RPC_TASK_NEED_RECV, &task->tk_runstate)) {
+       if (test_and_clear_bit(RPC_TASK_NEED_RECV, &task->tk_runstate))
                xprt_request_rb_remove(req->rq_xprt, req);
-               xdr_free_bvec(&req->rq_rcv_buf);
-               req->rq_private_buf.bvec = NULL;
-       }
 }
 
 /**
@@ -1221,6 +1218,8 @@ void xprt_complete_rqst(struct rpc_task *task, int copied)
 
        xprt->stat.recvs++;
 
+       xdr_free_bvec(&req->rq_rcv_buf);
+       req->rq_private_buf.bvec = NULL;
        req->rq_private_buf.len = copied;
        /* Ensure all writes are done before we update */
        /* req->rq_reply_bytes_recvd */
@@ -1453,6 +1452,7 @@ xprt_request_dequeue_xprt(struct rpc_task *task)
                xprt_request_dequeue_transmit_locked(task);
                xprt_request_dequeue_receive_locked(task);
                spin_unlock(&xprt->queue_lock);
+               xdr_free_bvec(&req->rq_rcv_buf);
        }
 }
 
index 2f4d232..9618e44 100644 (file)
@@ -160,7 +160,7 @@ static void map_set(u64 *up_map, int i, unsigned int v)
 
 static int map_get(u64 up_map, int i)
 {
-       return (up_map & (1 << i)) >> i;
+       return (up_map & (1ULL << i)) >> i;
 }
 
 static struct tipc_peer *peer_prev(struct tipc_peer *peer)
index f76119f..fe27241 100644 (file)
@@ -2702,7 +2702,9 @@ int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx, int tx)
                        crypto_info->version != TLS_1_3_VERSION &&
                        !!(tfm->__crt_alg->cra_flags & CRYPTO_ALG_ASYNC);
 
-               tls_strp_init(&sw_ctx_rx->strp, sk);
+               rc = tls_strp_init(&sw_ctx_rx->strp, sk);
+               if (rc)
+                       goto free_aead;
        }
 
        goto out;
index aab4346..0878b16 100644 (file)
@@ -65,9 +65,10 @@ static ssize_t ht40allow_map_read(struct file *file,
 {
        struct wiphy *wiphy = file->private_data;
        char *buf;
-       unsigned int offset = 0, buf_size = PAGE_SIZE, i, r;
+       unsigned int offset = 0, buf_size = PAGE_SIZE, i;
        enum nl80211_band band;
        struct ieee80211_supported_band *sband;
+       ssize_t r;
 
        buf = kzalloc(buf_size, GFP_KERNEL);
        if (!buf)
index 6a5f08f..cca5e1c 100644 (file)
@@ -136,7 +136,7 @@ static int ccmp_init_iv_and_aad(const struct ieee80211_hdr *hdr,
        pos = (u8 *) hdr;
        aad[0] = pos[0] & 0x8f;
        aad[1] = pos[1] & 0xc7;
-       memcpy(aad + 2, hdr->addr1, 3 * ETH_ALEN);
+       memcpy(aad + 2, &hdr->addrs, 3 * ETH_ALEN);
        pos = (u8 *) & hdr->seq_ctrl;
        aad[20] = pos[0] & 0x0f;
        aad[21] = 0;            /* all bits masked */
index f701121..a71a8c6 100644 (file)
@@ -379,6 +379,16 @@ static void xp_check_dma_contiguity(struct xsk_dma_map *dma_map)
 
 static int xp_init_dma_info(struct xsk_buff_pool *pool, struct xsk_dma_map *dma_map)
 {
+       if (!pool->unaligned) {
+               u32 i;
+
+               for (i = 0; i < pool->heads_cnt; i++) {
+                       struct xdp_buff_xsk *xskb = &pool->heads[i];
+
+                       xp_init_xskb_dma(xskb, pool, dma_map->dma_pages, xskb->orig_addr);
+               }
+       }
+
        pool->dma_pages = kvcalloc(dma_map->dma_pages_cnt, sizeof(*pool->dma_pages), GFP_KERNEL);
        if (!pool->dma_pages)
                return -ENOMEM;
@@ -428,12 +438,6 @@ int xp_dma_map(struct xsk_buff_pool *pool, struct device *dev,
 
        if (pool->unaligned)
                xp_check_dma_contiguity(dma_map);
-       else
-               for (i = 0; i < pool->heads_cnt; i++) {
-                       struct xdp_buff_xsk *xskb = &pool->heads[i];
-
-                       xp_init_xskb_dma(xskb, pool, dma_map->dma_pages, xskb->orig_addr);
-               }
 
        err = xp_init_dma_info(pool, dma_map);
        if (err) {
index 82d14ee..974eb97 100644 (file)
@@ -168,7 +168,7 @@ int espintcp_queue_out(struct sock *sk, struct sk_buff *skb)
 {
        struct espintcp_ctx *ctx = espintcp_getctx(sk);
 
-       if (skb_queue_len(&ctx->out_queue) >= netdev_max_backlog)
+       if (skb_queue_len(&ctx->out_queue) >= READ_ONCE(netdev_max_backlog))
                return -ENOBUFS;
 
        __skb_queue_tail(&ctx->out_queue, skb);
index 144238a..b2f4ec9 100644 (file)
@@ -669,7 +669,6 @@ resume:
 
                x->curlft.bytes += skb->len;
                x->curlft.packets++;
-               x->curlft.use_time = ktime_get_real_seconds();
 
                spin_unlock(&x->lock);
 
@@ -783,7 +782,7 @@ int xfrm_trans_queue_net(struct net *net, struct sk_buff *skb,
 
        trans = this_cpu_ptr(&xfrm_trans_tasklet);
 
-       if (skb_queue_len(&trans->queue) >= netdev_max_backlog)
+       if (skb_queue_len(&trans->queue) >= READ_ONCE(netdev_max_backlog))
                return -ENOBUFS;
 
        BUILD_BUG_ON(sizeof(struct xfrm_trans_cb) > sizeof(skb->cb));
index 555ab35..9a5e79a 100644 (file)
@@ -534,7 +534,6 @@ static int xfrm_output_one(struct sk_buff *skb, int err)
 
                x->curlft.bytes += skb->len;
                x->curlft.packets++;
-               x->curlft.use_time = ktime_get_real_seconds();
 
                spin_unlock_bh(&x->lock);
 
index f1a0bab..cc6ab79 100644 (file)
@@ -3162,7 +3162,7 @@ ok:
        return dst;
 
 nopol:
-       if (!(dst_orig->dev->flags & IFF_LOOPBACK) &&
+       if ((!dst_orig->dev || !(dst_orig->dev->flags & IFF_LOOPBACK)) &&
            net->xfrm.policy_default[dir] == XFRM_USERPOLICY_BLOCK) {
                err = -EPERM;
                goto error;
@@ -3599,6 +3599,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
                if (pols[1]) {
                        if (IS_ERR(pols[1])) {
                                XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLERROR);
+                               xfrm_pol_put(pols[0]);
                                return 0;
                        }
                        pols[1]->curlft.use_time = ktime_get_real_seconds();
index 52e60e6..91c32a3 100644 (file)
@@ -1592,6 +1592,7 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig,
        x->replay = orig->replay;
        x->preplay = orig->preplay;
        x->mapping_maxage = orig->mapping_maxage;
+       x->lastused = orig->lastused;
        x->new_mapping = 0;
        x->new_mapping_sport = 0;
 
index f5f0d6f..6ae4821 100644 (file)
@@ -47,9 +47,20 @@ else
 
 ifdef CONFIG_CC_IS_CLANG
 KBUILD_CFLAGS += -Wno-initializer-overrides
+# Clang before clang-16 would warn on default argument promotions.
+ifeq ($(shell [ $(CONFIG_CLANG_VERSION) -lt 160000 ] && echo y),y)
+# Disable -Wformat
 KBUILD_CFLAGS += -Wno-format
+# Then re-enable flags that were part of the -Wformat group that aren't
+# problematic.
+KBUILD_CFLAGS += -Wformat-extra-args -Wformat-invalid-specifier
+KBUILD_CFLAGS += -Wformat-zero-length -Wnonnull
+# Requires clang-12+.
+ifeq ($(shell [ $(CONFIG_CLANG_VERSION) -ge 120000 ] && echo y),y)
+KBUILD_CFLAGS += -Wformat-insufficient-args
+endif
+endif
 KBUILD_CFLAGS += -Wno-sign-compare
-KBUILD_CFLAGS += -Wno-format-zero-length
 KBUILD_CFLAGS += $(call cc-disable-warning, pointer-to-enum-cast)
 KBUILD_CFLAGS += -Wno-tautological-constant-out-of-range-compare
 KBUILD_CFLAGS += $(call cc-disable-warning, unaligned-access)
index 692d64a..e4deaf5 100644 (file)
@@ -4,7 +4,7 @@ gcc-plugin-$(CONFIG_GCC_PLUGIN_LATENT_ENTROPY)  += latent_entropy_plugin.so
 gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_LATENT_ENTROPY)          \
                += -DLATENT_ENTROPY_PLUGIN
 ifdef CONFIG_GCC_PLUGIN_LATENT_ENTROPY
-    DISABLE_LATENT_ENTROPY_PLUGIN += -fplugin-arg-latent_entropy_plugin-disable
+    DISABLE_LATENT_ENTROPY_PLUGIN += -fplugin-arg-latent_entropy_plugin-disable -ULATENT_ENTROPY_PLUGIN
 endif
 export DISABLE_LATENT_ENTROPY_PLUGIN
 
index f754415..1337ced 100755 (executable)
@@ -51,6 +51,7 @@ def run_analysis(entry):
         checks += "linuxkernel-*"
     else:
         checks += "clang-analyzer-*"
+        checks += ",-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling"
     p = subprocess.run(["clang-tidy", "-p", args.path, checks, entry["file"]],
                        stdout=subprocess.PIPE,
                        stderr=subprocess.STDOUT,
index 7db8258..1db1889 100755 (executable)
@@ -59,7 +59,7 @@ fi
 if arg_contain -E "$@"; then
        # For scripts/cc-version.sh; This emulates GCC 20.0.0
        if arg_contain - "$@"; then
-               sed -n '/^GCC/{s/__GNUC__/20/; s/__GNUC_MINOR__/0/; s/__GNUC_PATCHLEVEL__/0/; p;}'
+               sed -n '/^GCC/{s/__GNUC__/20/; s/__GNUC_MINOR__/0/; s/__GNUC_PATCHLEVEL__/0/; p;}; s/__LONG_DOUBLE_128__/1/ p'
                exit 0
        else
                echo "no input files" >&2
index 3b42f25..8df33e7 100755 (executable)
@@ -62,6 +62,7 @@ try_decompress 'BZh'          xy    bunzip2
 try_decompress '\135\0\0\0'   xxx   unlzma
 try_decompress '\211\114\132' xy    'lzop -d'
 try_decompress '\002\041\114\030' xyy 'lz4 -d -l'
+try_decompress '\050\265\057\375' xxx unzstd
 
 # Bail out:
 echo "$me: Cannot find kernel config." >&2
diff --git a/scripts/gcc-goto.sh b/scripts/gcc-goto.sh
deleted file mode 100755 (executable)
index 8b980fb..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
-# Test for gcc 'asm goto' support
-# Copyright (C) 2010, Jason Baron <jbaron@redhat.com>
-
-cat << "END" | $@ -x c - -fno-PIE -c -o /dev/null
-int main(void)
-{
-#if defined(__arm__) || defined(__aarch64__)
-       /*
-        * Not related to asm goto, but used by jump label
-        * and broken on some ARM GCC versions (see GCC Bug 48637).
-        */
-       static struct { int dummy; int state; } tp;
-       asm (".long %c0" :: "i" (&tp.state));
-#endif
-
-entry:
-       asm goto ("" :::: entry);
-       return 0;
-}
-END
diff --git a/scripts/gcc-ld b/scripts/gcc-ld
deleted file mode 100755 (executable)
index 997b818..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
-# run gcc with ld options
-# used as a wrapper to execute link time optimizations
-# yes virginia, this is not pretty
-
-ARGS="-nostdlib"
-
-while [ "$1" != "" ] ; do
-       case "$1" in
-       -save-temps|-m32|-m64) N="$1" ;;
-       -r) N="$1" ;;
-       -[Wg]*) N="$1" ;;
-       -[olv]|-[Ofd]*|-nostdlib) N="$1" ;;
-       --end-group|--start-group)
-                N="-Wl,$1" ;;
-       -[RTFGhIezcbyYu]*|\
---script|--defsym|-init|-Map|--oformat|-rpath|\
--rpath-link|--sort-section|--section-start|-Tbss|-Tdata|-Ttext|\
---version-script|--dynamic-list|--version-exports-symbol|--wrap|-m)
-               A="$1" ; shift ; N="-Wl,$A,$1" ;;
-       -[m]*) N="$1" ;;
-       -*) N="-Wl,$1" ;;
-       *)  N="$1" ;;
-       esac
-       ARGS="$ARGS $N"
-       shift
-done
-
-exec $CC $ARGS
index 9aa23d1..ad8bbc5 100755 (executable)
@@ -41,4 +41,4 @@
 # so we just ignore them to let readprofile continue to work.
 # (At least sparc64 has __crc_ in the middle).
 
-$NM -n $1 | grep -v '\( [aNUw] \)\|\(__crc_\)\|\( \$[adt]\)\|\( \.L\)' > $2
+$NM -n $1 | grep -v '\( [aNUw] \)\|\(__crc_\)\|\( \$[adt]\)\|\( \.L\)\|\( L0\)' > $2
index 55e32af..2c80da0 100644 (file)
@@ -2021,13 +2021,11 @@ static void add_exported_symbols(struct buffer *buf, struct module *mod)
        /* record CRCs for exported symbols */
        buf_printf(buf, "\n");
        list_for_each_entry(sym, &mod->exported_symbols, list) {
-               if (!sym->crc_valid) {
+               if (!sym->crc_valid)
                        warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will not be versioned.\n"
                             "Is \"%s\" prototyped in <asm/asm-prototypes.h>?\n",
                             sym->name, mod->name, mod->is_vmlinux ? "" : ".ko",
                             sym->name);
-                       continue;
-               }
 
                buf_printf(buf, "SYMBOL_CRC(%s, 0x%08x, \"%s\");\n",
                           sym->name, sym->crc, sym->is_gpl_only ? "_gpl" : "");
index ec5a624..a9dbd99 100644 (file)
@@ -150,6 +150,16 @@ retry:
 /* clang-format on */
 
 /*
+ * All access rights that are denied by default whether they are handled or not
+ * by a ruleset/layer.  This must be ORed with all ruleset->fs_access_masks[]
+ * entries when we need to get the absolute handled access masks.
+ */
+/* clang-format off */
+#define ACCESS_INITIALLY_DENIED ( \
+       LANDLOCK_ACCESS_FS_REFER)
+/* clang-format on */
+
+/*
  * @path: Should have been checked by get_path_from_fd().
  */
 int landlock_append_fs_rule(struct landlock_ruleset *const ruleset,
@@ -167,7 +177,9 @@ int landlock_append_fs_rule(struct landlock_ruleset *const ruleset,
                return -EINVAL;
 
        /* Transforms relative access rights to absolute ones. */
-       access_rights |= LANDLOCK_MASK_ACCESS_FS & ~ruleset->fs_access_masks[0];
+       access_rights |=
+               LANDLOCK_MASK_ACCESS_FS &
+               ~(ruleset->fs_access_masks[0] | ACCESS_INITIALLY_DENIED);
        object = get_inode_object(d_backing_inode(path->dentry));
        if (IS_ERR(object))
                return PTR_ERR(object);
@@ -277,23 +289,12 @@ static inline bool is_nouser_or_private(const struct dentry *dentry)
 static inline access_mask_t
 get_handled_accesses(const struct landlock_ruleset *const domain)
 {
-       access_mask_t access_dom = 0;
-       unsigned long access_bit;
-
-       for (access_bit = 0; access_bit < LANDLOCK_NUM_ACCESS_FS;
-            access_bit++) {
-               size_t layer_level;
+       access_mask_t access_dom = ACCESS_INITIALLY_DENIED;
+       size_t layer_level;
 
-               for (layer_level = 0; layer_level < domain->num_layers;
-                    layer_level++) {
-                       if (domain->fs_access_masks[layer_level] &
-                           BIT_ULL(access_bit)) {
-                               access_dom |= BIT_ULL(access_bit);
-                               break;
-                       }
-               }
-       }
-       return access_dom;
+       for (layer_level = 0; layer_level < domain->num_layers; layer_level++)
+               access_dom |= domain->fs_access_masks[layer_level];
+       return access_dom & LANDLOCK_MASK_ACCESS_FS;
 }
 
 static inline access_mask_t
@@ -316,8 +317,13 @@ init_layer_masks(const struct landlock_ruleset *const domain,
 
                for_each_set_bit(access_bit, &access_req,
                                 ARRAY_SIZE(*layer_masks)) {
-                       if (domain->fs_access_masks[layer_level] &
-                           BIT_ULL(access_bit)) {
+                       /*
+                        * Artificially handles all initially denied by default
+                        * access rights.
+                        */
+                       if (BIT_ULL(access_bit) &
+                           (domain->fs_access_masks[layer_level] |
+                            ACCESS_INITIALLY_DENIED)) {
                                (*layer_masks)[access_bit] |=
                                        BIT_ULL(layer_level);
                                handled_accesses |= BIT_ULL(access_bit);
@@ -857,10 +863,6 @@ static int current_check_refer_path(struct dentry *const old_dentry,
                                              NULL, NULL);
        }
 
-       /* Backward compatibility: no reparenting support. */
-       if (!(get_handled_accesses(dom) & LANDLOCK_ACCESS_FS_REFER))
-               return -EXDEV;
-
        access_request_parent1 |= LANDLOCK_ACCESS_FS_REFER;
        access_request_parent2 |= LANDLOCK_ACCESS_FS_REFER;
 
index 6ab5f2b..4452158 100644 (file)
@@ -356,13 +356,11 @@ static long dm_verity_ioctl(struct file *filp, unsigned int cmd, unsigned long a
 {
        void __user *uarg = (void __user *)arg;
        unsigned int fd;
-       int rc;
 
        switch (cmd) {
        case LOADPIN_IOC_SET_TRUSTED_VERITY_DIGESTS:
-               rc = copy_from_user(&fd, uarg, sizeof(fd));
-               if (rc)
-                       return rc;
+               if (copy_from_user(&fd, uarg, sizeof(fd)))
+                       return -EFAULT;
 
                return read_trusted_verity_root_digests(fd);
 
index 14d30fe..4b95de2 100644 (file)
@@ -2660,4 +2660,8 @@ int security_uring_sqpoll(void)
 {
        return call_int_hook(uring_sqpoll, 0);
 }
+int security_uring_cmd(struct io_uring_cmd *ioucmd)
+{
+       return call_int_hook(uring_cmd, 0, ioucmd);
+}
 #endif /* CONFIG_IO_URING */
index 7957350..03bca97 100644 (file)
@@ -91,6 +91,7 @@
 #include <uapi/linux/mount.h>
 #include <linux/fsnotify.h>
 #include <linux/fanotify.h>
+#include <linux/io_uring.h>
 
 #include "avc.h"
 #include "objsec.h"
@@ -6987,6 +6988,28 @@ static int selinux_uring_sqpoll(void)
        return avc_has_perm(&selinux_state, sid, sid,
                            SECCLASS_IO_URING, IO_URING__SQPOLL, NULL);
 }
+
+/**
+ * selinux_uring_cmd - check if IORING_OP_URING_CMD is allowed
+ * @ioucmd: the io_uring command structure
+ *
+ * Check to see if the current domain is allowed to execute an
+ * IORING_OP_URING_CMD against the device/file specified in @ioucmd.
+ *
+ */
+static int selinux_uring_cmd(struct io_uring_cmd *ioucmd)
+{
+       struct file *file = ioucmd->file;
+       struct inode *inode = file_inode(file);
+       struct inode_security_struct *isec = selinux_inode(inode);
+       struct common_audit_data ad;
+
+       ad.type = LSM_AUDIT_DATA_FILE;
+       ad.u.file = file;
+
+       return avc_has_perm(&selinux_state, current_sid(), isec->sid,
+                           SECCLASS_IO_URING, IO_URING__CMD, &ad);
+}
 #endif /* CONFIG_IO_URING */
 
 /*
@@ -7231,6 +7254,7 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
 #ifdef CONFIG_IO_URING
        LSM_HOOK_INIT(uring_override_creds, selinux_uring_override_creds),
        LSM_HOOK_INIT(uring_sqpoll, selinux_uring_sqpoll),
+       LSM_HOOK_INIT(uring_cmd, selinux_uring_cmd),
 #endif
 
        /*
index ff757ae..1c2f41f 100644 (file)
@@ -253,7 +253,7 @@ const struct security_class_mapping secclass_map[] = {
        { "anon_inode",
          { COMMON_FILE_PERMS, NULL } },
        { "io_uring",
-         { "override_creds", "sqpoll", NULL } },
+         { "override_creds", "sqpoll", "cmd", NULL } },
        { NULL }
   };
 
index 0018314..bffccdc 100644 (file)
@@ -42,6 +42,7 @@
 #include <linux/fs_context.h>
 #include <linux/fs_parser.h>
 #include <linux/watch_queue.h>
+#include <linux/io_uring.h>
 #include "smack.h"
 
 #define TRANS_TRUE     "TRUE"
@@ -4732,6 +4733,36 @@ static int smack_uring_sqpoll(void)
        return -EPERM;
 }
 
+/**
+ * smack_uring_cmd - check on file operations for io_uring
+ * @ioucmd: the command in question
+ *
+ * Make a best guess about whether a io_uring "command" should
+ * be allowed. Use the same logic used for determining if the
+ * file could be opened for read in the absence of better criteria.
+ */
+static int smack_uring_cmd(struct io_uring_cmd *ioucmd)
+{
+       struct file *file = ioucmd->file;
+       struct smk_audit_info ad;
+       struct task_smack *tsp;
+       struct inode *inode;
+       int rc;
+
+       if (!file)
+               return -EINVAL;
+
+       tsp = smack_cred(file->f_cred);
+       inode = file_inode(file);
+
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
+       smk_ad_setfield_u_fs_path(&ad, file->f_path);
+       rc = smk_tskacc(tsp, smk_of_inode(inode), MAY_READ, &ad);
+       rc = smk_bu_credfile(file->f_cred, file, MAY_READ, rc);
+
+       return rc;
+}
+
 #endif /* CONFIG_IO_URING */
 
 struct lsm_blob_sizes smack_blob_sizes __lsm_ro_after_init = {
@@ -4889,6 +4920,7 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {
 #ifdef CONFIG_IO_URING
        LSM_HOOK_INIT(uring_override_creds, smack_uring_override_creds),
        LSM_HOOK_INIT(uring_sqpoll, smack_uring_sqpoll),
+       LSM_HOOK_INIT(uring_cmd, smack_uring_cmd),
 #endif
 };
 
index f3e8937..a727192 100644 (file)
@@ -385,14 +385,14 @@ static bool elem_id_matches(const struct snd_kcontrol *kctl,
 #define MULTIPLIER     37
 static unsigned long get_ctl_id_hash(const struct snd_ctl_elem_id *id)
 {
+       int i;
        unsigned long h;
-       const unsigned char *p;
 
        h = id->iface;
        h = MULTIPLIER * h + id->device;
        h = MULTIPLIER * h + id->subdevice;
-       for (p = id->name; *p; p++)
-               h = MULTIPLIER * h + *p;
+       for (i = 0; i < SNDRV_CTL_ELEM_ID_NAME_MAXLEN && id->name[i]; i++)
+               h = MULTIPLIER * h + id->name[i];
        h = MULTIPLIER * h + id->index;
        h &= LONG_MAX;
        return h;
index b8058b3..0b2f04d 100644 (file)
@@ -111,9 +111,9 @@ static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig)
        entry = data->entry;
        mutex_lock(&entry->access);
        if (entry->c.ops->llseek) {
-               offset = entry->c.ops->llseek(entry,
-                                             data->file_private_data,
-                                             file, offset, orig);
+               ret = entry->c.ops->llseek(entry,
+                                          data->file_private_data,
+                                          file, offset, orig);
                goto out;
        }
 
index 193dae3..5377f94 100644 (file)
@@ -178,10 +178,8 @@ int snd_card_new(struct device *parent, int idx, const char *xid,
                return -ENOMEM;
 
        err = snd_card_init(card, parent, idx, xid, module, extra_size);
-       if (err < 0) {
-               kfree(card);
-               return err;
-       }
+       if (err < 0)
+               return err; /* card is freed by error handler */
 
        *card_ret = card;
        return 0;
@@ -233,7 +231,7 @@ int snd_devm_card_new(struct device *parent, int idx, const char *xid,
        card->managed = true;
        err = snd_card_init(card, parent, idx, xid, module, extra_size);
        if (err < 0) {
-               devres_free(card);
+               devres_free(card); /* in managed mode, we need to free manually */
                return err;
        }
 
@@ -297,6 +295,8 @@ static int snd_card_init(struct snd_card *card, struct device *parent,
                mutex_unlock(&snd_card_mutex);
                dev_err(parent, "cannot find the slot for index %d (range 0-%i), error: %d\n",
                         idx, snd_ecards_limit - 1, err);
+               if (!card->managed)
+                       kfree(card); /* manually free here, as no destructor called */
                return err;
        }
        set_bit(idx, snd_cards_lock);           /* lock it */
index d3885cb..cfcd8ef 100644 (file)
 
 static const struct snd_malloc_ops *snd_dma_get_ops(struct snd_dma_buffer *dmab);
 
+#ifdef CONFIG_SND_DMA_SGBUF
+static void *do_alloc_fallback_pages(struct device *dev, size_t size,
+                                    dma_addr_t *addr, bool wc);
+static void do_free_fallback_pages(void *p, size_t size, bool wc);
+static void *snd_dma_sg_fallback_alloc(struct snd_dma_buffer *dmab, size_t size);
+#endif
+
 /* a cast to gfp flag from the dev pointer; for CONTINUOUS and VMALLOC types */
 static inline gfp_t snd_mem_get_gfp_flags(const struct snd_dma_buffer *dmab,
                                          gfp_t default_gfp)
@@ -277,16 +284,21 @@ EXPORT_SYMBOL(snd_sgbuf_get_chunk_size);
 /*
  * Continuous pages allocator
  */
-static void *snd_dma_continuous_alloc(struct snd_dma_buffer *dmab, size_t size)
+static void *do_alloc_pages(size_t size, dma_addr_t *addr, gfp_t gfp)
 {
-       gfp_t gfp = snd_mem_get_gfp_flags(dmab, GFP_KERNEL);
        void *p = alloc_pages_exact(size, gfp);
 
        if (p)
-               dmab->addr = page_to_phys(virt_to_page(p));
+               *addr = page_to_phys(virt_to_page(p));
        return p;
 }
 
+static void *snd_dma_continuous_alloc(struct snd_dma_buffer *dmab, size_t size)
+{
+       return do_alloc_pages(size, &dmab->addr,
+                             snd_mem_get_gfp_flags(dmab, GFP_KERNEL));
+}
+
 static void snd_dma_continuous_free(struct snd_dma_buffer *dmab)
 {
        free_pages_exact(dmab->area, dmab->bytes);
@@ -463,6 +475,25 @@ static const struct snd_malloc_ops snd_dma_dev_ops = {
 /*
  * Write-combined pages
  */
+/* x86-specific allocations */
+#ifdef CONFIG_SND_DMA_SGBUF
+static void *snd_dma_wc_alloc(struct snd_dma_buffer *dmab, size_t size)
+{
+       return do_alloc_fallback_pages(dmab->dev.dev, size, &dmab->addr, true);
+}
+
+static void snd_dma_wc_free(struct snd_dma_buffer *dmab)
+{
+       do_free_fallback_pages(dmab->area, dmab->bytes, true);
+}
+
+static int snd_dma_wc_mmap(struct snd_dma_buffer *dmab,
+                          struct vm_area_struct *area)
+{
+       area->vm_page_prot = pgprot_writecombine(area->vm_page_prot);
+       return snd_dma_continuous_mmap(dmab, area);
+}
+#else
 static void *snd_dma_wc_alloc(struct snd_dma_buffer *dmab, size_t size)
 {
        return dma_alloc_wc(dmab->dev.dev, size, &dmab->addr, DEFAULT_GFP);
@@ -479,6 +510,7 @@ static int snd_dma_wc_mmap(struct snd_dma_buffer *dmab,
        return dma_mmap_wc(dmab->dev.dev, area,
                           dmab->area, dmab->addr, dmab->bytes);
 }
+#endif /* CONFIG_SND_DMA_SGBUF */
 
 static const struct snd_malloc_ops snd_dma_wc_ops = {
        .alloc = snd_dma_wc_alloc,
@@ -486,10 +518,6 @@ static const struct snd_malloc_ops snd_dma_wc_ops = {
        .mmap = snd_dma_wc_mmap,
 };
 
-#ifdef CONFIG_SND_DMA_SGBUF
-static void *snd_dma_sg_fallback_alloc(struct snd_dma_buffer *dmab, size_t size);
-#endif
-
 /*
  * Non-contiguous pages allocator
  */
@@ -515,10 +543,13 @@ static void *snd_dma_noncontig_alloc(struct snd_dma_buffer *dmab, size_t size)
        dmab->dev.need_sync = dma_need_sync(dmab->dev.dev,
                                            sg_dma_address(sgt->sgl));
        p = dma_vmap_noncontiguous(dmab->dev.dev, size, sgt);
-       if (p)
+       if (p) {
                dmab->private_data = sgt;
-       else
+               /* store the first page address for convenience */
+               dmab->addr = snd_sgbuf_get_addr(dmab, 0);
+       } else {
                dma_free_noncontiguous(dmab->dev.dev, size, sgt, dmab->dev.dir);
+       }
        return p;
 }
 
@@ -669,6 +700,37 @@ static const struct snd_malloc_ops snd_dma_sg_wc_ops = {
        .get_chunk_size = snd_dma_noncontig_get_chunk_size,
 };
 
+/* manual page allocations with wc setup */
+static void *do_alloc_fallback_pages(struct device *dev, size_t size,
+                                    dma_addr_t *addr, bool wc)
+{
+       gfp_t gfp = GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN;
+       void *p;
+
+ again:
+       p = do_alloc_pages(size, addr, gfp);
+       if (!p || (*addr + size - 1) & ~dev->coherent_dma_mask) {
+               if (IS_ENABLED(CONFIG_ZONE_DMA32) && !(gfp & GFP_DMA32)) {
+                       gfp |= GFP_DMA32;
+                       goto again;
+               }
+               if (IS_ENABLED(CONFIG_ZONE_DMA) && !(gfp & GFP_DMA)) {
+                       gfp = (gfp & ~GFP_DMA32) | GFP_DMA;
+                       goto again;
+               }
+       }
+       if (p && wc)
+               set_memory_wc((unsigned long)(p), size >> PAGE_SHIFT);
+       return p;
+}
+
+static void do_free_fallback_pages(void *p, size_t size, bool wc)
+{
+       if (wc)
+               set_memory_wb((unsigned long)(p), size >> PAGE_SHIFT);
+       free_pages_exact(p, size);
+}
+
 /* Fallback SG-buffer allocations for x86 */
 struct snd_dma_sg_fallback {
        size_t count;
@@ -679,14 +741,11 @@ struct snd_dma_sg_fallback {
 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;
 
-       if (sgbuf->count && dmab->dev.type == SNDRV_DMA_TYPE_DEV_WC_SG_FALLBACK)
-               set_pages_array_wb(sgbuf->pages, sgbuf->count);
        for (i = 0; i < sgbuf->count && sgbuf->pages[i]; i++)
-               dma_free_coherent(dmab->dev.dev, PAGE_SIZE,
-                                 page_address(sgbuf->pages[i]),
-                                 sgbuf->addrs[i]);
+               do_free_fallback_pages(page_address(sgbuf->pages[i]), PAGE_SIZE, wc);
        kvfree(sgbuf->pages);
        kvfree(sgbuf->addrs);
        kfree(sgbuf);
@@ -698,6 +757,7 @@ static void *snd_dma_sg_fallback_alloc(struct snd_dma_buffer *dmab, size_t size)
        struct page **pages;
        size_t i, count;
        void *p;
+       bool wc = dmab->dev.type == SNDRV_DMA_TYPE_DEV_WC_SG_FALLBACK;
 
        sgbuf = kzalloc(sizeof(*sgbuf), GFP_KERNEL);
        if (!sgbuf)
@@ -712,19 +772,19 @@ static void *snd_dma_sg_fallback_alloc(struct snd_dma_buffer *dmab, size_t size)
                goto error;
 
        for (i = 0; i < count; sgbuf->count++, i++) {
-               p = dma_alloc_coherent(dmab->dev.dev, PAGE_SIZE,
-                                      &sgbuf->addrs[i], DEFAULT_GFP);
+               p = do_alloc_fallback_pages(dmab->dev.dev, PAGE_SIZE,
+                                           &sgbuf->addrs[i], wc);
                if (!p)
                        goto error;
                sgbuf->pages[i] = virt_to_page(p);
        }
 
-       if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_WC_SG_FALLBACK)
-               set_pages_array_wc(pages, count);
        p = vmap(pages, count, VM_MAP, PAGE_KERNEL);
        if (!p)
                goto error;
        dmab->private_data = sgbuf;
+       /* store the first page address for convenience */
+       dmab->addr = snd_sgbuf_get_addr(dmab, 0);
        return p;
 
  error:
index 90c3a36..02df915 100644 (file)
@@ -1672,14 +1672,14 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
                runtime = substream->runtime;
                if (atomic_read(&substream->mmap_count))
                        goto __direct;
-               err = snd_pcm_oss_make_ready(substream);
-               if (err < 0)
-                       return err;
                atomic_inc(&runtime->oss.rw_ref);
                if (mutex_lock_interruptible(&runtime->oss.params_lock)) {
                        atomic_dec(&runtime->oss.rw_ref);
                        return -ERESTARTSYS;
                }
+               err = snd_pcm_oss_make_ready_locked(substream);
+               if (err < 0)
+                       goto unlock;
                format = snd_pcm_oss_format_from(runtime->oss.format);
                width = snd_pcm_format_physical_width(format);
                if (runtime->oss.buffer_used > 0) {
index 1e3bf08..07efb38 100644 (file)
@@ -270,7 +270,9 @@ snd_seq_oss_midi_clear_all(void)
 void
 snd_seq_oss_midi_setup(struct seq_oss_devinfo *dp)
 {
+       spin_lock_irq(&register_lock);
        dp->max_mididev = max_midi_devs;
+       spin_unlock_irq(&register_lock);
 }
 
 /*
index 2e9d695..2d707af 100644 (file)
@@ -121,13 +121,13 @@ struct snd_seq_client *snd_seq_client_use_ptr(int clientid)
        spin_unlock_irqrestore(&clients_lock, flags);
 #ifdef CONFIG_MODULES
        if (!in_interrupt()) {
-               static char client_requested[SNDRV_SEQ_GLOBAL_CLIENTS];
-               static char card_requested[SNDRV_CARDS];
+               static DECLARE_BITMAP(client_requested, SNDRV_SEQ_GLOBAL_CLIENTS);
+               static DECLARE_BITMAP(card_requested, SNDRV_CARDS);
+
                if (clientid < SNDRV_SEQ_GLOBAL_CLIENTS) {
                        int idx;
                        
-                       if (!client_requested[clientid]) {
-                               client_requested[clientid] = 1;
+                       if (!test_and_set_bit(clientid, client_requested)) {
                                for (idx = 0; idx < 15; idx++) {
                                        if (seq_client_load[idx] < 0)
                                                break;
@@ -142,10 +142,8 @@ struct snd_seq_client *snd_seq_client_use_ptr(int clientid)
                        int card = (clientid - SNDRV_SEQ_GLOBAL_CLIENTS) /
                                SNDRV_SEQ_CLIENTS_PER_CARD;
                        if (card < snd_ecards_limit) {
-                               if (! card_requested[card]) {
-                                       card_requested[card] = 1;
+                               if (!test_and_set_bit(card, card_requested))
                                        snd_request_card(card);
-                               }
                                snd_seq_device_load_drivers();
                        }
                }
index 9b4a7cd..12f12a2 100644 (file)
@@ -605,17 +605,18 @@ static unsigned int loopback_jiffies_timer_pos_update
                        cable->streams[SNDRV_PCM_STREAM_PLAYBACK];
        struct loopback_pcm *dpcm_capt =
                        cable->streams[SNDRV_PCM_STREAM_CAPTURE];
-       unsigned long delta_play = 0, delta_capt = 0;
+       unsigned long delta_play = 0, delta_capt = 0, cur_jiffies;
        unsigned int running, count1, count2;
 
+       cur_jiffies = jiffies;
        running = cable->running ^ cable->pause;
        if (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) {
-               delta_play = jiffies - dpcm_play->last_jiffies;
+               delta_play = cur_jiffies - dpcm_play->last_jiffies;
                dpcm_play->last_jiffies += delta_play;
        }
 
        if (running & (1 << SNDRV_PCM_STREAM_CAPTURE)) {
-               delta_capt = jiffies - dpcm_capt->last_jiffies;
+               delta_capt = cur_jiffies - dpcm_capt->last_jiffies;
                dpcm_capt->last_jiffies += delta_capt;
        }
 
index 9db5ccd..13bb0cc 100644 (file)
@@ -55,16 +55,22 @@ int intel_nhlt_get_dmic_geo(struct device *dev, struct nhlt_acpi_table *nhlt)
 
                /* find max number of channels based on format_configuration */
                if (fmt_configs->fmt_count) {
+                       struct nhlt_fmt_cfg *fmt_cfg = fmt_configs->fmt_config;
+
                        dev_dbg(dev, "found %d format definitions\n",
                                fmt_configs->fmt_count);
 
                        for (i = 0; i < fmt_configs->fmt_count; i++) {
                                struct wav_fmt_ext *fmt_ext;
 
-                               fmt_ext = &fmt_configs->fmt_config[i].fmt_ext;
+                               fmt_ext = &fmt_cfg->fmt_ext;
 
                                if (fmt_ext->fmt.channels > max_ch)
                                        max_ch = fmt_ext->fmt.channels;
+
+                               /* Move to the next nhlt_fmt_cfg */
+                               fmt_cfg = (struct nhlt_fmt_cfg *)(fmt_cfg->config.caps +
+                                                                 fmt_cfg->config.size);
                        }
                        dev_dbg(dev, "max channels found %d\n", max_ch);
                } else {
index b2701a4..48af77a 100644 (file)
@@ -124,7 +124,7 @@ static int snd_emu10k1_pcm_channel_alloc(struct snd_emu10k1_pcm * epcm, int voic
        epcm->voices[0]->epcm = epcm;
        if (voices > 1) {
                for (i = 1; i < voices; i++) {
-                       epcm->voices[i] = &epcm->emu->voices[epcm->voices[0]->number + i];
+                       epcm->voices[i] = &epcm->emu->voices[(epcm->voices[0]->number + i) % NUM_G];
                        epcm->voices[i]->epcm = epcm;
                }
        }
index 129bffb..15e2a00 100644 (file)
@@ -1163,6 +1163,11 @@ static int cs35l41_no_acpi_dsd(struct cs35l41_hda *cs35l41, struct device *physd
                hw_cfg->gpio1.func = CS35l41_VSPK_SWITCH;
                hw_cfg->gpio1.valid = true;
        } else {
+               /*
+                * Note: CLSA010(0/1) are special cases which use a slightly different design.
+                * All other HIDs e.g. CSC3551 require valid ACPI _DSD properties to be supported.
+                */
+               dev_err(cs35l41->dev, "Error: ACPI _DSD Properties are missing for HID %s.\n", hid);
                hw_cfg->valid = false;
                hw_cfg->gpio1.valid = false;
                hw_cfg->gpio2.valid = false;
index cae9a97..1a868dd 100644 (file)
@@ -157,10 +157,10 @@ static int hda_codec_driver_remove(struct device *dev)
                return codec->bus->core.ext_ops->hdev_detach(&codec->core);
        }
 
-       refcount_dec(&codec->pcm_ref);
        snd_hda_codec_disconnect_pcms(codec);
        snd_hda_jack_tbl_disconnect(codec);
-       wait_event(codec->remove_sleep, !refcount_read(&codec->pcm_ref));
+       if (!refcount_dec_and_test(&codec->pcm_ref))
+               wait_event(codec->remove_sleep, !refcount_read(&codec->pcm_ref));
        snd_power_sync_ref(codec->bus->card);
 
        if (codec->patch_ops.free)
index a77165b..6f30c37 100644 (file)
@@ -1817,7 +1817,7 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci,
 
        /* use the non-cached pages in non-snoop mode */
        if (!azx_snoop(chip))
-               azx_bus(chip)->dma_type = SNDRV_DMA_TYPE_DEV_WC;
+               azx_bus(chip)->dma_type = SNDRV_DMA_TYPE_DEV_WC_SG;
 
        if (chip->driver_type == AZX_DRIVER_NVIDIA) {
                dev_dbg(chip->card->dev, "Enable delay in RIRB handling\n");
@@ -2550,6 +2550,8 @@ static const struct pci_device_id azx_ids[] = {
        /* 5 Series/3400 */
        { PCI_DEVICE(0x8086, 0x3b56),
          .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM },
+       { PCI_DEVICE(0x8086, 0x3b57),
+         .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM },
        /* Poulsbo */
        { PCI_DEVICE(0x8086, 0x811b),
          .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_BASE },
index 7debb2c..976a112 100644 (file)
@@ -474,7 +474,8 @@ MODULE_DEVICE_TABLE(of, hda_tegra_match);
 static int hda_tegra_probe(struct platform_device *pdev)
 {
        const unsigned int driver_flags = AZX_DCAPS_CORBRP_SELF_CLEAR |
-                                         AZX_DCAPS_PM_RUNTIME;
+                                         AZX_DCAPS_PM_RUNTIME |
+                                         AZX_DCAPS_4K_BDLE_BOUNDARY;
        struct snd_card *card;
        struct azx *chip;
        struct hda_tegra *hda;
index e0d3a8b..b288874 100644 (file)
@@ -546,6 +546,10 @@ const struct snd_pci_quirk cs8409_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1028, 0x0BD6, "Dolphin", CS8409_DOLPHIN),
        SND_PCI_QUIRK(0x1028, 0x0BD7, "Dolphin", CS8409_DOLPHIN),
        SND_PCI_QUIRK(0x1028, 0x0BD8, "Dolphin", CS8409_DOLPHIN),
+       SND_PCI_QUIRK(0x1028, 0x0C43, "Dolphin", CS8409_DOLPHIN),
+       SND_PCI_QUIRK(0x1028, 0x0C50, "Dolphin", CS8409_DOLPHIN),
+       SND_PCI_QUIRK(0x1028, 0x0C51, "Dolphin", CS8409_DOLPHIN),
+       SND_PCI_QUIRK(0x1028, 0x0C52, "Dolphin", CS8409_DOLPHIN),
        {} /* terminator */
 };
 
index 6c209cd..c239d9d 100644 (file)
@@ -170,6 +170,8 @@ struct hdmi_spec {
        bool dyn_pcm_no_legacy;
        /* hdmi interrupt trigger control flag for Nvidia codec */
        bool hdmi_intr_trig_ctrl;
+       bool nv_dp_workaround; /* workaround DP audio infoframe for Nvidia */
+
        bool intel_hsw_fixup;   /* apply Intel platform-specific fixups */
        /*
         * Non-generic VIA/NVIDIA specific
@@ -679,15 +681,24 @@ static void hdmi_pin_setup_infoframe(struct hda_codec *codec,
                                     int ca, int active_channels,
                                     int conn_type)
 {
+       struct hdmi_spec *spec = codec->spec;
        union audio_infoframe ai;
 
        memset(&ai, 0, sizeof(ai));
-       if (conn_type == 0) { /* HDMI */
+       if ((conn_type == 0) || /* HDMI */
+               /* Nvidia DisplayPort: Nvidia HW expects same layout as HDMI */
+               (conn_type == 1 && spec->nv_dp_workaround)) {
                struct hdmi_audio_infoframe *hdmi_ai = &ai.hdmi;
 
-               hdmi_ai->type           = 0x84;
-               hdmi_ai->ver            = 0x01;
-               hdmi_ai->len            = 0x0a;
+               if (conn_type == 0) { /* HDMI */
+                       hdmi_ai->type           = 0x84;
+                       hdmi_ai->ver            = 0x01;
+                       hdmi_ai->len            = 0x0a;
+               } else {/* Nvidia DP */
+                       hdmi_ai->type           = 0x84;
+                       hdmi_ai->ver            = 0x1b;
+                       hdmi_ai->len            = 0x11 << 2;
+               }
                hdmi_ai->CC02_CT47      = active_channels - 1;
                hdmi_ai->CA             = ca;
                hdmi_checksum_audio_infoframe(hdmi_ai);
@@ -1267,6 +1278,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
        set_bit(pcm_idx, &spec->pcm_in_use);
        per_pin = get_pin(spec, pin_idx);
        per_pin->cvt_nid = per_cvt->cvt_nid;
+       per_pin->silent_stream = false;
        hinfo->nid = per_cvt->cvt_nid;
 
        /* flip stripe flag for the assigned stream if supported */
@@ -3617,6 +3629,7 @@ static int patch_nvhdmi_2ch(struct hda_codec *codec)
        spec->pcm_playback.rates = SUPPORTED_RATES;
        spec->pcm_playback.maxbps = SUPPORTED_MAXBPS;
        spec->pcm_playback.formats = SUPPORTED_FORMATS;
+       spec->nv_dp_workaround = true;
        return 0;
 }
 
@@ -3756,6 +3769,7 @@ static int patch_nvhdmi(struct hda_codec *codec)
        spec->chmap.ops.chmap_cea_alloc_validate_get_type =
                nvhdmi_chmap_cea_alloc_validate_get_type;
        spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate;
+       spec->nv_dp_workaround = true;
 
        codec->link_down_at_suspend = 1;
 
@@ -3779,6 +3793,7 @@ static int patch_nvhdmi_legacy(struct hda_codec *codec)
        spec->chmap.ops.chmap_cea_alloc_validate_get_type =
                nvhdmi_chmap_cea_alloc_validate_get_type;
        spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate;
+       spec->nv_dp_workaround = true;
 
        codec->link_down_at_suspend = 1;
 
@@ -3984,6 +3999,7 @@ static int tegra_hdmi_init(struct hda_codec *codec)
 
        generic_hdmi_init_per_pins(codec);
 
+       codec->depop_delay = 10;
        codec->patch_ops.build_pcms = tegra_hdmi_build_pcms;
        spec->chmap.ops.chmap_cea_alloc_validate_get_type =
                nvhdmi_chmap_cea_alloc_validate_get_type;
@@ -3992,6 +4008,7 @@ static int tegra_hdmi_init(struct hda_codec *codec)
        spec->chmap.ops.chmap_cea_alloc_validate_get_type =
                nvhdmi_chmap_cea_alloc_validate_get_type;
        spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate;
+       spec->nv_dp_workaround = true;
 
        return 0;
 }
index fd630d6..f9d46ae 100644 (file)
@@ -4700,6 +4700,48 @@ static void alc236_fixup_hp_mute_led_micmute_vref(struct hda_codec *codec,
        alc236_fixup_hp_micmute_led_vref(codec, fix, action);
 }
 
+static inline void alc298_samsung_write_coef_pack(struct hda_codec *codec,
+                                                 const unsigned short coefs[2])
+{
+       alc_write_coef_idx(codec, 0x23, coefs[0]);
+       alc_write_coef_idx(codec, 0x25, coefs[1]);
+       alc_write_coef_idx(codec, 0x26, 0xb011);
+}
+
+struct alc298_samsung_amp_desc {
+       unsigned char nid;
+       unsigned short init_seq[2][2];
+};
+
+static void alc298_fixup_samsung_amp(struct hda_codec *codec,
+                                    const struct hda_fixup *fix, int action)
+{
+       int i, j;
+       static const unsigned short init_seq[][2] = {
+               { 0x19, 0x00 }, { 0x20, 0xc0 }, { 0x22, 0x44 }, { 0x23, 0x08 },
+               { 0x24, 0x85 }, { 0x25, 0x41 }, { 0x35, 0x40 }, { 0x36, 0x01 },
+               { 0x38, 0x81 }, { 0x3a, 0x03 }, { 0x3b, 0x81 }, { 0x40, 0x3e },
+               { 0x41, 0x07 }, { 0x400, 0x1 }
+       };
+       static const struct alc298_samsung_amp_desc amps[] = {
+               { 0x3a, { { 0x18, 0x1 }, { 0x26, 0x0 } } },
+               { 0x39, { { 0x18, 0x2 }, { 0x26, 0x1 } } }
+       };
+
+       if (action != HDA_FIXUP_ACT_INIT)
+               return;
+
+       for (i = 0; i < ARRAY_SIZE(amps); i++) {
+               alc_write_coef_idx(codec, 0x22, amps[i].nid);
+
+               for (j = 0; j < ARRAY_SIZE(amps[i].init_seq); j++)
+                       alc298_samsung_write_coef_pack(codec, amps[i].init_seq[j]);
+
+               for (j = 0; j < ARRAY_SIZE(init_seq); j++)
+                       alc298_samsung_write_coef_pack(codec, init_seq[j]);
+       }
+}
+
 #if IS_REACHABLE(CONFIG_INPUT)
 static void gpio2_mic_hotkey_event(struct hda_codec *codec,
                                   struct hda_jack_callback *event)
@@ -7025,11 +7067,14 @@ enum {
        ALC294_FIXUP_ASUS_GU502_HP,
        ALC294_FIXUP_ASUS_GU502_PINS,
        ALC294_FIXUP_ASUS_GU502_VERBS,
+       ALC294_FIXUP_ASUS_G513_PINS,
+       ALC285_FIXUP_ASUS_G533Z_PINS,
        ALC285_FIXUP_HP_GPIO_LED,
        ALC285_FIXUP_HP_MUTE_LED,
        ALC236_FIXUP_HP_GPIO_LED,
        ALC236_FIXUP_HP_MUTE_LED,
        ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF,
+       ALC298_FIXUP_SAMSUNG_AMP,
        ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET,
        ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET,
        ALC295_FIXUP_ASUS_MIC_NO_PRESENCE,
@@ -8363,6 +8408,24 @@ static const struct hda_fixup alc269_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc294_fixup_gu502_hp,
        },
+        [ALC294_FIXUP_ASUS_G513_PINS] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                               { 0x19, 0x03a11050 }, /* front HP mic */
+                               { 0x1a, 0x03a11c30 }, /* rear external mic */
+                               { 0x21, 0x03211420 }, /* front HP out */
+                               { }
+               },
+       },
+       [ALC285_FIXUP_ASUS_G533Z_PINS] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x14, 0x90170120 },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC294_FIXUP_ASUS_G513_PINS,
+       },
        [ALC294_FIXUP_ASUS_COEF_1B] = {
                .type = HDA_FIXUP_VERBS,
                .v.verbs = (const struct hda_verb[]) {
@@ -8396,6 +8459,12 @@ static const struct hda_fixup alc269_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc236_fixup_hp_mute_led_micmute_vref,
        },
+       [ALC298_FIXUP_SAMSUNG_AMP] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc298_fixup_samsung_amp,
+               .chained = true,
+               .chain_id = ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET
+       },
        [ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET] = {
                .type = HDA_FIXUP_VERBS,
                .v.verbs = (const struct hda_verb[]) {
@@ -9100,6 +9169,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1028, 0x0871, "Dell Precision 3630", ALC255_FIXUP_DELL_HEADSET_MIC),
        SND_PCI_QUIRK(0x1028, 0x0872, "Dell Precision 3630", ALC255_FIXUP_DELL_HEADSET_MIC),
        SND_PCI_QUIRK(0x1028, 0x0873, "Dell Precision 3930", ALC255_FIXUP_DUMMY_LINEOUT_VERB),
+       SND_PCI_QUIRK(0x1028, 0x087d, "Dell Precision 5530", ALC289_FIXUP_DUAL_SPK),
        SND_PCI_QUIRK(0x1028, 0x08ad, "Dell WYSE AIO", ALC225_FIXUP_DELL_WYSE_AIO_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x08ae, "Dell WYSE NB", ALC225_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0935, "Dell", ALC274_FIXUP_DELL_AIO_LINEOUT_VERB),
@@ -9116,6 +9186,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1028, 0x0a9d, "Dell Latitude 5430", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0a9e, "Dell Latitude 5430", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0b19, "Dell XPS 15 9520", ALC289_FIXUP_DUAL_SPK),
+       SND_PCI_QUIRK(0x1028, 0x0b1a, "Dell Precision 5570", ALC289_FIXUP_DUAL_SPK),
        SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
@@ -9243,6 +9314,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x8896, "HP EliteBook 855 G8 Notebook PC", ALC285_FIXUP_HP_MUTE_LED),
        SND_PCI_QUIRK(0x103c, 0x8898, "HP EliteBook 845 G8 Notebook PC", ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x103c, 0x88d0, "HP Pavilion 15-eh1xxx (mainboard 88D0)", ALC287_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8902, "HP OMEN 16", ALC285_FIXUP_HP_MUTE_LED),
        SND_PCI_QUIRK(0x103c, 0x896e, "HP EliteBook x360 830 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8971, "HP EliteBook 830 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8972, "HP EliteBook 840 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
@@ -9283,16 +9355,18 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x1271, "ASUS X430UN", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1043, 0x1290, "ASUS X441SA", ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1043, 0x12a0, "ASUS X441UV", ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1043, 0x12af, "ASUS UX582ZS", ALC245_FIXUP_CS35L41_SPI_2),
        SND_PCI_QUIRK(0x1043, 0x12e0, "ASUS X541SA", ALC256_FIXUP_ASUS_MIC),
        SND_PCI_QUIRK(0x1043, 0x12f0, "ASUS X541UV", ALC256_FIXUP_ASUS_MIC),
        SND_PCI_QUIRK(0x1043, 0x1313, "Asus K42JZ", ALC269VB_FIXUP_ASUS_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1043, 0x13b0, "ASUS Z550SA", ALC256_FIXUP_ASUS_MIC),
        SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_ASUS_ZENBOOK),
        SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A),
+       SND_PCI_QUIRK(0x1043, 0x1662, "ASUS GV301QH", ALC294_FIXUP_ASUS_DUAL_SPK),
+       SND_PCI_QUIRK(0x1043, 0x16b2, "ASUS GU603", ALC289_FIXUP_ASUS_GA401),
        SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC),
        SND_PCI_QUIRK(0x1043, 0x1740, "ASUS UX430UA", ALC295_FIXUP_ASUS_DACS),
        SND_PCI_QUIRK(0x1043, 0x17d1, "ASUS UX431FL", ALC294_FIXUP_ASUS_DUAL_SPK),
-       SND_PCI_QUIRK(0x1043, 0x1662, "ASUS GV301QH", ALC294_FIXUP_ASUS_DUAL_SPK),
        SND_PCI_QUIRK(0x1043, 0x1881, "ASUS Zephyrus S/M", ALC294_FIXUP_ASUS_GX502_PINS),
        SND_PCI_QUIRK(0x1043, 0x18b1, "Asus MJ401TA", ALC256_FIXUP_ASUS_HEADSET_MIC),
        SND_PCI_QUIRK(0x1043, 0x18f1, "Asus FX505DT", ALC256_FIXUP_ASUS_HEADSET_MIC),
@@ -9303,18 +9377,21 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x19e1, "ASUS UX581LV", ALC295_FIXUP_ASUS_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
        SND_PCI_QUIRK(0x1043, 0x1a30, "ASUS X705UD", ALC256_FIXUP_ASUS_MIC),
+       SND_PCI_QUIRK(0x1043, 0x1a8f, "ASUS UX582ZS", ALC245_FIXUP_CS35L41_SPI_2),
        SND_PCI_QUIRK(0x1043, 0x1b11, "ASUS UX431DA", ALC294_FIXUP_ASUS_COEF_1B),
        SND_PCI_QUIRK(0x1043, 0x1b13, "Asus U41SV", ALC269_FIXUP_INV_DMIC),
        SND_PCI_QUIRK(0x1043, 0x1bbd, "ASUS Z550MA", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1043, 0x1c23, "Asus X55U", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+       SND_PCI_QUIRK(0x1043, 0x1c92, "ASUS ROG Strix G15", ALC285_FIXUP_ASUS_G533Z_PINS),
        SND_PCI_QUIRK(0x1043, 0x1ccd, "ASUS X555UB", ALC256_FIXUP_ASUS_MIC),
+       SND_PCI_QUIRK(0x1043, 0x1d42, "ASUS Zephyrus G14 2022", ALC289_FIXUP_ASUS_GA401),
        SND_PCI_QUIRK(0x1043, 0x1d4e, "ASUS TM420", ALC256_FIXUP_ASUS_HPE),
        SND_PCI_QUIRK(0x1043, 0x1e11, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA502),
        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),
+       SND_PCI_QUIRK(0x1043, 0x1c52, "ASUS Zephyrus G15 2022", ALC289_FIXUP_ASUS_GA401),
        SND_PCI_QUIRK(0x1043, 0x1f11, "ASUS Zephyrus G14", ALC289_FIXUP_ASUS_GA401),
-       SND_PCI_QUIRK(0x1043, 0x1d42, "ASUS Zephyrus G14 2022", ALC289_FIXUP_ASUS_GA401),
-       SND_PCI_QUIRK(0x1043, 0x16b2, "ASUS GU603", ALC289_FIXUP_ASUS_GA401),
        SND_PCI_QUIRK(0x1043, 0x3030, "ASUS ZN270IE", ALC256_FIXUP_ASUS_AIO_GPIO2),
        SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC),
        SND_PCI_QUIRK(0x1043, 0x834a, "ASUS S101", ALC269_FIXUP_STEREO_DMIC),
@@ -9340,13 +9417,13 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x10ec, 0x1254, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
        SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-SZ6", ALC269_FIXUP_HEADSET_MODE),
        SND_PCI_QUIRK(0x144d, 0xc109, "Samsung Ativ book 9 (NP900X3G)", ALC269_FIXUP_INV_DMIC),
-       SND_PCI_QUIRK(0x144d, 0xc169, "Samsung Notebook 9 Pen (NP930SBE-K01US)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET),
-       SND_PCI_QUIRK(0x144d, 0xc176, "Samsung Notebook 9 Pro (NP930MBE-K04US)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET),
-       SND_PCI_QUIRK(0x144d, 0xc189, "Samsung Galaxy Flex Book (NT950QCG-X716)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET),
-       SND_PCI_QUIRK(0x144d, 0xc18a, "Samsung Galaxy Book Ion (NP930XCJ-K01US)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET),
+       SND_PCI_QUIRK(0x144d, 0xc169, "Samsung Notebook 9 Pen (NP930SBE-K01US)", ALC298_FIXUP_SAMSUNG_AMP),
+       SND_PCI_QUIRK(0x144d, 0xc176, "Samsung Notebook 9 Pro (NP930MBE-K04US)", ALC298_FIXUP_SAMSUNG_AMP),
+       SND_PCI_QUIRK(0x144d, 0xc189, "Samsung Galaxy Flex Book (NT950QCG-X716)", ALC298_FIXUP_SAMSUNG_AMP),
+       SND_PCI_QUIRK(0x144d, 0xc18a, "Samsung Galaxy Book Ion (NP930XCJ-K01US)", ALC298_FIXUP_SAMSUNG_AMP),
        SND_PCI_QUIRK(0x144d, 0xc740, "Samsung Ativ book 8 (NP870Z5G)", ALC269_FIXUP_ATIV_BOOK_8),
-       SND_PCI_QUIRK(0x144d, 0xc812, "Samsung Notebook Pen S (NT950SBE-X58)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET),
-       SND_PCI_QUIRK(0x144d, 0xc830, "Samsung Galaxy Book Ion (NT950XCJ-X716A)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET),
+       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(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_HEADSET_MIC),
        SND_PCI_QUIRK(0x1462, 0xb120, "MSI Cubi MS-B120", ALC283_FIXUP_HEADSET_MIC),
@@ -9389,6 +9466,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1558, 0x70f4, "Clevo NH77EPY", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x70f6, "Clevo NH77DPQ-Y", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x7716, "Clevo NS50PU", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x7717, "Clevo NS70PU", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x7718, "Clevo L140PU", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x8228, "Clevo NR40BU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x8520, "Clevo NH50D[CD]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
@@ -9490,6 +9568,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x3852, "Lenovo Yoga 7 14ITL5", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS),
        SND_PCI_QUIRK(0x17aa, 0x3853, "Lenovo Yoga 7 15ITL5", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS),
        SND_PCI_QUIRK(0x17aa, 0x3855, "Legion 7 16ITHG6", ALC287_FIXUP_LEGION_16ITHG6),
+       SND_PCI_QUIRK(0x17aa, 0x3869, "Lenovo Yoga7 14IAL7", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
        SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
        SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC),
        SND_PCI_QUIRK(0x17aa, 0x3978, "Lenovo B50-70", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
@@ -9516,6 +9595,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
        SND_PCI_QUIRK(0x1849, 0x1233, "ASRock NUC Box 1100", ALC233_FIXUP_NO_AUDIO_JACK),
        SND_PCI_QUIRK(0x19e5, 0x3204, "Huawei MACH-WX9", ALC256_FIXUP_HUAWEI_MACH_WX9_PINS),
+       SND_PCI_QUIRK(0x19e5, 0x320f, "Huawei WRT-WX9 ", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1b35, 0x1235, "CZC B20", ALC269_FIXUP_CZC_B20),
        SND_PCI_QUIRK(0x1b35, 0x1236, "CZC TMI", ALC269_FIXUP_CZC_TMI),
        SND_PCI_QUIRK(0x1b35, 0x1237, "CZC L101", ALC269_FIXUP_CZC_L101),
@@ -9712,7 +9792,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
        {.id = ALC299_FIXUP_PREDATOR_SPK, .name = "predator-spk"},
        {.id = ALC298_FIXUP_HUAWEI_MBX_STEREO, .name = "huawei-mbx-stereo"},
        {.id = ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE, .name = "alc256-medion-headset"},
-       {.id = ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET, .name = "alc298-samsung-headphone"},
+       {.id = ALC298_FIXUP_SAMSUNG_AMP, .name = "alc298-samsung-amp"},
        {.id = ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET, .name = "alc256-samsung-headphone"},
        {.id = ALC255_FIXUP_XIAOMI_HEADSET_MIC, .name = "alc255-xiaomi-headset"},
        {.id = ALC274_FIXUP_HP_MIC, .name = "alc274-hp-mic-detect"},
index 61df4d3..7f340f1 100644 (file)
@@ -209,6 +209,7 @@ struct sigmatel_spec {
 
        /* beep widgets */
        hda_nid_t anabeep_nid;
+       bool beep_power_on;
 
        /* SPDIF-out mux */
        const char * const *spdif_labels;
@@ -4443,6 +4444,28 @@ static int stac_suspend(struct hda_codec *codec)
 
        return 0;
 }
+
+static int stac_check_power_status(struct hda_codec *codec, hda_nid_t nid)
+{
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+       struct sigmatel_spec *spec = codec->spec;
+#endif
+       int ret = snd_hda_gen_check_power_status(codec, nid);
+
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+       if (nid == spec->gen.beep_nid && codec->beep) {
+               if (codec->beep->enabled != spec->beep_power_on) {
+                       spec->beep_power_on = codec->beep->enabled;
+                       if (spec->beep_power_on)
+                               snd_hda_power_up_pm(codec);
+                       else
+                               snd_hda_power_down_pm(codec);
+               }
+               ret |= spec->beep_power_on;
+       }
+#endif
+       return ret;
+}
 #else
 #define stac_suspend           NULL
 #endif /* CONFIG_PM */
@@ -4455,6 +4478,7 @@ static const struct hda_codec_ops stac_patch_ops = {
        .unsol_event = snd_hda_jack_unsol_event,
 #ifdef CONFIG_PM
        .suspend = stac_suspend,
+       .check_power_status = stac_check_power_status,
 #endif
 };
 
index ecfe7a7..e0b24e1 100644 (file)
@@ -143,6 +143,34 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "21CL"),
                }
        },
+       {
+               .driver_data = &acp6x_card,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "21EM"),
+               }
+       },
+       {
+               .driver_data = &acp6x_card,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "21EN"),
+               }
+       },
+       {
+               .driver_data = &acp6x_card,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "21J5"),
+               }
+       },
+       {
+               .driver_data = &acp6x_card,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "21J6"),
+               }
+       },
        {}
 };
 
index 4850a17..ab2d7a7 100644 (file)
@@ -196,7 +196,7 @@ struct mchp_spdiftx_dev {
        struct clk                              *pclk;
        struct clk                              *gclk;
        unsigned int                            fmt;
-       int                                     gclk_enabled:1;
+       unsigned int                            gclk_enabled:1;
 };
 
 static inline int mchp_spdiftx_is_running(struct mchp_spdiftx_dev *dev)
index d545a59..daafd42 100644 (file)
@@ -1617,7 +1617,6 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *data)
        unsigned int current_plug_status;
        unsigned int current_button_status;
        unsigned int i;
-       int report = 0;
 
        mutex_lock(&cs42l42->irq_lock);
        if (cs42l42->suspended) {
@@ -1711,13 +1710,15 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *data)
 
                        if (current_button_status & CS42L42_M_DETECT_TF_MASK) {
                                dev_dbg(cs42l42->dev, "Button released\n");
-                               report = 0;
+                               snd_soc_jack_report(cs42l42->jack, 0,
+                                                   SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                                                   SND_JACK_BTN_2 | SND_JACK_BTN_3);
                        } else if (current_button_status & CS42L42_M_DETECT_FT_MASK) {
-                               report = cs42l42_handle_button_press(cs42l42);
-
+                               snd_soc_jack_report(cs42l42->jack,
+                                                   cs42l42_handle_button_press(cs42l42),
+                                                   SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                                                   SND_JACK_BTN_2 | SND_JACK_BTN_3);
                        }
-                       snd_soc_jack_report(cs42l42->jack, report, SND_JACK_BTN_0 | SND_JACK_BTN_1 |
-                                                                  SND_JACK_BTN_2 | SND_JACK_BTN_3);
                }
        }
 
index 58f70a0..0626d56 100644 (file)
@@ -357,17 +357,32 @@ static const struct snd_soc_dapm_route nau8540_dapm_routes[] = {
        {"AIFTX", NULL, "Digital CH4 Mux"},
 };
 
-static int nau8540_clock_check(struct nau8540 *nau8540, int rate, int osr)
+static const struct nau8540_osr_attr *
+nau8540_get_osr(struct nau8540 *nau8540)
 {
+       unsigned int osr;
+
+       regmap_read(nau8540->regmap, NAU8540_REG_ADC_SAMPLE_RATE, &osr);
+       osr &= NAU8540_ADC_OSR_MASK;
        if (osr >= ARRAY_SIZE(osr_adc_sel))
-               return -EINVAL;
+               return NULL;
+       return &osr_adc_sel[osr];
+}
+
+static int nau8540_dai_startup(struct snd_pcm_substream *substream,
+                              struct snd_soc_dai *dai)
+{
+       struct snd_soc_component *component = dai->component;
+       struct nau8540 *nau8540 = snd_soc_component_get_drvdata(component);
+       const struct nau8540_osr_attr *osr;
 
-       if (rate * osr > CLK_ADC_MAX) {
-               dev_err(nau8540->dev, "exceed the maximum frequency of CLK_ADC\n");
+       osr = nau8540_get_osr(nau8540);
+       if (!osr || !osr->osr)
                return -EINVAL;
-       }
 
-       return 0;
+       return snd_pcm_hw_constraint_minmax(substream->runtime,
+                                           SNDRV_PCM_HW_PARAM_RATE,
+                                           0, CLK_ADC_MAX / osr->osr);
 }
 
 static int nau8540_hw_params(struct snd_pcm_substream *substream,
@@ -375,7 +390,8 @@ static int nau8540_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_soc_component *component = dai->component;
        struct nau8540 *nau8540 = snd_soc_component_get_drvdata(component);
-       unsigned int val_len = 0, osr;
+       unsigned int val_len = 0;
+       const struct nau8540_osr_attr *osr;
 
        /* CLK_ADC = OSR * FS
         * ADC clock frequency is defined as Over Sampling Rate (OSR)
@@ -383,13 +399,14 @@ static int nau8540_hw_params(struct snd_pcm_substream *substream,
         * values must be selected such that the maximum frequency is less
         * than 6.144 MHz.
         */
-       regmap_read(nau8540->regmap, NAU8540_REG_ADC_SAMPLE_RATE, &osr);
-       osr &= NAU8540_ADC_OSR_MASK;
-       if (nau8540_clock_check(nau8540, params_rate(params), osr))
+       osr = nau8540_get_osr(nau8540);
+       if (!osr || !osr->osr)
+               return -EINVAL;
+       if (params_rate(params) * osr->osr > CLK_ADC_MAX)
                return -EINVAL;
        regmap_update_bits(nau8540->regmap, NAU8540_REG_CLOCK_SRC,
                NAU8540_CLK_ADC_SRC_MASK,
-               osr_adc_sel[osr].clk_src << NAU8540_CLK_ADC_SRC_SFT);
+               osr->clk_src << NAU8540_CLK_ADC_SRC_SFT);
 
        switch (params_width(params)) {
        case 16:
@@ -515,6 +532,7 @@ static int nau8540_set_tdm_slot(struct snd_soc_dai *dai,
 
 
 static const struct snd_soc_dai_ops nau8540_dai_ops = {
+       .startup = nau8540_dai_startup,
        .hw_params = nau8540_hw_params,
        .set_fmt = nau8540_set_fmt,
        .set_tdm_slot = nau8540_set_tdm_slot,
index 2d21339..4a72b94 100644 (file)
@@ -670,28 +670,40 @@ static const struct snd_soc_dapm_route nau8821_dapm_routes[] = {
        {"HPOR", NULL, "Class G"},
 };
 
-static int nau8821_clock_check(struct nau8821 *nau8821,
-       int stream, int rate, int osr)
+static const struct nau8821_osr_attr *
+nau8821_get_osr(struct nau8821 *nau8821, int stream)
 {
-       int osrate = 0;
+       unsigned int osr;
 
        if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               regmap_read(nau8821->regmap, NAU8821_R2C_DAC_CTRL1, &osr);
+               osr &= NAU8821_DAC_OVERSAMPLE_MASK;
                if (osr >= ARRAY_SIZE(osr_dac_sel))
-                       return -EINVAL;
-               osrate = osr_dac_sel[osr].osr;
+                       return NULL;
+               return &osr_dac_sel[osr];
        } else {
+               regmap_read(nau8821->regmap, NAU8821_R2B_ADC_RATE, &osr);
+               osr &= NAU8821_ADC_SYNC_DOWN_MASK;
                if (osr >= ARRAY_SIZE(osr_adc_sel))
-                       return -EINVAL;
-               osrate = osr_adc_sel[osr].osr;
+                       return NULL;
+               return &osr_adc_sel[osr];
        }
+}
 
-       if (!osrate || rate * osrate > CLK_DA_AD_MAX) {
-               dev_err(nau8821->dev,
-                       "exceed the maximum frequency of CLK_ADC or CLK_DAC");
+static int nau8821_dai_startup(struct snd_pcm_substream *substream,
+                              struct snd_soc_dai *dai)
+{
+       struct snd_soc_component *component = dai->component;
+       struct nau8821 *nau8821 = snd_soc_component_get_drvdata(component);
+       const struct nau8821_osr_attr *osr;
+
+       osr = nau8821_get_osr(nau8821, substream->stream);
+       if (!osr || !osr->osr)
                return -EINVAL;
-       }
 
-       return 0;
+       return snd_pcm_hw_constraint_minmax(substream->runtime,
+                                           SNDRV_PCM_HW_PARAM_RATE,
+                                           0, CLK_DA_AD_MAX / osr->osr);
 }
 
 static int nau8821_hw_params(struct snd_pcm_substream *substream,
@@ -699,7 +711,8 @@ static int nau8821_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_soc_component *component = dai->component;
        struct nau8821 *nau8821 = snd_soc_component_get_drvdata(component);
-       unsigned int val_len = 0, osr, ctrl_val, bclk_fs, clk_div;
+       unsigned int val_len = 0, ctrl_val, bclk_fs, clk_div;
+       const struct nau8821_osr_attr *osr;
 
        nau8821->fs = params_rate(params);
        /* CLK_DAC or CLK_ADC = OSR * FS
@@ -708,27 +721,19 @@ static int nau8821_hw_params(struct snd_pcm_substream *substream,
         * values must be selected such that the maximum frequency is less
         * than 6.144 MHz.
         */
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               regmap_read(nau8821->regmap, NAU8821_R2C_DAC_CTRL1, &osr);
-               osr &= NAU8821_DAC_OVERSAMPLE_MASK;
-               if (nau8821_clock_check(nau8821, substream->stream,
-                       nau8821->fs, osr)) {
-                       return -EINVAL;
-               }
+       osr = nau8821_get_osr(nau8821, substream->stream);
+       if (!osr || !osr->osr)
+               return -EINVAL;
+       if (nau8821->fs * osr->osr > CLK_DA_AD_MAX)
+               return -EINVAL;
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                regmap_update_bits(nau8821->regmap, NAU8821_R03_CLK_DIVIDER,
                        NAU8821_CLK_DAC_SRC_MASK,
-                       osr_dac_sel[osr].clk_src << NAU8821_CLK_DAC_SRC_SFT);
-       } else {
-               regmap_read(nau8821->regmap, NAU8821_R2B_ADC_RATE, &osr);
-               osr &= NAU8821_ADC_SYNC_DOWN_MASK;
-               if (nau8821_clock_check(nau8821, substream->stream,
-                       nau8821->fs, osr)) {
-                       return -EINVAL;
-               }
+                       osr->clk_src << NAU8821_CLK_DAC_SRC_SFT);
+       else
                regmap_update_bits(nau8821->regmap, NAU8821_R03_CLK_DIVIDER,
                        NAU8821_CLK_ADC_SRC_MASK,
-                       osr_adc_sel[osr].clk_src << NAU8821_CLK_ADC_SRC_SFT);
-       }
+                       osr->clk_src << NAU8821_CLK_ADC_SRC_SFT);
 
        /* make BCLK and LRC divde configuration if the codec as master. */
        regmap_read(nau8821->regmap, NAU8821_R1D_I2S_PCM_CTRL2, &ctrl_val);
@@ -843,6 +848,7 @@ static int nau8821_digital_mute(struct snd_soc_dai *dai, int mute,
 }
 
 static const struct snd_soc_dai_ops nau8821_dai_ops = {
+       .startup = nau8821_dai_startup,
        .hw_params = nau8821_hw_params,
        .set_fmt = nau8821_set_dai_fmt,
        .mute_stream = nau8821_digital_mute,
index ad54d70..1559645 100644 (file)
@@ -1014,27 +1014,42 @@ static irqreturn_t nau8824_interrupt(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-static int nau8824_clock_check(struct nau8824 *nau8824,
-       int stream, int rate, int osr)
+static const struct nau8824_osr_attr *
+nau8824_get_osr(struct nau8824 *nau8824, int stream)
 {
-       int osrate;
+       unsigned int osr;
 
        if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               regmap_read(nau8824->regmap,
+                           NAU8824_REG_DAC_FILTER_CTRL_1, &osr);
+               osr &= NAU8824_DAC_OVERSAMPLE_MASK;
                if (osr >= ARRAY_SIZE(osr_dac_sel))
-                       return -EINVAL;
-               osrate = osr_dac_sel[osr].osr;
+                       return NULL;
+               return &osr_dac_sel[osr];
        } else {
+               regmap_read(nau8824->regmap,
+                           NAU8824_REG_ADC_FILTER_CTRL, &osr);
+               osr &= NAU8824_ADC_SYNC_DOWN_MASK;
                if (osr >= ARRAY_SIZE(osr_adc_sel))
-                       return -EINVAL;
-               osrate = osr_adc_sel[osr].osr;
+                       return NULL;
+               return &osr_adc_sel[osr];
        }
+}
+
+static int nau8824_dai_startup(struct snd_pcm_substream *substream,
+                              struct snd_soc_dai *dai)
+{
+       struct snd_soc_component *component = dai->component;
+       struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component);
+       const struct nau8824_osr_attr *osr;
 
-       if (!osrate || rate * osr > CLK_DA_AD_MAX) {
-               dev_err(nau8824->dev, "exceed the maximum frequency of CLK_ADC or CLK_DAC\n");
+       osr = nau8824_get_osr(nau8824, substream->stream);
+       if (!osr || !osr->osr)
                return -EINVAL;
-       }
 
-       return 0;
+       return snd_pcm_hw_constraint_minmax(substream->runtime,
+                                           SNDRV_PCM_HW_PARAM_RATE,
+                                           0, CLK_DA_AD_MAX / osr->osr);
 }
 
 static int nau8824_hw_params(struct snd_pcm_substream *substream,
@@ -1042,7 +1057,9 @@ static int nau8824_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_soc_component *component = dai->component;
        struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component);
-       unsigned int val_len = 0, osr, ctrl_val, bclk_fs, bclk_div;
+       unsigned int val_len = 0, ctrl_val, bclk_fs, bclk_div;
+       const struct nau8824_osr_attr *osr;
+       int err = -EINVAL;
 
        nau8824_sema_acquire(nau8824, HZ);
 
@@ -1053,27 +1070,19 @@ static int nau8824_hw_params(struct snd_pcm_substream *substream,
         * than 6.144 MHz.
         */
        nau8824->fs = params_rate(params);
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               regmap_read(nau8824->regmap,
-                       NAU8824_REG_DAC_FILTER_CTRL_1, &osr);
-               osr &= NAU8824_DAC_OVERSAMPLE_MASK;
-               if (nau8824_clock_check(nau8824, substream->stream,
-                       nau8824->fs, osr))
-                       return -EINVAL;
+       osr = nau8824_get_osr(nau8824, substream->stream);
+       if (!osr || !osr->osr)
+               goto error;
+       if (nau8824->fs * osr->osr > CLK_DA_AD_MAX)
+               goto error;
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                regmap_update_bits(nau8824->regmap, NAU8824_REG_CLK_DIVIDER,
                        NAU8824_CLK_DAC_SRC_MASK,
-                       osr_dac_sel[osr].clk_src << NAU8824_CLK_DAC_SRC_SFT);
-       } else {
-               regmap_read(nau8824->regmap,
-                       NAU8824_REG_ADC_FILTER_CTRL, &osr);
-               osr &= NAU8824_ADC_SYNC_DOWN_MASK;
-               if (nau8824_clock_check(nau8824, substream->stream,
-                       nau8824->fs, osr))
-                       return -EINVAL;
+                       osr->clk_src << NAU8824_CLK_DAC_SRC_SFT);
+       else
                regmap_update_bits(nau8824->regmap, NAU8824_REG_CLK_DIVIDER,
                        NAU8824_CLK_ADC_SRC_MASK,
-                       osr_adc_sel[osr].clk_src << NAU8824_CLK_ADC_SRC_SFT);
-       }
+                       osr->clk_src << NAU8824_CLK_ADC_SRC_SFT);
 
        /* make BCLK and LRC divde configuration if the codec as master. */
        regmap_read(nau8824->regmap,
@@ -1090,7 +1099,7 @@ static int nau8824_hw_params(struct snd_pcm_substream *substream,
                else if (bclk_fs <= 256)
                        bclk_div = 0;
                else
-                       return -EINVAL;
+                       goto error;
                regmap_update_bits(nau8824->regmap,
                        NAU8824_REG_PORT0_I2S_PCM_CTRL_2,
                        NAU8824_I2S_LRC_DIV_MASK | NAU8824_I2S_BLK_DIV_MASK,
@@ -1111,15 +1120,17 @@ static int nau8824_hw_params(struct snd_pcm_substream *substream,
                val_len |= NAU8824_I2S_DL_32;
                break;
        default:
-               return -EINVAL;
+               goto error;
        }
 
        regmap_update_bits(nau8824->regmap, NAU8824_REG_PORT0_I2S_PCM_CTRL_1,
                NAU8824_I2S_DL_MASK, val_len);
+       err = 0;
 
+ error:
        nau8824_sema_release(nau8824);
 
-       return 0;
+       return err;
 }
 
 static int nau8824_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
@@ -1128,8 +1139,6 @@ static int nau8824_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component);
        unsigned int ctrl1_val = 0, ctrl2_val = 0;
 
-       nau8824_sema_acquire(nau8824, HZ);
-
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
        case SND_SOC_DAIFMT_CBM_CFM:
                ctrl2_val |= NAU8824_I2S_MS_MASTER;
@@ -1171,6 +1180,8 @@ static int nau8824_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
                return -EINVAL;
        }
 
+       nau8824_sema_acquire(nau8824, HZ);
+
        regmap_update_bits(nau8824->regmap, NAU8824_REG_PORT0_I2S_PCM_CTRL_1,
                NAU8824_I2S_DF_MASK | NAU8824_I2S_BP_MASK |
                NAU8824_I2S_PCMB_EN, ctrl1_val);
@@ -1547,6 +1558,7 @@ static const struct snd_soc_component_driver nau8824_component_driver = {
 };
 
 static const struct snd_soc_dai_ops nau8824_dai_ops = {
+       .startup = nau8824_dai_startup,
        .hw_params = nau8824_hw_params,
        .set_fmt = nau8824_set_fmt,
        .set_tdm_slot = nau8824_set_tdm_slot,
index 54ef7b0..8213273 100644 (file)
@@ -1247,27 +1247,42 @@ static const struct snd_soc_dapm_route nau8825_dapm_routes[] = {
        {"HPOR", NULL, "Class G"},
 };
 
-static int nau8825_clock_check(struct nau8825 *nau8825,
-       int stream, int rate, int osr)
+static const struct nau8825_osr_attr *
+nau8825_get_osr(struct nau8825 *nau8825, int stream)
 {
-       int osrate;
+       unsigned int osr;
 
        if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               regmap_read(nau8825->regmap,
+                           NAU8825_REG_DAC_CTRL1, &osr);
+               osr &= NAU8825_DAC_OVERSAMPLE_MASK;
                if (osr >= ARRAY_SIZE(osr_dac_sel))
-                       return -EINVAL;
-               osrate = osr_dac_sel[osr].osr;
+                       return NULL;
+               return &osr_dac_sel[osr];
        } else {
+               regmap_read(nau8825->regmap,
+                           NAU8825_REG_ADC_RATE, &osr);
+               osr &= NAU8825_ADC_SYNC_DOWN_MASK;
                if (osr >= ARRAY_SIZE(osr_adc_sel))
-                       return -EINVAL;
-               osrate = osr_adc_sel[osr].osr;
+                       return NULL;
+               return &osr_adc_sel[osr];
        }
+}
 
-       if (!osrate || rate * osr > CLK_DA_AD_MAX) {
-               dev_err(nau8825->dev, "exceed the maximum frequency of CLK_ADC or CLK_DAC\n");
+static int nau8825_dai_startup(struct snd_pcm_substream *substream,
+                              struct snd_soc_dai *dai)
+{
+       struct snd_soc_component *component = dai->component;
+       struct nau8825 *nau8825 = snd_soc_component_get_drvdata(component);
+       const struct nau8825_osr_attr *osr;
+
+       osr = nau8825_get_osr(nau8825, substream->stream);
+       if (!osr || !osr->osr)
                return -EINVAL;
-       }
 
-       return 0;
+       return snd_pcm_hw_constraint_minmax(substream->runtime,
+                                           SNDRV_PCM_HW_PARAM_RATE,
+                                           0, CLK_DA_AD_MAX / osr->osr);
 }
 
 static int nau8825_hw_params(struct snd_pcm_substream *substream,
@@ -1276,7 +1291,9 @@ static int nau8825_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_soc_component *component = dai->component;
        struct nau8825 *nau8825 = snd_soc_component_get_drvdata(component);
-       unsigned int val_len = 0, osr, ctrl_val, bclk_fs, bclk_div;
+       unsigned int val_len = 0, ctrl_val, bclk_fs, bclk_div;
+       const struct nau8825_osr_attr *osr;
+       int err = -EINVAL;
 
        nau8825_sema_acquire(nau8825, 3 * HZ);
 
@@ -1286,29 +1303,19 @@ static int nau8825_hw_params(struct snd_pcm_substream *substream,
         * values must be selected such that the maximum frequency is less
         * than 6.144 MHz.
         */
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               regmap_read(nau8825->regmap, NAU8825_REG_DAC_CTRL1, &osr);
-               osr &= NAU8825_DAC_OVERSAMPLE_MASK;
-               if (nau8825_clock_check(nau8825, substream->stream,
-                       params_rate(params), osr)) {
-                       nau8825_sema_release(nau8825);
-                       return -EINVAL;
-               }
+       osr = nau8825_get_osr(nau8825, substream->stream);
+       if (!osr || !osr->osr)
+               goto error;
+       if (params_rate(params) * osr->osr > CLK_DA_AD_MAX)
+               goto error;
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                regmap_update_bits(nau8825->regmap, NAU8825_REG_CLK_DIVIDER,
                        NAU8825_CLK_DAC_SRC_MASK,
-                       osr_dac_sel[osr].clk_src << NAU8825_CLK_DAC_SRC_SFT);
-       } else {
-               regmap_read(nau8825->regmap, NAU8825_REG_ADC_RATE, &osr);
-               osr &= NAU8825_ADC_SYNC_DOWN_MASK;
-               if (nau8825_clock_check(nau8825, substream->stream,
-                       params_rate(params), osr)) {
-                       nau8825_sema_release(nau8825);
-                       return -EINVAL;
-               }
+                       osr->clk_src << NAU8825_CLK_DAC_SRC_SFT);
+       else
                regmap_update_bits(nau8825->regmap, NAU8825_REG_CLK_DIVIDER,
                        NAU8825_CLK_ADC_SRC_MASK,
-                       osr_adc_sel[osr].clk_src << NAU8825_CLK_ADC_SRC_SFT);
-       }
+                       osr->clk_src << NAU8825_CLK_ADC_SRC_SFT);
 
        /* make BCLK and LRC divde configuration if the codec as master. */
        regmap_read(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL2, &ctrl_val);
@@ -1321,10 +1328,8 @@ static int nau8825_hw_params(struct snd_pcm_substream *substream,
                        bclk_div = 1;
                else if (bclk_fs <= 128)
                        bclk_div = 0;
-               else {
-                       nau8825_sema_release(nau8825);
-                       return -EINVAL;
-               }
+               else
+                       goto error;
                regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL2,
                        NAU8825_I2S_LRC_DIV_MASK | NAU8825_I2S_BLK_DIV_MASK,
                        ((bclk_div + 1) << NAU8825_I2S_LRC_DIV_SFT) | bclk_div);
@@ -1344,17 +1349,18 @@ static int nau8825_hw_params(struct snd_pcm_substream *substream,
                val_len |= NAU8825_I2S_DL_32;
                break;
        default:
-               nau8825_sema_release(nau8825);
-               return -EINVAL;
+               goto error;
        }
 
        regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL1,
                NAU8825_I2S_DL_MASK, val_len);
+       err = 0;
 
+ error:
        /* Release the semaphore. */
        nau8825_sema_release(nau8825);
 
-       return 0;
+       return err;
 }
 
 static int nau8825_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
@@ -1420,6 +1426,7 @@ static int nau8825_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 }
 
 static const struct snd_soc_dai_ops nau8825_dai_ops = {
+       .startup        = nau8825_dai_startup,
        .hw_params      = nau8825_hw_params,
        .set_fmt        = nau8825_set_dai_fmt,
 };
index 38ab8d4..5a84432 100644 (file)
@@ -1986,7 +1986,7 @@ static int rt5640_set_bias_level(struct snd_soc_component *component,
                snd_soc_component_write(component, RT5640_PWR_MIXER, 0x0000);
                if (rt5640->jd_src == RT5640_JD_SRC_HDA_HEADER)
                        snd_soc_component_write(component, RT5640_PWR_ANLG1,
-                               0x0018);
+                               0x2818);
                else
                        snd_soc_component_write(component, RT5640_PWR_ANLG1,
                                0x0000);
@@ -2600,7 +2600,8 @@ static void rt5640_enable_hda_jack_detect(
        snd_soc_component_update_bits(component, RT5640_DUMMY1, 0x400, 0x0);
 
        snd_soc_component_update_bits(component, RT5640_PWR_ANLG1,
-               RT5640_PWR_VREF2, RT5640_PWR_VREF2);
+               RT5640_PWR_VREF2 | RT5640_PWR_MB | RT5640_PWR_BG,
+               RT5640_PWR_VREF2 | RT5640_PWR_MB | RT5640_PWR_BG);
        usleep_range(10000, 15000);
        snd_soc_component_update_bits(component, RT5640_PWR_ANLG1,
                RT5640_PWR_FV2, RT5640_PWR_FV2);
index 3cb634c..bb653b6 100644 (file)
@@ -46,34 +46,22 @@ static void tas2770_reset(struct tas2770_priv *tas2770)
        usleep_range(1000, 2000);
 }
 
-static int tas2770_set_bias_level(struct snd_soc_component *component,
-                                enum snd_soc_bias_level level)
+static int tas2770_update_pwr_ctrl(struct tas2770_priv *tas2770)
 {
-       struct tas2770_priv *tas2770 =
-                       snd_soc_component_get_drvdata(component);
+       struct snd_soc_component *component = tas2770->component;
+       unsigned int val;
+       int ret;
 
-       switch (level) {
-       case SND_SOC_BIAS_ON:
-               snd_soc_component_update_bits(component, TAS2770_PWR_CTRL,
-                                             TAS2770_PWR_CTRL_MASK,
-                                             TAS2770_PWR_CTRL_ACTIVE);
-               break;
-       case SND_SOC_BIAS_STANDBY:
-       case SND_SOC_BIAS_PREPARE:
-               snd_soc_component_update_bits(component, TAS2770_PWR_CTRL,
-                                             TAS2770_PWR_CTRL_MASK,
-                                             TAS2770_PWR_CTRL_MUTE);
-               break;
-       case SND_SOC_BIAS_OFF:
-               snd_soc_component_update_bits(component, TAS2770_PWR_CTRL,
-                                             TAS2770_PWR_CTRL_MASK,
-                                             TAS2770_PWR_CTRL_SHUTDOWN);
-               break;
+       if (tas2770->dac_powered)
+               val = tas2770->unmuted ?
+                       TAS2770_PWR_CTRL_ACTIVE : TAS2770_PWR_CTRL_MUTE;
+       else
+               val = TAS2770_PWR_CTRL_SHUTDOWN;
 
-       default:
-               dev_err(tas2770->dev, "wrong power level setting %d\n", level);
-               return -EINVAL;
-       }
+       ret = snd_soc_component_update_bits(component, TAS2770_PWR_CTRL,
+                                           TAS2770_PWR_CTRL_MASK, val);
+       if (ret < 0)
+               return ret;
 
        return 0;
 }
@@ -114,9 +102,7 @@ static int tas2770_codec_resume(struct snd_soc_component *component)
                gpiod_set_value_cansleep(tas2770->sdz_gpio, 1);
                usleep_range(1000, 2000);
        } else {
-               ret = snd_soc_component_update_bits(component, TAS2770_PWR_CTRL,
-                                                   TAS2770_PWR_CTRL_MASK,
-                                                   TAS2770_PWR_CTRL_ACTIVE);
+               ret = tas2770_update_pwr_ctrl(tas2770);
                if (ret < 0)
                        return ret;
        }
@@ -152,24 +138,19 @@ static int tas2770_dac_event(struct snd_soc_dapm_widget *w,
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
-               ret = snd_soc_component_update_bits(component, TAS2770_PWR_CTRL,
-                                                   TAS2770_PWR_CTRL_MASK,
-                                                   TAS2770_PWR_CTRL_MUTE);
+               tas2770->dac_powered = 1;
+               ret = tas2770_update_pwr_ctrl(tas2770);
                break;
        case SND_SOC_DAPM_PRE_PMD:
-               ret = snd_soc_component_update_bits(component, TAS2770_PWR_CTRL,
-                                                   TAS2770_PWR_CTRL_MASK,
-                                                   TAS2770_PWR_CTRL_SHUTDOWN);
+               tas2770->dac_powered = 0;
+               ret = tas2770_update_pwr_ctrl(tas2770);
                break;
        default:
                dev_err(tas2770->dev, "Not supported evevt\n");
                return -EINVAL;
        }
 
-       if (ret < 0)
-               return ret;
-
-       return 0;
+       return ret;
 }
 
 static const struct snd_kcontrol_new isense_switch =
@@ -203,21 +184,11 @@ static const struct snd_soc_dapm_route tas2770_audio_map[] = {
 static int tas2770_mute(struct snd_soc_dai *dai, int mute, int direction)
 {
        struct snd_soc_component *component = dai->component;
-       int ret;
-
-       if (mute)
-               ret = snd_soc_component_update_bits(component, TAS2770_PWR_CTRL,
-                                                   TAS2770_PWR_CTRL_MASK,
-                                                   TAS2770_PWR_CTRL_MUTE);
-       else
-               ret = snd_soc_component_update_bits(component, TAS2770_PWR_CTRL,
-                                                   TAS2770_PWR_CTRL_MASK,
-                                                   TAS2770_PWR_CTRL_ACTIVE);
-
-       if (ret < 0)
-               return ret;
+       struct tas2770_priv *tas2770 =
+                       snd_soc_component_get_drvdata(component);
 
-       return 0;
+       tas2770->unmuted = !mute;
+       return tas2770_update_pwr_ctrl(tas2770);
 }
 
 static int tas2770_set_bitwidth(struct tas2770_priv *tas2770, int bitwidth)
@@ -337,7 +308,7 @@ static int tas2770_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        struct snd_soc_component *component = dai->component;
        struct tas2770_priv *tas2770 =
                        snd_soc_component_get_drvdata(component);
-       u8 tdm_rx_start_slot = 0, asi_cfg_1 = 0;
+       u8 tdm_rx_start_slot = 0, invert_fpol = 0, fpol_preinv = 0, asi_cfg_1 = 0;
        int ret;
 
        switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
@@ -349,9 +320,15 @@ static int tas2770_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        }
 
        switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_IF:
+               invert_fpol = 1;
+               fallthrough;
        case SND_SOC_DAIFMT_NB_NF:
                asi_cfg_1 |= TAS2770_TDM_CFG_REG1_RX_RSING;
                break;
+       case SND_SOC_DAIFMT_IB_IF:
+               invert_fpol = 1;
+               fallthrough;
        case SND_SOC_DAIFMT_IB_NF:
                asi_cfg_1 |= TAS2770_TDM_CFG_REG1_RX_FALING;
                break;
@@ -369,15 +346,19 @@ static int tas2770_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_I2S:
                tdm_rx_start_slot = 1;
+               fpol_preinv = 0;
                break;
        case SND_SOC_DAIFMT_DSP_A:
                tdm_rx_start_slot = 0;
+               fpol_preinv = 1;
                break;
        case SND_SOC_DAIFMT_DSP_B:
                tdm_rx_start_slot = 1;
+               fpol_preinv = 1;
                break;
        case SND_SOC_DAIFMT_LEFT_J:
                tdm_rx_start_slot = 0;
+               fpol_preinv = 1;
                break;
        default:
                dev_err(tas2770->dev,
@@ -391,6 +372,14 @@ static int tas2770_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        if (ret < 0)
                return ret;
 
+       ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG0,
+                                           TAS2770_TDM_CFG_REG0_FPOL_MASK,
+                                           (fpol_preinv ^ invert_fpol)
+                                            ? TAS2770_TDM_CFG_REG0_FPOL_RSING
+                                            : TAS2770_TDM_CFG_REG0_FPOL_FALING);
+       if (ret < 0)
+               return ret;
+
        return 0;
 }
 
@@ -489,7 +478,7 @@ static struct snd_soc_dai_driver tas2770_dai_driver[] = {
                .id = 0,
                .playback = {
                        .stream_name    = "ASI1 Playback",
-                       .channels_min   = 2,
+                       .channels_min   = 1,
                        .channels_max   = 2,
                        .rates      = TAS2770_RATES,
                        .formats    = TAS2770_FORMATS,
@@ -537,7 +526,6 @@ static const struct snd_soc_component_driver soc_component_driver_tas2770 = {
        .probe                  = tas2770_codec_probe,
        .suspend                = tas2770_codec_suspend,
        .resume                 = tas2770_codec_resume,
-       .set_bias_level = tas2770_set_bias_level,
        .controls               = tas2770_snd_controls,
        .num_controls           = ARRAY_SIZE(tas2770_snd_controls),
        .dapm_widgets           = tas2770_dapm_widgets,
index d156666..f75f407 100644 (file)
@@ -41,6 +41,9 @@
 #define TAS2770_TDM_CFG_REG0_31_44_1_48KHZ  0x6
 #define TAS2770_TDM_CFG_REG0_31_88_2_96KHZ  0x8
 #define TAS2770_TDM_CFG_REG0_31_176_4_192KHZ  0xa
+#define TAS2770_TDM_CFG_REG0_FPOL_MASK  BIT(0)
+#define TAS2770_TDM_CFG_REG0_FPOL_RSING  0
+#define TAS2770_TDM_CFG_REG0_FPOL_FALING  1
     /* TDM Configuration Reg1 */
 #define TAS2770_TDM_CFG_REG1  TAS2770_REG(0X0, 0x0B)
 #define TAS2770_TDM_CFG_REG1_MASK      GENMASK(5, 1)
@@ -135,6 +138,8 @@ struct tas2770_priv {
        struct device *dev;
        int v_sense_slot;
        int i_sense_slot;
+       bool dac_powered;
+       bool unmuted;
 };
 
 #endif /* __TAS2770__ */
index 4b74805..ffe1828 100644 (file)
@@ -49,6 +49,8 @@ struct aic32x4_priv {
        struct aic32x4_setup_data *setup;
        struct device *dev;
        enum aic32x4_type type;
+
+       unsigned int fmt;
 };
 
 static int aic32x4_reset_adc(struct snd_soc_dapm_widget *w,
@@ -611,6 +613,7 @@ static int aic32x4_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 {
        struct snd_soc_component *component = codec_dai->component;
+       struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
        u8 iface_reg_1 = 0;
        u8 iface_reg_2 = 0;
        u8 iface_reg_3 = 0;
@@ -653,6 +656,8 @@ static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
                return -EINVAL;
        }
 
+       aic32x4->fmt = fmt;
+
        snd_soc_component_update_bits(component, AIC32X4_IFACE1,
                                AIC32X4_IFACE1_DATATYPE_MASK |
                                AIC32X4_IFACE1_MASTER_MASK, iface_reg_1);
@@ -757,6 +762,10 @@ static int aic32x4_setup_clocks(struct snd_soc_component *component,
                return -EINVAL;
        }
 
+       /* PCM over I2S is always 2-channel */
+       if ((aic32x4->fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S)
+               channels = 2;
+
        madc = DIV_ROUND_UP((32 * adc_resource_class), aosr);
        max_dosr = (AIC32X4_MAX_DOSR_FREQ / sample_rate / dosr_increment) *
                        dosr_increment;
index 873295f..1e421d9 100644 (file)
@@ -234,18 +234,26 @@ static int fsl_aud2htx_probe(struct platform_device *pdev)
 
        regcache_cache_only(aud2htx->regmap, true);
 
+       /*
+        * Register platform component before registering cpu dai for there
+        * is not defer probe for platform component in snd_soc_add_pcm_runtime().
+        */
+       ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to pcm register\n");
+               pm_runtime_disable(&pdev->dev);
+               return ret;
+       }
+
        ret = devm_snd_soc_register_component(&pdev->dev,
                                              &fsl_aud2htx_component,
                                              &fsl_aud2htx_dai, 1);
        if (ret) {
                dev_err(&pdev->dev, "failed to register ASoC DAI\n");
+               pm_runtime_disable(&pdev->dev);
                return ret;
        }
 
-       ret = imx_pcm_dma_init(pdev);
-       if (ret)
-               dev_err(&pdev->dev, "failed to init imx pcm dma: %d\n", ret);
-
        return ret;
 }
 
index c1e2f67..4922e67 100644 (file)
@@ -122,7 +122,7 @@ static int fsl_mqs_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        }
 
        switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
-       case SND_SOC_DAIFMT_BP_FP:
+       case SND_SOC_DAIFMT_CBC_CFC:
                break;
        default:
                return -EINVAL;
index 7523bb9..d430eec 100644 (file)
@@ -1306,7 +1306,7 @@ static int fsl_sai_probe(struct platform_device *pdev)
                sai->mclk_clk[i] = devm_clk_get(dev, tmp);
                if (IS_ERR(sai->mclk_clk[i])) {
                        dev_err(dev, "failed to get mclk%d clock: %ld\n",
-                                       i + 1, PTR_ERR(sai->mclk_clk[i]));
+                                       i, PTR_ERR(sai->mclk_clk[i]));
                        sai->mclk_clk[i] = NULL;
                }
        }
index f21b0cd..8fe5917 100644 (file)
@@ -636,8 +636,8 @@ static ssize_t topology_name_read(struct file *file, char __user *user_buf, size
        char buf[64];
        size_t len;
 
-       len = snprintf(buf, sizeof(buf), "%s/%s\n", component->driver->topology_name_prefix,
-                      mach->tplg_filename);
+       len = scnprintf(buf, sizeof(buf), "%s/%s\n", component->driver->topology_name_prefix,
+                       mach->tplg_filename);
 
        return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 }
index c7f33c8..606cc32 100644 (file)
@@ -760,6 +760,9 @@ static int sof_es8336_remove(struct platform_device *pdev)
 
 static const struct platform_device_id board_ids[] = {
        {
+               .name = "sof-essx8336", /* default quirk == 0 */
+       },
+       {
                .name = "adl_es83x6_c1_h02",
                .driver_data = (kernel_ulong_t)(SOF_ES8336_SSP_CODEC(1) |
                                        SOF_NO_OF_HDMI_CAPTURE_SSP(2) |
@@ -786,5 +789,4 @@ module_platform_driver(sof_es8336_driver);
 
 MODULE_DESCRIPTION("ASoC Intel(R) SOF + ES8336 Machine driver");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:sof-essx8336");
 MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
index 2667045..0944024 100644 (file)
@@ -271,9 +271,6 @@ static int mtk_adda_ul_event(struct snd_soc_dapm_widget *w,
                /* should delayed 1/fs(smallest is 8k) = 125us before afe off */
                usleep_range(125, 135);
                mt8186_afe_gpio_request(afe->dev, false, MT8186_DAI_ADDA, 1);
-
-               /* reset dmic */
-               afe_priv->mtkaif_dmic = 0;
                break;
        default:
                break;
index ce4a571..98a2fde 100644 (file)
@@ -270,6 +270,7 @@ static int sm8250_platform_probe(struct platform_device *pdev)
        if (!card)
                return -ENOMEM;
 
+       card->owner = THIS_MODULE;
        /* Allocate the private data */
        data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
        if (!data)
index 0d0594a..7ace0c0 100644 (file)
@@ -1017,32 +1017,36 @@ static int rz_ssi_probe(struct platform_device *pdev)
 
        ssi->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
        if (IS_ERR(ssi->rstc)) {
-               rz_ssi_release_dma_channels(ssi);
-               return PTR_ERR(ssi->rstc);
+               ret = PTR_ERR(ssi->rstc);
+               goto err_reset;
        }
 
        reset_control_deassert(ssi->rstc);
        pm_runtime_enable(&pdev->dev);
        ret = pm_runtime_resume_and_get(&pdev->dev);
        if (ret < 0) {
-               rz_ssi_release_dma_channels(ssi);
-               pm_runtime_disable(ssi->dev);
-               reset_control_assert(ssi->rstc);
-               return dev_err_probe(ssi->dev, ret, "pm_runtime_resume_and_get failed\n");
+               dev_err(&pdev->dev, "pm_runtime_resume_and_get failed\n");
+               goto err_pm;
        }
 
        ret = devm_snd_soc_register_component(&pdev->dev, &rz_ssi_soc_component,
                                              rz_ssi_soc_dai,
                                              ARRAY_SIZE(rz_ssi_soc_dai));
        if (ret < 0) {
-               rz_ssi_release_dma_channels(ssi);
-
-               pm_runtime_put(ssi->dev);
-               pm_runtime_disable(ssi->dev);
-               reset_control_assert(ssi->rstc);
                dev_err(&pdev->dev, "failed to register snd component\n");
+               goto err_snd_soc;
        }
 
+       return 0;
+
+err_snd_soc:
+       pm_runtime_put(ssi->dev);
+err_pm:
+       pm_runtime_disable(ssi->dev);
+       reset_control_assert(ssi->rstc);
+err_reset:
+       rz_ssi_release_dma_channels(ssi);
+
        return ret;
 }
 
index 5b99bf2..4f60c0a 100644 (file)
@@ -1317,6 +1317,9 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card,
                if (!be->dai_link->no_pcm)
                        continue;
 
+               if (!snd_soc_dpcm_get_substream(be, stream))
+                       continue;
+
                for_each_rtd_dais(be, i, dai) {
                        w = snd_soc_dai_get_widget(dai, stream);
 
index e90f173..37f7df5 100644 (file)
@@ -196,6 +196,7 @@ config SND_SOC_SOF_DEBUG_ENABLE_FIRMWARE_TRACE
 
 config SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST
        tristate "SOF enable IPC flood test"
+       depends on SND_SOC_SOF
        select SND_SOC_SOF_CLIENT
        help
          This option enables a separate client device for IPC flood test
@@ -214,6 +215,7 @@ config SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST_NUM
 
 config SND_SOC_SOF_DEBUG_IPC_MSG_INJECTOR
        tristate "SOF enable IPC message injector"
+       depends on SND_SOC_SOF
        select SND_SOC_SOF_CLIENT
        help
          This option enables the IPC message injector which can be used to send
index c5d797e..d9a3ce7 100644 (file)
@@ -252,9 +252,9 @@ static int memory_info_update(struct snd_sof_dev *sdev, char *buf, size_t buff_s
        }
 
        for (i = 0, len = 0; i < reply->num_elems; i++) {
-               ret = snprintf(buf + len, buff_size - len, "zone %d.%d used %#8x free %#8x\n",
-                              reply->elems[i].zone, reply->elems[i].id,
-                              reply->elems[i].used, reply->elems[i].free);
+               ret = scnprintf(buf + len, buff_size - len, "zone %d.%d used %#8x free %#8x\n",
+                               reply->elems[i].zone, reply->elems[i].id,
+                               reply->elems[i].used, reply->elems[i].free);
                if (ret < 0)
                        goto error;
                len += ret;
index 8639ea6..6d4ecbe 100644 (file)
@@ -574,7 +574,7 @@ static void hda_dsp_dump_ext_rom_status(struct snd_sof_dev *sdev, const char *le
        chip = get_chip_info(sdev->pdata);
        for (i = 0; i < HDA_EXT_ROM_STATUS_SIZE; i++) {
                value = snd_sof_dsp_read(sdev, HDA_DSP_BAR, chip->rom_status_reg + i * 0x4);
-               len += snprintf(msg + len, sizeof(msg) - len, " 0x%x", value);
+               len += scnprintf(msg + len, sizeof(msg) - len, " 0x%x", value);
        }
 
        dev_printk(level, sdev->dev, "extended rom status: %s", msg);
index b2cc046..65923e7 100644 (file)
@@ -2338,7 +2338,7 @@ static int sof_ipc3_parse_manifest(struct snd_soc_component *scomp, int index,
        }
 
        dev_info(scomp->dev,
-                "Topology: ABI %d:%d:%d Kernel ABI %hhu:%hhu:%hhu\n",
+                "Topology: ABI %d:%d:%d Kernel ABI %d:%d:%d\n",
                 man->priv.data[0], man->priv.data[1], man->priv.data[2],
                 SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_PATCH);
 
index af072b4..64929dc 100644 (file)
@@ -771,7 +771,7 @@ static int sof_ipc4_widget_setup_comp_src(struct snd_sof_widget *swidget)
                goto err;
 
        ret = sof_update_ipc_object(scomp, src, SOF_SRC_TOKENS, swidget->tuples,
-                                   swidget->num_tuples, sizeof(src), 1);
+                                   swidget->num_tuples, sizeof(*src), 1);
        if (ret) {
                dev_err(scomp->dev, "Parsing SRC tokens failed\n");
                goto err;
@@ -1251,7 +1251,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
                        if (blob->alh_cfg.count > 1) {
                                int group_id;
 
-                               group_id = ida_alloc_max(&alh_group_ida, ALH_MULTI_GTW_COUNT,
+                               group_id = ida_alloc_max(&alh_group_ida, ALH_MULTI_GTW_COUNT - 1,
                                                         GFP_KERNEL);
 
                                if (group_id < 0)
index d356743..706d249 100644 (file)
@@ -699,7 +699,7 @@ static bool check_delayed_register_option(struct snd_usb_audio *chip, int iface)
                if (delayed_register[i] &&
                    sscanf(delayed_register[i], "%x:%x", &id, &inum) == 2 &&
                    id == chip->usb_id)
-                       return inum != iface;
+                       return iface < inum;
        }
 
        return false;
index 0d7b73b..eb71df9 100644 (file)
@@ -924,6 +924,8 @@ void snd_usb_endpoint_close(struct snd_usb_audio *chip,
                endpoint_set_interface(chip, ep, false);
 
        if (!--ep->opened) {
+               if (ep->clock_ref && !atomic_read(&ep->clock_ref->locked))
+                       ep->clock_ref->rate = 0;
                ep->iface = 0;
                ep->altsetting = 0;
                ep->cur_audiofmt = NULL;
index 168fd80..5b4d8f5 100644 (file)
@@ -1764,7 +1764,7 @@ bool snd_usb_registration_quirk(struct snd_usb_audio *chip, int iface)
 
        for (q = registration_quirks; q->usb_id; q++)
                if (chip->usb_id == q->usb_id)
-                       return iface != q->interface;
+                       return iface < q->interface;
 
        /* Register as normal */
        return false;
@@ -1903,6 +1903,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
                   QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
        DEVICE_FLG(0x21b4, 0x0081, /* AudioQuest DragonFly */
                   QUIRK_FLAG_GET_SAMPLE_RATE),
+       DEVICE_FLG(0x2522, 0x0007, /* LH Labs Geek Out HD Audio 1V5 */
+                  QUIRK_FLAG_SET_IFACE_FIRST),
        DEVICE_FLG(0x2708, 0x0002, /* Audient iD14 */
                   QUIRK_FLAG_IGNORE_CTL_ERROR),
        DEVICE_FLG(0x2912, 0x30c8, /* Audioengine D1 */
index ceb93d7..f10f4e6 100644 (file)
@@ -495,6 +495,10 @@ static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip,
                        return 0;
                }
        }
+
+       if (chip->card->registered)
+               chip->need_delayed_register = true;
+
        /* look for an empty stream */
        list_for_each_entry(as, &chip->pcm_list, list) {
                if (as->fmt_type != fp->fmt_type)
@@ -502,9 +506,6 @@ static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip,
                subs = &as->substream[stream];
                if (subs->ep_num)
                        continue;
-               if (snd_device_get_state(chip->card, as->pcm) !=
-                   SNDRV_DEV_BUILD)
-                       chip->need_delayed_register = true;
                err = snd_pcm_new_stream(as->pcm, stream, 1);
                if (err < 0)
                        return err;
@@ -1105,7 +1106,7 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip,
         * Dallas DS4201 workaround: It presents 5 altsettings, but the last
         * one misses syncpipe, and does not produce any sound.
         */
-       if (chip->usb_id == USB_ID(0x04fa, 0x4201))
+       if (chip->usb_id == USB_ID(0x04fa, 0x4201) && num >= 4)
                num = 4;
 
        for (i = 0; i < num; i++) {
index 3bb1343..316917b 100644 (file)
@@ -75,9 +75,11 @@ struct kvm_regs {
 
 /* KVM_ARM_SET_DEVICE_ADDR ioctl id encoding */
 #define KVM_ARM_DEVICE_TYPE_SHIFT      0
-#define KVM_ARM_DEVICE_TYPE_MASK       (0xffff << KVM_ARM_DEVICE_TYPE_SHIFT)
+#define KVM_ARM_DEVICE_TYPE_MASK       GENMASK(KVM_ARM_DEVICE_TYPE_SHIFT + 15, \
+                                               KVM_ARM_DEVICE_TYPE_SHIFT)
 #define KVM_ARM_DEVICE_ID_SHIFT                16
-#define KVM_ARM_DEVICE_ID_MASK         (0xffff << KVM_ARM_DEVICE_ID_SHIFT)
+#define KVM_ARM_DEVICE_ID_MASK         GENMASK(KVM_ARM_DEVICE_ID_SHIFT + 15, \
+                                               KVM_ARM_DEVICE_ID_SHIFT)
 
 /* Supported device IDs */
 #define KVM_ARM_DEVICE_VGIC_V2         0
index 7a6b148..a73cf01 100644 (file)
@@ -74,6 +74,7 @@ struct kvm_s390_io_adapter_req {
 #define KVM_S390_VM_CRYPTO             2
 #define KVM_S390_VM_CPU_MODEL          3
 #define KVM_S390_VM_MIGRATION          4
+#define KVM_S390_VM_CPU_TOPOLOGY       5
 
 /* kvm attributes for mem_ctrl */
 #define KVM_S390_VM_MEM_ENABLE_CMMA    0
index 8323ac5..ef4775c 100644 (file)
 #define X86_FEATURE_IBRS               ( 7*32+25) /* Indirect Branch Restricted Speculation */
 #define X86_FEATURE_IBPB               ( 7*32+26) /* Indirect Branch Prediction Barrier */
 #define X86_FEATURE_STIBP              ( 7*32+27) /* Single Thread Indirect Branch Predictors */
-#define X86_FEATURE_ZEN                        ( 7*32+28) /* "" CPU is AMD family 0x17 or above (Zen) */
+#define X86_FEATURE_ZEN                        (7*32+28) /* "" CPU based on Zen microarchitecture */
 #define X86_FEATURE_L1TF_PTEINV                ( 7*32+29) /* "" L1TF workaround PTE inversion */
 #define X86_FEATURE_IBRS_ENHANCED      ( 7*32+30) /* Enhanced IBRS */
 #define X86_FEATURE_MSR_IA32_FEAT_CTL  ( 7*32+31) /* "" MSR IA32_FEAT_CTL configured */
 #define X86_FEATURE_RETHUNK            (11*32+14) /* "" Use REturn THUNK */
 #define X86_FEATURE_UNRET              (11*32+15) /* "" AMD BTB untrain return */
 #define X86_FEATURE_USE_IBPB_FW                (11*32+16) /* "" Use IBPB during runtime firmware calls */
-#define X86_FEATURE_RSB_VMEXIT_LITE    (11*32+17) /* "" Fill RSB on VM-Exit when EIBRS is enabled */
+#define X86_FEATURE_RSB_VMEXIT_LITE    (11*32+17) /* "" Fill RSB on VM exit when EIBRS is enabled */
 
 /* Intel-defined CPU features, CPUID level 0x00000007:1 (EAX), word 12 */
 #define X86_FEATURE_AVX_VNNI           (12*32+ 4) /* AVX VNNI instructions */
 #define X86_FEATURE_AVIC               (15*32+13) /* Virtual Interrupt Controller */
 #define X86_FEATURE_V_VMSAVE_VMLOAD    (15*32+15) /* Virtual VMSAVE VMLOAD */
 #define X86_FEATURE_VGIF               (15*32+16) /* Virtual GIF */
+#define X86_FEATURE_X2AVIC             (15*32+18) /* Virtual x2apic */
 #define X86_FEATURE_V_SPEC_CTRL                (15*32+20) /* Virtual SPEC_CTRL */
 #define X86_FEATURE_SVME_ADDR_CHK      (15*32+28) /* "" SVME addr check */
 
 #define X86_BUG_ITLB_MULTIHIT          X86_BUG(23) /* CPU may incur MCE during certain page attribute changes */
 #define X86_BUG_SRBDS                  X86_BUG(24) /* CPU may leak RNG bits if not mitigated */
 #define X86_BUG_MMIO_STALE_DATA                X86_BUG(25) /* CPU is affected by Processor MMIO Stale Data vulnerabilities */
-#define X86_BUG_RETBLEED               X86_BUG(26) /* CPU is affected by RETBleed */
+#define X86_BUG_MMIO_UNKNOWN           X86_BUG(26) /* CPU is too old and its MMIO Stale Data status is unknown */
+#define X86_BUG_RETBLEED               X86_BUG(27) /* CPU is affected by RETBleed */
+#define X86_BUG_EIBRS_PBRSB            X86_BUG(28) /* EIBRS is vulnerable to Post Barrier RSB Predictions */
 
 #endif /* _ASM_X86_CPUFEATURES_H */
index e057e03..6674bdb 100644 (file)
 #define PERF_CAP_PT_IDX                        16
 
 #define MSR_PEBS_LD_LAT_THRESHOLD      0x000003f6
+#define PERF_CAP_PEBS_TRAP             BIT_ULL(6)
+#define PERF_CAP_ARCH_REG              BIT_ULL(7)
+#define PERF_CAP_PEBS_FORMAT           0xf00
+#define PERF_CAP_PEBS_BASELINE         BIT_ULL(14)
+#define PERF_CAP_PEBS_MASK     (PERF_CAP_PEBS_TRAP | PERF_CAP_ARCH_REG | \
+                                PERF_CAP_PEBS_FORMAT | PERF_CAP_PEBS_BASELINE)
 
 #define MSR_IA32_RTIT_CTL              0x00000570
 #define RTIT_CTL_TRACEEN               BIT(0)
 #define MSR_TURBO_ACTIVATION_RATIO     0x0000064C
 
 #define MSR_PLATFORM_ENERGY_STATUS     0x0000064D
+#define MSR_SECONDARY_TURBO_RATIO_LIMIT        0x00000650
 
 #define MSR_PKG_WEIGHTED_CORE_C0_RES   0x00000658
 #define MSR_PKG_ANY_CORE_C0_RES                0x00000659
 #define MSR_IA32_VMX_TRUE_EXIT_CTLS      0x0000048f
 #define MSR_IA32_VMX_TRUE_ENTRY_CTLS     0x00000490
 #define MSR_IA32_VMX_VMFUNC             0x00000491
+#define MSR_IA32_VMX_PROCBASED_CTLS3   0x00000492
 
 /* VMX_BASIC bits and bitmasks */
 #define VMX_BASIC_VMCS_SIZE_SHIFT      32
index fee7983..11ff975 100644 (file)
@@ -2,8 +2,6 @@
 #ifndef _TOOLS_LINUX_ASM_X86_RMWcc
 #define _TOOLS_LINUX_ASM_X86_RMWcc
 
-#ifdef CONFIG_CC_HAS_ASM_GOTO
-
 #define __GEN_RMWcc(fullop, var, cc, ...)                              \
 do {                                                                   \
        asm_volatile_goto (fullop "; j" cc " %l[cc_label]"              \
@@ -20,23 +18,4 @@ cc_label:                                                            \
 #define GEN_BINARY_RMWcc(op, var, vcon, val, arg0, cc)                 \
        __GEN_RMWcc(op " %1, " arg0, var, cc, vcon (val))
 
-#else /* !CONFIG_CC_HAS_ASM_GOTO */
-
-#define __GEN_RMWcc(fullop, var, cc, ...)                              \
-do {                                                                   \
-       char c;                                                         \
-       asm volatile (fullop "; set" cc " %1"                           \
-                       : "+m" (var), "=qm" (c)                         \
-                       : __VA_ARGS__ : "memory");                      \
-       return c != 0;                                                  \
-} while (0)
-
-#define GEN_UNARY_RMWcc(op, var, arg0, cc)                             \
-       __GEN_RMWcc(op " " arg0, var, cc)
-
-#define GEN_BINARY_RMWcc(op, var, vcon, val, arg0, cc)                 \
-       __GEN_RMWcc(op " %2, " arg0, var, cc, vcon (val))
-
-#endif /* CONFIG_CC_HAS_ASM_GOTO */
-
 #endif /* _TOOLS_LINUX_ASM_X86_RMWcc */
index ec53c9f..46de10a 100644 (file)
@@ -306,7 +306,8 @@ struct kvm_pit_state {
        struct kvm_pit_channel_state channels[3];
 };
 
-#define KVM_PIT_FLAGS_HPET_LEGACY  0x00000001
+#define KVM_PIT_FLAGS_HPET_LEGACY     0x00000001
+#define KVM_PIT_FLAGS_SPEAKER_DATA_ON 0x00000002
 
 struct kvm_pit_state2 {
        struct kvm_pit_channel_state channels[3];
@@ -325,6 +326,7 @@ struct kvm_reinject_control {
 #define KVM_VCPUEVENT_VALID_SHADOW     0x00000004
 #define KVM_VCPUEVENT_VALID_SMM                0x00000008
 #define KVM_VCPUEVENT_VALID_PAYLOAD    0x00000010
+#define KVM_VCPUEVENT_VALID_TRIPLE_FAULT       0x00000020
 
 /* Interrupt shadow states */
 #define KVM_X86_SHADOW_INT_MOV_SS      0x01
@@ -359,7 +361,10 @@ struct kvm_vcpu_events {
                __u8 smm_inside_nmi;
                __u8 latched_init;
        } smi;
-       __u8 reserved[27];
+       struct {
+               __u8 pending;
+       } triple_fault;
+       __u8 reserved[26];
        __u8 exception_has_payload;
        __u64 exception_payload;
 };
@@ -434,6 +439,7 @@ struct kvm_sync_regs {
 #define KVM_X86_QUIRK_OUT_7E_INC_RIP           (1 << 3)
 #define KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT     (1 << 4)
 #define KVM_X86_QUIRK_FIX_HYPERCALL_INSN       (1 << 5)
+#define KVM_X86_QUIRK_MWAIT_NEVER_UD_FAULTS    (1 << 6)
 
 #define KVM_STATE_NESTED_FORMAT_VMX    0
 #define KVM_STATE_NESTED_FORMAT_SVM    1
index 946d761..a5faf6d 100644 (file)
@@ -91,6 +91,7 @@
 #define EXIT_REASON_UMWAIT              67
 #define EXIT_REASON_TPAUSE              68
 #define EXIT_REASON_BUS_LOCK            74
+#define EXIT_REASON_NOTIFY              75
 
 #define VMX_EXIT_REASONS \
        { EXIT_REASON_EXCEPTION_NMI,         "EXCEPTION_NMI" }, \
        { EXIT_REASON_XRSTORS,               "XRSTORS" }, \
        { EXIT_REASON_UMWAIT,                "UMWAIT" }, \
        { EXIT_REASON_TPAUSE,                "TPAUSE" }, \
-       { EXIT_REASON_BUS_LOCK,              "BUS_LOCK" }
+       { EXIT_REASON_BUS_LOCK,              "BUS_LOCK" }, \
+       { EXIT_REASON_NOTIFY,                "NOTIFY" }
 
 #define VMX_EXIT_REASON_FLAGS \
        { VMX_EXIT_REASONS_FAILED_VMENTRY,      "FAILED_VMENTRY" }
index f1af27c..279be06 100755 (executable)
@@ -187,6 +187,7 @@ else
        echo " * auxiliary taint, defined for and used by distros (#16)"
 
 fi
+
 T=`expr $T / 2`
 if [ `expr $T % 2` -eq 0 ]; then
        addout " "
@@ -195,6 +196,14 @@ else
        echo " * kernel was built with the struct randomization plugin (#17)"
 fi
 
+T=`expr $T / 2`
+if [ `expr $T % 2` -eq 0 ]; then
+       addout " "
+else
+       addout "N"
+       echo " * an in-kernel test (such as a KUnit test) has been run (#18)"
+fi
+
 echo "For a more detailed explanation of the various taint flags see"
 echo " Documentation/admin-guide/tainted-kernels.rst in the Linux kernel sources"
 echo " or https://kernel.org/doc/html/latest/admin-guide/tainted-kernels.html"
index 1e6fd6c..27f5e7d 100644 (file)
@@ -44,7 +44,7 @@
 
 /*
  * KVP protocol: The user mode component first registers with the
- * the kernel component. Subsequently, the kernel component requests, data
+ * kernel component. Subsequently, the kernel component requests, data
  * for the specified keys. In response to this message the user mode component
  * fills in the value corresponding to the specified key. We overload the
  * sequence field in the cn_msg header to define our KVP message types.
@@ -772,11 +772,11 @@ static int kvp_process_ip_address(void *addrp,
        const char *str;
 
        if (family == AF_INET) {
-               addr = (struct sockaddr_in *)addrp;
+               addr = addrp;
                str = inet_ntop(family, &addr->sin_addr, tmp, 50);
                addr_length = INET_ADDRSTRLEN;
        } else {
-               addr6 = (struct sockaddr_in6 *)addrp;
+               addr6 = addrp;
                str = inet_ntop(family, &addr6->sin6_addr.s6_addr, tmp, 50);
                addr_length = INET6_ADDRSTRLEN;
        }
index 24ae305..1bdd834 100644 (file)
@@ -36,4 +36,8 @@
 #include <linux/compiler-gcc.h>
 #endif
 
+#ifndef asm_volatile_goto
+#define asm_volatile_goto(x...) asm goto(x)
+#endif
+
 #endif /* __LINUX_COMPILER_TYPES_H */
index d30439b..869379f 100644 (file)
@@ -9,8 +9,8 @@
 #include "../../../arch/alpha/include/uapi/asm/errno.h"
 #elif defined(__mips__)
 #include "../../../arch/mips/include/uapi/asm/errno.h"
-#elif defined(__xtensa__)
-#include "../../../arch/xtensa/include/uapi/asm/errno.h"
+#elif defined(__hppa__)
+#include "../../../arch/parisc/include/uapi/asm/errno.h"
 #else
 #include <asm-generic/errno.h>
 #endif
index b28ff5d..520ad26 100644 (file)
@@ -751,14 +751,27 @@ typedef struct drm_i915_irq_wait {
 
 /* Must be kept compact -- no holes and well documented */
 
-typedef struct drm_i915_getparam {
+/**
+ * struct drm_i915_getparam - Driver parameter query structure.
+ */
+struct drm_i915_getparam {
+       /** @param: Driver parameter to query. */
        __s32 param;
-       /*
+
+       /**
+        * @value: Address of memory where queried value should be put.
+        *
         * WARNING: Using pointers instead of fixed-size u64 means we need to write
         * compat32 code. Don't repeat this mistake.
         */
        int __user *value;
-} drm_i915_getparam_t;
+};
+
+/**
+ * typedef drm_i915_getparam_t - Driver parameter query structure.
+ * See struct drm_i915_getparam.
+ */
+typedef struct drm_i915_getparam drm_i915_getparam_t;
 
 /* Ioctl to set kernel params:
  */
@@ -1239,76 +1252,119 @@ struct drm_i915_gem_exec_object2 {
        __u64 rsvd2;
 };
 
+/**
+ * struct drm_i915_gem_exec_fence - An input or output fence for the execbuf
+ * ioctl.
+ *
+ * The request will wait for input fence to signal before submission.
+ *
+ * The returned output fence will be signaled after the completion of the
+ * request.
+ */
 struct drm_i915_gem_exec_fence {
-       /**
-        * User's handle for a drm_syncobj to wait on or signal.
-        */
+       /** @handle: User's handle for a drm_syncobj to wait on or signal. */
        __u32 handle;
 
+       /**
+        * @flags: Supported flags are:
+        *
+        * I915_EXEC_FENCE_WAIT:
+        * Wait for the input fence before request submission.
+        *
+        * I915_EXEC_FENCE_SIGNAL:
+        * Return request completion fence as output
+        */
+       __u32 flags;
 #define I915_EXEC_FENCE_WAIT            (1<<0)
 #define I915_EXEC_FENCE_SIGNAL          (1<<1)
 #define __I915_EXEC_FENCE_UNKNOWN_FLAGS (-(I915_EXEC_FENCE_SIGNAL << 1))
-       __u32 flags;
 };
 
-/*
- * See drm_i915_gem_execbuffer_ext_timeline_fences.
- */
-#define DRM_I915_GEM_EXECBUFFER_EXT_TIMELINE_FENCES 0
-
-/*
+/**
+ * struct drm_i915_gem_execbuffer_ext_timeline_fences - Timeline fences
+ * for execbuf ioctl.
+ *
  * This structure describes an array of drm_syncobj and associated points for
  * timeline variants of drm_syncobj. It is invalid to append this structure to
  * the execbuf if I915_EXEC_FENCE_ARRAY is set.
  */
 struct drm_i915_gem_execbuffer_ext_timeline_fences {
+#define DRM_I915_GEM_EXECBUFFER_EXT_TIMELINE_FENCES 0
+       /** @base: Extension link. See struct i915_user_extension. */
        struct i915_user_extension base;
 
        /**
-        * Number of element in the handles_ptr & value_ptr arrays.
+        * @fence_count: Number of elements in the @handles_ptr & @value_ptr
+        * arrays.
         */
        __u64 fence_count;
 
        /**
-        * Pointer to an array of struct drm_i915_gem_exec_fence of length
-        * fence_count.
+        * @handles_ptr: Pointer to an array of struct drm_i915_gem_exec_fence
+        * of length @fence_count.
         */
        __u64 handles_ptr;
 
        /**
-        * Pointer to an array of u64 values of length fence_count. Values
-        * must be 0 for a binary drm_syncobj. A Value of 0 for a timeline
-        * drm_syncobj is invalid as it turns a drm_syncobj into a binary one.
+        * @values_ptr: Pointer to an array of u64 values of length
+        * @fence_count.
+        * Values must be 0 for a binary drm_syncobj. A Value of 0 for a
+        * timeline drm_syncobj is invalid as it turns a drm_syncobj into a
+        * binary one.
         */
        __u64 values_ptr;
 };
 
+/**
+ * struct drm_i915_gem_execbuffer2 - Structure for DRM_I915_GEM_EXECBUFFER2
+ * ioctl.
+ */
 struct drm_i915_gem_execbuffer2 {
-       /**
-        * List of gem_exec_object2 structs
-        */
+       /** @buffers_ptr: Pointer to a list of gem_exec_object2 structs */
        __u64 buffers_ptr;
+
+       /** @buffer_count: Number of elements in @buffers_ptr array */
        __u32 buffer_count;
 
-       /** Offset in the batchbuffer to start execution from. */
+       /**
+        * @batch_start_offset: Offset in the batchbuffer to start execution
+        * from.
+        */
        __u32 batch_start_offset;
-       /** Bytes used in batchbuffer from batch_start_offset */
+
+       /**
+        * @batch_len: Length in bytes of the batch buffer, starting from the
+        * @batch_start_offset. If 0, length is assumed to be the batch buffer
+        * object size.
+        */
        __u32 batch_len;
+
+       /** @DR1: deprecated */
        __u32 DR1;
+
+       /** @DR4: deprecated */
        __u32 DR4;
+
+       /** @num_cliprects: See @cliprects_ptr */
        __u32 num_cliprects;
+
        /**
-        * This is a struct drm_clip_rect *cliprects if I915_EXEC_FENCE_ARRAY
-        * & I915_EXEC_USE_EXTENSIONS are not set.
+        * @cliprects_ptr: Kernel clipping was a DRI1 misfeature.
+        *
+        * It is invalid to use this field if I915_EXEC_FENCE_ARRAY or
+        * I915_EXEC_USE_EXTENSIONS flags are not set.
         *
         * If I915_EXEC_FENCE_ARRAY is set, then this is a pointer to an array
-        * of struct drm_i915_gem_exec_fence and num_cliprects is the length
-        * of the array.
+        * of &drm_i915_gem_exec_fence and @num_cliprects is the length of the
+        * array.
         *
         * If I915_EXEC_USE_EXTENSIONS is set, then this is a pointer to a
-        * single struct i915_user_extension and num_cliprects is 0.
+        * single &i915_user_extension and num_cliprects is 0.
         */
        __u64 cliprects_ptr;
+
+       /** @flags: Execbuf flags */
+       __u64 flags;
 #define I915_EXEC_RING_MASK              (0x3f)
 #define I915_EXEC_DEFAULT                (0<<0)
 #define I915_EXEC_RENDER                 (1<<0)
@@ -1326,10 +1382,6 @@ struct drm_i915_gem_execbuffer2 {
 #define I915_EXEC_CONSTANTS_REL_GENERAL (0<<6) /* default */
 #define I915_EXEC_CONSTANTS_ABSOLUTE   (1<<6)
 #define I915_EXEC_CONSTANTS_REL_SURFACE (2<<6) /* gen4/5 only */
-       __u64 flags;
-       __u64 rsvd1; /* now used for context info */
-       __u64 rsvd2;
-};
 
 /** Resets the SO write offset registers for transform feedback on gen7. */
 #define I915_EXEC_GEN7_SOL_RESET       (1<<8)
@@ -1432,9 +1484,23 @@ struct drm_i915_gem_execbuffer2 {
  * drm_i915_gem_execbuffer_ext enum.
  */
 #define I915_EXEC_USE_EXTENSIONS       (1 << 21)
-
 #define __I915_EXEC_UNKNOWN_FLAGS (-(I915_EXEC_USE_EXTENSIONS << 1))
 
+       /** @rsvd1: Context id */
+       __u64 rsvd1;
+
+       /**
+        * @rsvd2: in and out sync_file file descriptors.
+        *
+        * When I915_EXEC_FENCE_IN or I915_EXEC_FENCE_SUBMIT flag is set, the
+        * lower 32 bits of this field will have the in sync_file fd (input).
+        *
+        * When I915_EXEC_FENCE_OUT flag is set, the upper 32 bits of this
+        * field will have the out sync_file fd (output).
+        */
+       __u64 rsvd2;
+};
+
 #define I915_EXEC_CONTEXT_ID_MASK      (0xffffffff)
 #define i915_execbuffer2_set_context_id(eb2, context) \
        (eb2).rsvd1 = context & I915_EXEC_CONTEXT_ID_MASK
@@ -1814,19 +1880,58 @@ struct drm_i915_gem_context_create {
        __u32 pad;
 };
 
+/**
+ * struct drm_i915_gem_context_create_ext - Structure for creating contexts.
+ */
 struct drm_i915_gem_context_create_ext {
-       __u32 ctx_id; /* output: id of new context*/
+       /** @ctx_id: Id of the created context (output) */
+       __u32 ctx_id;
+
+       /**
+        * @flags: Supported flags are:
+        *
+        * I915_CONTEXT_CREATE_FLAGS_USE_EXTENSIONS:
+        *
+        * Extensions may be appended to this structure and driver must check
+        * for those. See @extensions.
+        *
+        * I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE
+        *
+        * Created context will have single timeline.
+        */
        __u32 flags;
 #define I915_CONTEXT_CREATE_FLAGS_USE_EXTENSIONS       (1u << 0)
 #define I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE      (1u << 1)
 #define I915_CONTEXT_CREATE_FLAGS_UNKNOWN \
        (-(I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE << 1))
+
+       /**
+        * @extensions: Zero-terminated chain of extensions.
+        *
+        * I915_CONTEXT_CREATE_EXT_SETPARAM:
+        * Context parameter to set or query during context creation.
+        * See struct drm_i915_gem_context_create_ext_setparam.
+        *
+        * I915_CONTEXT_CREATE_EXT_CLONE:
+        * This extension has been removed. On the off chance someone somewhere
+        * has attempted to use it, never re-use this extension number.
+        */
        __u64 extensions;
+#define I915_CONTEXT_CREATE_EXT_SETPARAM 0
+#define I915_CONTEXT_CREATE_EXT_CLONE 1
 };
 
+/**
+ * struct drm_i915_gem_context_param - Context parameter to set or query.
+ */
 struct drm_i915_gem_context_param {
+       /** @ctx_id: Context id */
        __u32 ctx_id;
+
+       /** @size: Size of the parameter @value */
        __u32 size;
+
+       /** @param: Parameter to set or query */
        __u64 param;
 #define I915_CONTEXT_PARAM_BAN_PERIOD  0x1
 /* I915_CONTEXT_PARAM_NO_ZEROMAP has been removed.  On the off chance
@@ -1973,6 +2078,7 @@ struct drm_i915_gem_context_param {
 #define I915_CONTEXT_PARAM_PROTECTED_CONTENT    0xd
 /* Must be kept compact -- no holes and well documented */
 
+       /** @value: Context parameter value to be set or queried */
        __u64 value;
 };
 
@@ -2371,23 +2477,29 @@ struct i915_context_param_engines {
        struct i915_engine_class_instance engines[N__]; \
 } __attribute__((packed)) name__
 
+/**
+ * struct drm_i915_gem_context_create_ext_setparam - Context parameter
+ * to set or query during context creation.
+ */
 struct drm_i915_gem_context_create_ext_setparam {
-#define I915_CONTEXT_CREATE_EXT_SETPARAM 0
+       /** @base: Extension link. See struct i915_user_extension. */
        struct i915_user_extension base;
+
+       /**
+        * @param: Context parameter to set or query.
+        * See struct drm_i915_gem_context_param.
+        */
        struct drm_i915_gem_context_param param;
 };
 
-/* This API has been removed.  On the off chance someone somewhere has
- * attempted to use it, never re-use this extension number.
- */
-#define I915_CONTEXT_CREATE_EXT_CLONE 1
-
 struct drm_i915_gem_context_destroy {
        __u32 ctx_id;
        __u32 pad;
 };
 
-/*
+/**
+ * struct drm_i915_gem_vm_control - Structure to create or destroy VM.
+ *
  * DRM_I915_GEM_VM_CREATE -
  *
  * Create a new virtual memory address space (ppGTT) for use within a context
@@ -2397,20 +2509,23 @@ struct drm_i915_gem_context_destroy {
  * The id of new VM (bound to the fd) for use with I915_CONTEXT_PARAM_VM is
  * returned in the outparam @id.
  *
- * No flags are defined, with all bits reserved and must be zero.
- *
  * An extension chain maybe provided, starting with @extensions, and terminated
  * by the @next_extension being 0. Currently, no extensions are defined.
  *
  * DRM_I915_GEM_VM_DESTROY -
  *
- * Destroys a previously created VM id, specified in @id.
+ * Destroys a previously created VM id, specified in @vm_id.
  *
  * No extensions or flags are allowed currently, and so must be zero.
  */
 struct drm_i915_gem_vm_control {
+       /** @extensions: Zero-terminated chain of extensions. */
        __u64 extensions;
+
+       /** @flags: reserved for future usage, currently MBZ */
        __u32 flags;
+
+       /** @vm_id: Id of the VM created or to be destroyed */
        __u32 vm_id;
 };
 
@@ -3207,36 +3322,6 @@ struct drm_i915_gem_memory_class_instance {
  * struct drm_i915_memory_region_info - Describes one region as known to the
  * driver.
  *
- * Note that we reserve some stuff here for potential future work. As an example
- * we might want expose the capabilities for a given region, which could include
- * things like if the region is CPU mappable/accessible, what are the supported
- * mapping types etc.
- *
- * Note that to extend struct drm_i915_memory_region_info and struct
- * drm_i915_query_memory_regions in the future the plan is to do the following:
- *
- * .. code-block:: C
- *
- *     struct drm_i915_memory_region_info {
- *             struct drm_i915_gem_memory_class_instance region;
- *             union {
- *                     __u32 rsvd0;
- *                     __u32 new_thing1;
- *             };
- *             ...
- *             union {
- *                     __u64 rsvd1[8];
- *                     struct {
- *                             __u64 new_thing2;
- *                             __u64 new_thing3;
- *                             ...
- *                     };
- *             };
- *     };
- *
- * With this things should remain source compatible between versions for
- * userspace, even as we add new fields.
- *
  * Note this is using both struct drm_i915_query_item and struct drm_i915_query.
  * For this new query we are adding the new query id DRM_I915_QUERY_MEMORY_REGIONS
  * at &drm_i915_query_item.query_id.
@@ -3248,14 +3333,81 @@ struct drm_i915_memory_region_info {
        /** @rsvd0: MBZ */
        __u32 rsvd0;
 
-       /** @probed_size: Memory probed by the driver (-1 = unknown) */
+       /**
+        * @probed_size: Memory probed by the driver
+        *
+        * Note that it should not be possible to ever encounter a zero value
+        * here, also note that no current region type will ever return -1 here.
+        * Although for future region types, this might be a possibility. The
+        * same applies to the other size fields.
+        */
        __u64 probed_size;
 
-       /** @unallocated_size: Estimate of memory remaining (-1 = unknown) */
+       /**
+        * @unallocated_size: Estimate of memory remaining
+        *
+        * Requires CAP_PERFMON or CAP_SYS_ADMIN to get reliable accounting.
+        * Without this (or if this is an older kernel) the value here will
+        * always equal the @probed_size. Note this is only currently tracked
+        * for I915_MEMORY_CLASS_DEVICE regions (for other types the value here
+        * will always equal the @probed_size).
+        */
        __u64 unallocated_size;
 
-       /** @rsvd1: MBZ */
-       __u64 rsvd1[8];
+       union {
+               /** @rsvd1: MBZ */
+               __u64 rsvd1[8];
+               struct {
+                       /**
+                        * @probed_cpu_visible_size: Memory probed by the driver
+                        * that is CPU accessible.
+                        *
+                        * This will be always be <= @probed_size, and the
+                        * remainder (if there is any) will not be CPU
+                        * accessible.
+                        *
+                        * On systems without small BAR, the @probed_size will
+                        * always equal the @probed_cpu_visible_size, since all
+                        * of it will be CPU accessible.
+                        *
+                        * Note this is only tracked for
+                        * I915_MEMORY_CLASS_DEVICE regions (for other types the
+                        * value here will always equal the @probed_size).
+                        *
+                        * Note that if the value returned here is zero, then
+                        * this must be an old kernel which lacks the relevant
+                        * small-bar uAPI support (including
+                        * I915_GEM_CREATE_EXT_FLAG_NEEDS_CPU_ACCESS), but on
+                        * such systems we should never actually end up with a
+                        * small BAR configuration, assuming we are able to load
+                        * the kernel module. Hence it should be safe to treat
+                        * this the same as when @probed_cpu_visible_size ==
+                        * @probed_size.
+                        */
+                       __u64 probed_cpu_visible_size;
+
+                       /**
+                        * @unallocated_cpu_visible_size: Estimate of CPU
+                        * visible memory remaining.
+                        *
+                        * Note this is only tracked for
+                        * I915_MEMORY_CLASS_DEVICE regions (for other types the
+                        * value here will always equal the
+                        * @probed_cpu_visible_size).
+                        *
+                        * Requires CAP_PERFMON or CAP_SYS_ADMIN to get reliable
+                        * accounting.  Without this the value here will always
+                        * equal the @probed_cpu_visible_size. Note this is only
+                        * currently tracked for I915_MEMORY_CLASS_DEVICE
+                        * regions (for other types the value here will also
+                        * always equal the @probed_cpu_visible_size).
+                        *
+                        * If this is an older kernel the value here will be
+                        * zero, see also @probed_cpu_visible_size.
+                        */
+                       __u64 unallocated_cpu_visible_size;
+               };
+       };
 };
 
 /**
@@ -3329,11 +3481,11 @@ struct drm_i915_query_memory_regions {
  * struct drm_i915_gem_create_ext - Existing gem_create behaviour, with added
  * extension support using struct i915_user_extension.
  *
- * Note that in the future we want to have our buffer flags here, at least for
- * the stuff that is immutable. Previously we would have two ioctls, one to
- * create the object with gem_create, and another to apply various parameters,
- * however this creates some ambiguity for the params which are considered
- * immutable. Also in general we're phasing out the various SET/GET ioctls.
+ * Note that new buffer flags should be added here, at least for the stuff that
+ * is immutable. Previously we would have two ioctls, one to create the object
+ * with gem_create, and another to apply various parameters, however this
+ * creates some ambiguity for the params which are considered immutable. Also in
+ * general we're phasing out the various SET/GET ioctls.
  */
 struct drm_i915_gem_create_ext {
        /**
@@ -3341,7 +3493,6 @@ struct drm_i915_gem_create_ext {
         *
         * The (page-aligned) allocated size for the object will be returned.
         *
-        *
         * DG2 64K min page size implications:
         *
         * On discrete platforms, starting from DG2, we have to contend with GTT
@@ -3353,7 +3504,9 @@ struct drm_i915_gem_create_ext {
         *
         * Note that the returned size here will always reflect any required
         * rounding up done by the kernel, i.e 4K will now become 64K on devices
-        * such as DG2.
+        * such as DG2. The kernel will always select the largest minimum
+        * page-size for the set of possible placements as the value to use when
+        * rounding up the @size.
         *
         * Special DG2 GTT address alignment requirement:
         *
@@ -3377,14 +3530,58 @@ struct drm_i915_gem_create_ext {
         * is deemed to be a good compromise.
         */
        __u64 size;
+
        /**
         * @handle: Returned handle for the object.
         *
         * Object handles are nonzero.
         */
        __u32 handle;
-       /** @flags: MBZ */
+
+       /**
+        * @flags: Optional flags.
+        *
+        * Supported values:
+        *
+        * I915_GEM_CREATE_EXT_FLAG_NEEDS_CPU_ACCESS - Signal to the kernel that
+        * the object will need to be accessed via the CPU.
+        *
+        * Only valid when placing objects in I915_MEMORY_CLASS_DEVICE, and only
+        * strictly required on configurations where some subset of the device
+        * memory is directly visible/mappable through the CPU (which we also
+        * call small BAR), like on some DG2+ systems. Note that this is quite
+        * undesirable, but due to various factors like the client CPU, BIOS etc
+        * it's something we can expect to see in the wild. See
+        * &drm_i915_memory_region_info.probed_cpu_visible_size for how to
+        * determine if this system applies.
+        *
+        * Note that one of the placements MUST be I915_MEMORY_CLASS_SYSTEM, to
+        * ensure the kernel can always spill the allocation to system memory,
+        * if the object can't be allocated in the mappable part of
+        * I915_MEMORY_CLASS_DEVICE.
+        *
+        * Also note that since the kernel only supports flat-CCS on objects
+        * that can *only* be placed in I915_MEMORY_CLASS_DEVICE, we therefore
+        * don't support I915_GEM_CREATE_EXT_FLAG_NEEDS_CPU_ACCESS together with
+        * flat-CCS.
+        *
+        * Without this hint, the kernel will assume that non-mappable
+        * I915_MEMORY_CLASS_DEVICE is preferred for this object. Note that the
+        * kernel can still migrate the object to the mappable part, as a last
+        * resort, if userspace ever CPU faults this object, but this might be
+        * expensive, and so ideally should be avoided.
+        *
+        * On older kernels which lack the relevant small-bar uAPI support (see
+        * also &drm_i915_memory_region_info.probed_cpu_visible_size),
+        * usage of the flag will result in an error, but it should NEVER be
+        * possible to end up with a small BAR configuration, assuming we can
+        * also successfully load the i915 kernel module. In such cases the
+        * entire I915_MEMORY_CLASS_DEVICE region will be CPU accessible, and as
+        * such there are zero restrictions on where the object can be placed.
+        */
+#define I915_GEM_CREATE_EXT_FLAG_NEEDS_CPU_ACCESS (1 << 0)
        __u32 flags;
+
        /**
         * @extensions: The chain of extensions to apply to this object.
         *
@@ -3443,6 +3640,22 @@ struct drm_i915_gem_create_ext {
  * At which point we get the object handle in &drm_i915_gem_create_ext.handle,
  * along with the final object size in &drm_i915_gem_create_ext.size, which
  * should account for any rounding up, if required.
+ *
+ * Note that userspace has no means of knowing the current backing region
+ * for objects where @num_regions is larger than one. The kernel will only
+ * ensure that the priority order of the @regions array is honoured, either
+ * when initially placing the object, or when moving memory around due to
+ * memory pressure
+ *
+ * On Flat-CCS capable HW, compression is supported for the objects residing
+ * in I915_MEMORY_CLASS_DEVICE. When such objects (compressed) have other
+ * memory class in @regions and migrated (by i915, due to memory
+ * constraints) to the non I915_MEMORY_CLASS_DEVICE region, then i915 needs to
+ * decompress the content. But i915 doesn't have the required information to
+ * decompress the userspace compressed objects.
+ *
+ * So i915 supports Flat-CCS, on the objects which can reside only on
+ * I915_MEMORY_CLASS_DEVICE regions.
  */
 struct drm_i915_gem_create_ext_memory_regions {
        /** @base: Extension link. See struct i915_user_extension. */
index 9f4428b..a756b29 100644 (file)
@@ -27,7 +27,8 @@
 #define FSCRYPT_MODE_AES_128_CBC               5
 #define FSCRYPT_MODE_AES_128_CTS               6
 #define FSCRYPT_MODE_ADIANTUM                  9
-/* If adding a mode number > 9, update FSCRYPT_MODE_MAX in fscrypt_private.h */
+#define FSCRYPT_MODE_AES_256_HCTR2             10
+/* If adding a mode number > 10, update FSCRYPT_MODE_MAX in fscrypt_private.h */
 
 /*
  * Legacy policy version; ad-hoc KDF and no key verification.
index cb6e384..eed0315 100644 (file)
@@ -270,6 +270,8 @@ struct kvm_xen_exit {
 #define KVM_EXIT_X86_BUS_LOCK     33
 #define KVM_EXIT_XEN              34
 #define KVM_EXIT_RISCV_SBI        35
+#define KVM_EXIT_RISCV_CSR        36
+#define KVM_EXIT_NOTIFY           37
 
 /* For KVM_EXIT_INTERNAL_ERROR */
 /* Emulate instruction failed. */
@@ -496,6 +498,18 @@ struct kvm_run {
                        unsigned long args[6];
                        unsigned long ret[2];
                } riscv_sbi;
+               /* KVM_EXIT_RISCV_CSR */
+               struct {
+                       unsigned long csr_num;
+                       unsigned long new_value;
+                       unsigned long write_mask;
+                       unsigned long ret_value;
+               } riscv_csr;
+               /* KVM_EXIT_NOTIFY */
+               struct {
+#define KVM_NOTIFY_CONTEXT_INVALID     (1 << 0)
+                       __u32 flags;
+               } notify;
                /* Fix the size of the union. */
                char padding[256];
        };
@@ -1157,6 +1171,12 @@ struct kvm_ppc_resize_hpt {
 #define KVM_CAP_VM_TSC_CONTROL 214
 #define KVM_CAP_SYSTEM_EVENT_DATA 215
 #define KVM_CAP_ARM_SYSTEM_SUSPEND 216
+#define KVM_CAP_S390_PROTECTED_DUMP 217
+#define KVM_CAP_X86_TRIPLE_FAULT_EVENT 218
+#define KVM_CAP_X86_NOTIFY_VMEXIT 219
+#define KVM_CAP_VM_DISABLE_NX_HUGE_PAGES 220
+#define KVM_CAP_S390_ZPCI_OP 221
+#define KVM_CAP_S390_CPU_TOPOLOGY 222
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -1660,6 +1680,55 @@ struct kvm_s390_pv_unp {
        __u64 tweak;
 };
 
+enum pv_cmd_dmp_id {
+       KVM_PV_DUMP_INIT,
+       KVM_PV_DUMP_CONFIG_STOR_STATE,
+       KVM_PV_DUMP_COMPLETE,
+       KVM_PV_DUMP_CPU,
+};
+
+struct kvm_s390_pv_dmp {
+       __u64 subcmd;
+       __u64 buff_addr;
+       __u64 buff_len;
+       __u64 gaddr;            /* For dump storage state */
+       __u64 reserved[4];
+};
+
+enum pv_cmd_info_id {
+       KVM_PV_INFO_VM,
+       KVM_PV_INFO_DUMP,
+};
+
+struct kvm_s390_pv_info_dump {
+       __u64 dump_cpu_buffer_len;
+       __u64 dump_config_mem_buffer_per_1m;
+       __u64 dump_config_finalize_len;
+};
+
+struct kvm_s390_pv_info_vm {
+       __u64 inst_calls_list[4];
+       __u64 max_cpus;
+       __u64 max_guests;
+       __u64 max_guest_addr;
+       __u64 feature_indication;
+};
+
+struct kvm_s390_pv_info_header {
+       __u32 id;
+       __u32 len_max;
+       __u32 len_written;
+       __u32 reserved;
+};
+
+struct kvm_s390_pv_info {
+       struct kvm_s390_pv_info_header header;
+       union {
+               struct kvm_s390_pv_info_dump dump;
+               struct kvm_s390_pv_info_vm vm;
+       };
+};
+
 enum pv_cmd_id {
        KVM_PV_ENABLE,
        KVM_PV_DISABLE,
@@ -1668,6 +1737,8 @@ enum pv_cmd_id {
        KVM_PV_VERIFY,
        KVM_PV_PREP_RESET,
        KVM_PV_UNSHARE_ALL,
+       KVM_PV_INFO,
+       KVM_PV_DUMP,
 };
 
 struct kvm_pv_cmd {
@@ -2119,4 +2190,41 @@ struct kvm_stats_desc {
 /* Available with KVM_CAP_XSAVE2 */
 #define KVM_GET_XSAVE2           _IOR(KVMIO,  0xcf, struct kvm_xsave)
 
+/* Available with KVM_CAP_S390_PROTECTED_DUMP */
+#define KVM_S390_PV_CPU_COMMAND        _IOWR(KVMIO, 0xd0, struct kvm_pv_cmd)
+
+/* Available with KVM_CAP_X86_NOTIFY_VMEXIT */
+#define KVM_X86_NOTIFY_VMEXIT_ENABLED          (1ULL << 0)
+#define KVM_X86_NOTIFY_VMEXIT_USER             (1ULL << 1)
+
+/* Available with KVM_CAP_S390_ZPCI_OP */
+#define KVM_S390_ZPCI_OP         _IOW(KVMIO,  0xd1, struct kvm_s390_zpci_op)
+
+struct kvm_s390_zpci_op {
+       /* in */
+       __u32 fh;               /* target device */
+       __u8  op;               /* operation to perform */
+       __u8  pad[3];
+       union {
+               /* for KVM_S390_ZPCIOP_REG_AEN */
+               struct {
+                       __u64 ibv;      /* Guest addr of interrupt bit vector */
+                       __u64 sb;       /* Guest addr of summary bit */
+                       __u32 flags;
+                       __u32 noi;      /* Number of interrupts */
+                       __u8 isc;       /* Guest interrupt subclass */
+                       __u8 sbo;       /* Offset of guest summary bit vector */
+                       __u16 pad;
+               } reg_aen;
+               __u64 reserved[8];
+       } u;
+};
+
+/* types for kvm_s390_zpci_op->op */
+#define KVM_S390_ZPCIOP_REG_AEN                0
+#define KVM_S390_ZPCIOP_DEREG_AEN      1
+
+/* flags for kvm_s390_zpci_op->u.reg_aen.flags */
+#define KVM_S390_ZPCIOP_REGAEN_HOST    (1 << 0)
+
 #endif /* __LINUX_KVM_H */
index e2b77fb..581ed4b 100644 (file)
@@ -301,6 +301,7 @@ enum {
  *       { u64         time_enabled; } && PERF_FORMAT_TOTAL_TIME_ENABLED
  *       { u64         time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING
  *       { u64         id;           } && PERF_FORMAT_ID
+ *       { u64         lost;         } && PERF_FORMAT_LOST
  *     } && !PERF_FORMAT_GROUP
  *
  *     { u64           nr;
@@ -308,6 +309,7 @@ enum {
  *       { u64         time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING
  *       { u64         value;
  *         { u64       id;           } && PERF_FORMAT_ID
+ *         { u64       lost;         } && PERF_FORMAT_LOST
  *       }             cntr[nr];
  *     } && PERF_FORMAT_GROUP
  * };
@@ -317,8 +319,9 @@ enum perf_event_read_format {
        PERF_FORMAT_TOTAL_TIME_RUNNING          = 1U << 1,
        PERF_FORMAT_ID                          = 1U << 2,
        PERF_FORMAT_GROUP                       = 1U << 3,
+       PERF_FORMAT_LOST                        = 1U << 4,
 
-       PERF_FORMAT_MAX = 1U << 4,              /* non-ABI */
+       PERF_FORMAT_MAX = 1U << 5,              /* non-ABI */
 };
 
 #define PERF_ATTR_SIZE_VER0    64      /* sizeof first published struct */
index cab645d..f9f115a 100644 (file)
 #define VHOST_VDPA_SET_GROUP_ASID      _IOW(VHOST_VIRTIO, 0x7C, \
                                             struct vhost_vring_state)
 
+/* Suspend a device so it does not process virtqueue requests anymore
+ *
+ * After the return of ioctl the device must preserve all the necessary state
+ * (the virtqueue vring base plus the possible device specific states) that is
+ * required for restoring in the future. The device must not change its
+ * configuration after that point.
+ */
+#define VHOST_VDPA_SUSPEND             _IO(VHOST_VIRTIO, 0x7D)
+
 #endif
index 384d5e0..6cd0be7 100644 (file)
@@ -309,7 +309,7 @@ bool perf_cpu_map__has(const struct perf_cpu_map *cpus, struct perf_cpu cpu)
        return perf_cpu_map__idx(cpus, cpu) != -1;
 }
 
-struct perf_cpu perf_cpu_map__max(struct perf_cpu_map *map)
+struct perf_cpu perf_cpu_map__max(const struct perf_cpu_map *map)
 {
        struct perf_cpu result = {
                .cpu = -1
index e6c98a6..8ec5b9f 100644 (file)
@@ -441,6 +441,7 @@ mmap_per_evsel(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
 
        perf_evlist__for_each_entry(evlist, evsel) {
                bool overwrite = evsel->attr.write_backward;
+               enum fdarray_flags flgs;
                struct perf_mmap *map;
                int *output, fd, cpu;
 
@@ -486,6 +487,7 @@ mmap_per_evsel(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
                        if (ops->idx)
                                ops->idx(evlist, evsel, mp, idx);
 
+                       pr_debug("idx %d: mmapping fd %d\n", idx, *output);
                        if (ops->mmap(map, mp, *output, evlist_cpu) < 0)
                                return -1;
 
@@ -494,6 +496,7 @@ mmap_per_evsel(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
                        if (!idx)
                                perf_evlist__set_mmap_first(evlist, map, overwrite);
                } else {
+                       pr_debug("idx %d: set output fd %d -> %d\n", idx, fd, *output);
                        if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, *output) != 0)
                                return -1;
 
@@ -502,8 +505,8 @@ mmap_per_evsel(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
 
                revent = !overwrite ? POLLIN : 0;
 
-               if (!evsel->system_wide &&
-                   perf_evlist__add_pollfd(evlist, fd, map, revent, fdarray_flag__default) < 0) {
+               flgs = evsel->system_wide ? fdarray_flag__nonfilterable : fdarray_flag__default;
+               if (perf_evlist__add_pollfd(evlist, fd, map, revent, flgs) < 0) {
                        perf_mmap__put(map);
                        return -1;
                }
@@ -520,6 +523,48 @@ mmap_per_evsel(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
 }
 
 static int
+mmap_per_thread(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
+               struct perf_mmap_param *mp)
+{
+       int nr_threads = perf_thread_map__nr(evlist->threads);
+       int nr_cpus    = perf_cpu_map__nr(evlist->all_cpus);
+       int cpu, thread, idx = 0;
+       int nr_mmaps = 0;
+
+       pr_debug("%s: nr cpu values (may include -1) %d nr threads %d\n",
+                __func__, nr_cpus, nr_threads);
+
+       /* per-thread mmaps */
+       for (thread = 0; thread < nr_threads; thread++, idx++) {
+               int output = -1;
+               int output_overwrite = -1;
+
+               if (mmap_per_evsel(evlist, ops, idx, mp, 0, thread, &output,
+                                  &output_overwrite, &nr_mmaps))
+                       goto out_unmap;
+       }
+
+       /* system-wide mmaps i.e. per-cpu */
+       for (cpu = 1; cpu < nr_cpus; cpu++, idx++) {
+               int output = -1;
+               int output_overwrite = -1;
+
+               if (mmap_per_evsel(evlist, ops, idx, mp, cpu, 0, &output,
+                                  &output_overwrite, &nr_mmaps))
+                       goto out_unmap;
+       }
+
+       if (nr_mmaps != evlist->nr_mmaps)
+               pr_err("Miscounted nr_mmaps %d vs %d\n", nr_mmaps, evlist->nr_mmaps);
+
+       return 0;
+
+out_unmap:
+       perf_evlist__munmap(evlist);
+       return -1;
+}
+
+static int
 mmap_per_cpu(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
             struct perf_mmap_param *mp)
 {
@@ -528,6 +573,8 @@ mmap_per_cpu(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
        int nr_mmaps = 0;
        int cpu, thread;
 
+       pr_debug("%s: nr cpu values %d nr threads %d\n", __func__, nr_cpus, nr_threads);
+
        for (cpu = 0; cpu < nr_cpus; cpu++) {
                int output = -1;
                int output_overwrite = -1;
@@ -569,6 +616,7 @@ int perf_evlist__mmap_ops(struct perf_evlist *evlist,
                          struct perf_evlist_mmap_ops *ops,
                          struct perf_mmap_param *mp)
 {
+       const struct perf_cpu_map *cpus = evlist->all_cpus;
        struct perf_evsel *evsel;
 
        if (!ops || !ops->get || !ops->mmap)
@@ -588,6 +636,9 @@ int perf_evlist__mmap_ops(struct perf_evlist *evlist,
        if (evlist->pollfd.entries == NULL && perf_evlist__alloc_pollfd(evlist) < 0)
                return -ENOMEM;
 
+       if (perf_cpu_map__empty(cpus))
+               return mmap_per_thread(evlist, ops, mp);
+
        return mmap_per_cpu(evlist, ops, mp);
 }
 
index 952f352..8ce5bbd 100644 (file)
@@ -305,6 +305,9 @@ int perf_evsel__read_size(struct perf_evsel *evsel)
        if (read_format & PERF_FORMAT_ID)
                entry += sizeof(u64);
 
+       if (read_format & PERF_FORMAT_LOST)
+               entry += sizeof(u64);
+
        if (read_format & PERF_FORMAT_GROUP) {
                nr = evsel->nr_members;
                size += sizeof(u64);
@@ -314,24 +317,98 @@ int perf_evsel__read_size(struct perf_evsel *evsel)
        return size;
 }
 
+/* This only reads values for the leader */
+static int perf_evsel__read_group(struct perf_evsel *evsel, int cpu_map_idx,
+                                 int thread, struct perf_counts_values *count)
+{
+       size_t size = perf_evsel__read_size(evsel);
+       int *fd = FD(evsel, cpu_map_idx, thread);
+       u64 read_format = evsel->attr.read_format;
+       u64 *data;
+       int idx = 1;
+
+       if (fd == NULL || *fd < 0)
+               return -EINVAL;
+
+       data = calloc(1, size);
+       if (data == NULL)
+               return -ENOMEM;
+
+       if (readn(*fd, data, size) <= 0) {
+               free(data);
+               return -errno;
+       }
+
+       /*
+        * This reads only the leader event intentionally since we don't have
+        * perf counts values for sibling events.
+        */
+       if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
+               count->ena = data[idx++];
+       if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
+               count->run = data[idx++];
+
+       /* value is always available */
+       count->val = data[idx++];
+       if (read_format & PERF_FORMAT_ID)
+               count->id = data[idx++];
+       if (read_format & PERF_FORMAT_LOST)
+               count->lost = data[idx++];
+
+       free(data);
+       return 0;
+}
+
+/*
+ * The perf read format is very flexible.  It needs to set the proper
+ * values according to the read format.
+ */
+static void perf_evsel__adjust_values(struct perf_evsel *evsel, u64 *buf,
+                                     struct perf_counts_values *count)
+{
+       u64 read_format = evsel->attr.read_format;
+       int n = 0;
+
+       count->val = buf[n++];
+
+       if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
+               count->ena = buf[n++];
+
+       if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
+               count->run = buf[n++];
+
+       if (read_format & PERF_FORMAT_ID)
+               count->id = buf[n++];
+
+       if (read_format & PERF_FORMAT_LOST)
+               count->lost = buf[n++];
+}
+
 int perf_evsel__read(struct perf_evsel *evsel, int cpu_map_idx, int thread,
                     struct perf_counts_values *count)
 {
        size_t size = perf_evsel__read_size(evsel);
        int *fd = FD(evsel, cpu_map_idx, thread);
+       u64 read_format = evsel->attr.read_format;
+       struct perf_counts_values buf;
 
        memset(count, 0, sizeof(*count));
 
        if (fd == NULL || *fd < 0)
                return -EINVAL;
 
+       if (read_format & PERF_FORMAT_GROUP)
+               return perf_evsel__read_group(evsel, cpu_map_idx, thread, count);
+
        if (MMAP(evsel, cpu_map_idx, thread) &&
+           !(read_format & (PERF_FORMAT_ID | PERF_FORMAT_LOST)) &&
            !perf_mmap__read_self(MMAP(evsel, cpu_map_idx, thread), count))
                return 0;
 
-       if (readn(*fd, count->values, size) <= 0)
+       if (readn(*fd, buf.values, size) <= 0)
                return -errno;
 
+       perf_evsel__adjust_values(evsel, buf.values, count);
        return 0;
 }
 
index 24de795..03aceb7 100644 (file)
@@ -23,7 +23,7 @@ LIBPERF_API void perf_cpu_map__put(struct perf_cpu_map *map);
 LIBPERF_API struct perf_cpu perf_cpu_map__cpu(const struct perf_cpu_map *cpus, int idx);
 LIBPERF_API int perf_cpu_map__nr(const struct perf_cpu_map *cpus);
 LIBPERF_API bool perf_cpu_map__empty(const struct perf_cpu_map *map);
-LIBPERF_API struct perf_cpu perf_cpu_map__max(struct perf_cpu_map *map);
+LIBPERF_API struct perf_cpu perf_cpu_map__max(const struct perf_cpu_map *map);
 LIBPERF_API bool perf_cpu_map__has(const struct perf_cpu_map *map, struct perf_cpu cpu);
 
 #define perf_cpu_map__for_each_cpu(cpu, idx, cpus)             \
index 556bb06..93bf93a 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/types.h>
 #include <linux/limits.h>
 #include <linux/bpf.h>
+#include <linux/compiler.h>
 #include <sys/types.h> /* pid_t */
 
 #define event_contains(obj, mem) ((obj).header.size > offsetof(typeof(obj), mem))
@@ -76,7 +77,7 @@ struct perf_record_lost_samples {
 };
 
 /*
- * PERF_FORMAT_ENABLED | PERF_FORMAT_RUNNING | PERF_FORMAT_ID
+ * PERF_FORMAT_ENABLED | PERF_FORMAT_RUNNING | PERF_FORMAT_ID | PERF_FORMAT_LOST
  */
 struct perf_record_read {
        struct perf_event_header header;
@@ -85,6 +86,7 @@ struct perf_record_read {
        __u64                    time_enabled;
        __u64                    time_running;
        __u64                    id;
+       __u64                    lost;
 };
 
 struct perf_record_throttle {
@@ -153,22 +155,60 @@ enum {
        PERF_CPU_MAP__MASK = 1,
 };
 
+/*
+ * Array encoding of a perf_cpu_map where nr is the number of entries in cpu[]
+ * and each entry is a value for a CPU in the map.
+ */
 struct cpu_map_entries {
        __u16                    nr;
        __u16                    cpu[];
 };
 
-struct perf_record_record_cpu_map {
+/* Bitmap encoding of a perf_cpu_map where bitmap entries are 32-bit. */
+struct perf_record_mask_cpu_map32 {
+       /* Number of mask values. */
+       __u16                    nr;
+       /* Constant 4. */
+       __u16                    long_size;
+       /* Bitmap data. */
+       __u32                    mask[];
+};
+
+/* Bitmap encoding of a perf_cpu_map where bitmap entries are 64-bit. */
+struct perf_record_mask_cpu_map64 {
+       /* Number of mask values. */
        __u16                    nr;
+       /* Constant 8. */
        __u16                    long_size;
-       unsigned long            mask[];
+       /* Legacy padding. */
+       char                     __pad[4];
+       /* Bitmap data. */
+       __u64                    mask[];
 };
 
-struct perf_record_cpu_map_data {
+/*
+ * 'struct perf_record_cpu_map_data' is packed as unfortunately an earlier
+ * version had unaligned data and we wish to retain file format compatibility.
+ * -irogers
+ */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpacked"
+#pragma GCC diagnostic ignored "-Wattributes"
+
+struct __packed perf_record_cpu_map_data {
        __u16                    type;
-       char                     data[];
+       union {
+               /* Used when type == PERF_CPU_MAP__CPUS. */
+               struct cpu_map_entries cpus_data;
+               /* Used when type == PERF_CPU_MAP__MASK and long_size == 4. */
+               struct perf_record_mask_cpu_map32 mask32_data;
+               /* Used when type == PERF_CPU_MAP__MASK and long_size == 8. */
+               struct perf_record_mask_cpu_map64 mask64_data;
+       };
 };
 
+#pragma GCC diagnostic pop
+
 struct perf_record_cpu_map {
        struct perf_event_header         header;
        struct perf_record_cpu_map_data  data;
index 699c0ed..6f92204 100644 (file)
@@ -18,8 +18,10 @@ struct perf_counts_values {
                        uint64_t val;
                        uint64_t ena;
                        uint64_t run;
+                       uint64_t id;
+                       uint64_t lost;
                };
-               uint64_t values[3];
+               uint64_t values[5];
        };
 };
 
index 89be89a..a11fc51 100644 (file)
@@ -1,10 +1,13 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <stdarg.h>
 #include <stdio.h>
+#include <string.h>
 #include <linux/perf_event.h>
+#include <linux/kernel.h>
 #include <perf/cpumap.h>
 #include <perf/threadmap.h>
 #include <perf/evsel.h>
+#include <internal/evsel.h>
 #include <internal/tests.h>
 #include "tests.h"
 
@@ -189,6 +192,163 @@ static int test_stat_user_read(int event)
        return 0;
 }
 
+static int test_stat_read_format_single(struct perf_event_attr *attr, struct perf_thread_map *threads)
+{
+       struct perf_evsel *evsel;
+       struct perf_counts_values counts;
+       volatile int count = 0x100000;
+       int err;
+
+       evsel = perf_evsel__new(attr);
+       __T("failed to create evsel", evsel);
+
+       /* skip old kernels that don't support the format */
+       err = perf_evsel__open(evsel, NULL, threads);
+       if (err < 0)
+               return 0;
+
+       while (count--) ;
+
+       memset(&counts, -1, sizeof(counts));
+       perf_evsel__read(evsel, 0, 0, &counts);
+
+       __T("failed to read value", counts.val);
+       if (attr->read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
+               __T("failed to read TOTAL_TIME_ENABLED", counts.ena);
+       if (attr->read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
+               __T("failed to read TOTAL_TIME_RUNNING", counts.run);
+       if (attr->read_format & PERF_FORMAT_ID)
+               __T("failed to read ID", counts.id);
+       if (attr->read_format & PERF_FORMAT_LOST)
+               __T("failed to read LOST", counts.lost == 0);
+
+       perf_evsel__close(evsel);
+       perf_evsel__delete(evsel);
+       return 0;
+}
+
+static int test_stat_read_format_group(struct perf_event_attr *attr, struct perf_thread_map *threads)
+{
+       struct perf_evsel *leader, *member;
+       struct perf_counts_values counts;
+       volatile int count = 0x100000;
+       int err;
+
+       attr->read_format |= PERF_FORMAT_GROUP;
+       leader = perf_evsel__new(attr);
+       __T("failed to create leader", leader);
+
+       attr->read_format &= ~PERF_FORMAT_GROUP;
+       member = perf_evsel__new(attr);
+       __T("failed to create member", member);
+
+       member->leader = leader;
+       leader->nr_members = 2;
+
+       /* skip old kernels that don't support the format */
+       err = perf_evsel__open(leader, NULL, threads);
+       if (err < 0)
+               return 0;
+       err = perf_evsel__open(member, NULL, threads);
+       if (err < 0)
+               return 0;
+
+       while (count--) ;
+
+       memset(&counts, -1, sizeof(counts));
+       perf_evsel__read(leader, 0, 0, &counts);
+
+       __T("failed to read leader value", counts.val);
+       if (attr->read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
+               __T("failed to read leader TOTAL_TIME_ENABLED", counts.ena);
+       if (attr->read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
+               __T("failed to read leader TOTAL_TIME_RUNNING", counts.run);
+       if (attr->read_format & PERF_FORMAT_ID)
+               __T("failed to read leader ID", counts.id);
+       if (attr->read_format & PERF_FORMAT_LOST)
+               __T("failed to read leader LOST", counts.lost == 0);
+
+       memset(&counts, -1, sizeof(counts));
+       perf_evsel__read(member, 0, 0, &counts);
+
+       __T("failed to read member value", counts.val);
+       if (attr->read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
+               __T("failed to read member TOTAL_TIME_ENABLED", counts.ena);
+       if (attr->read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
+               __T("failed to read member TOTAL_TIME_RUNNING", counts.run);
+       if (attr->read_format & PERF_FORMAT_ID)
+               __T("failed to read member ID", counts.id);
+       if (attr->read_format & PERF_FORMAT_LOST)
+               __T("failed to read member LOST", counts.lost == 0);
+
+       perf_evsel__close(member);
+       perf_evsel__close(leader);
+       perf_evsel__delete(member);
+       perf_evsel__delete(leader);
+       return 0;
+}
+
+static int test_stat_read_format(void)
+{
+       struct perf_thread_map *threads;
+       struct perf_event_attr attr = {
+               .type   = PERF_TYPE_SOFTWARE,
+               .config = PERF_COUNT_SW_TASK_CLOCK,
+       };
+       int err, i;
+
+#define FMT(_fmt)  PERF_FORMAT_ ## _fmt
+#define FMT_TIME  (FMT(TOTAL_TIME_ENABLED) | FMT(TOTAL_TIME_RUNNING))
+
+       uint64_t test_formats [] = {
+               0,
+               FMT_TIME,
+               FMT(ID),
+               FMT(LOST),
+               FMT_TIME | FMT(ID),
+               FMT_TIME | FMT(LOST),
+               FMT_TIME | FMT(ID) | FMT(LOST),
+               FMT(ID) | FMT(LOST),
+       };
+
+#undef FMT
+#undef FMT_TIME
+
+       threads = perf_thread_map__new_dummy();
+       __T("failed to create threads", threads);
+
+       perf_thread_map__set_pid(threads, 0, 0);
+
+       for (i = 0; i < (int)ARRAY_SIZE(test_formats); i++) {
+               attr.read_format = test_formats[i];
+               __T_VERBOSE("testing single read with read_format: %lx\n",
+                           (unsigned long)test_formats[i]);
+
+               err = test_stat_read_format_single(&attr, threads);
+               __T("failed to read single format", err == 0);
+       }
+
+       perf_thread_map__put(threads);
+
+       threads = perf_thread_map__new_array(2, NULL);
+       __T("failed to create threads", threads);
+
+       perf_thread_map__set_pid(threads, 0, 0);
+       perf_thread_map__set_pid(threads, 1, 0);
+
+       for (i = 0; i < (int)ARRAY_SIZE(test_formats); i++) {
+               attr.read_format = test_formats[i];
+               __T_VERBOSE("testing group read with read_format: %lx\n",
+                           (unsigned long)test_formats[i]);
+
+               err = test_stat_read_format_group(&attr, threads);
+               __T("failed to read group format", err == 0);
+       }
+
+       perf_thread_map__put(threads);
+       return 0;
+}
+
 int test_evsel(int argc, char **argv)
 {
        __T_START;
@@ -200,6 +360,7 @@ int test_evsel(int argc, char **argv)
        test_stat_thread_enable();
        test_stat_user_read(PERF_COUNT_HW_INSTRUCTIONS);
        test_stat_user_read(PERF_COUNT_HW_CPU_CYCLES);
+       test_stat_read_format();
 
        __T_END;
        return tests_failed == 0 ? 0 : -1;
index 0cec74d..e55fdf9 100644 (file)
@@ -162,32 +162,34 @@ static bool __dead_end_function(struct objtool_file *file, struct symbol *func,
 
        /*
         * Unfortunately these have to be hard coded because the noreturn
-        * attribute isn't provided in ELF data.
+        * attribute isn't provided in ELF data. Keep 'em sorted.
         */
        static const char * const global_noreturns[] = {
+               "__invalid_creds",
+               "__module_put_and_kthread_exit",
+               "__reiserfs_panic",
                "__stack_chk_fail",
-               "panic",
+               "__ubsan_handle_builtin_unreachable",
+               "cpu_bringup_and_idle",
+               "cpu_startup_entry",
                "do_exit",
+               "do_group_exit",
                "do_task_dead",
-               "kthread_exit",
-               "make_task_dead",
-               "__module_put_and_kthread_exit",
+               "ex_handler_msr_mce",
+               "fortify_panic",
                "kthread_complete_and_exit",
-               "__reiserfs_panic",
+               "kthread_exit",
+               "kunit_try_catch_throw",
                "lbug_with_loc",
-               "fortify_panic",
-               "usercopy_abort",
                "machine_real_restart",
+               "make_task_dead",
+               "panic",
                "rewind_stack_and_make_dead",
-               "kunit_try_catch_throw",
-               "xen_start_kernel",
-               "cpu_bringup_and_idle",
-               "do_group_exit",
+               "sev_es_terminate",
+               "snp_abort",
                "stop_this_cpu",
-               "__invalid_creds",
-               "cpu_startup_entry",
-               "__ubsan_handle_builtin_unreachable",
-               "ex_handler_msr_mce",
+               "usercopy_abort",
+               "xen_start_kernel",
        };
 
        if (!func)
@@ -4096,7 +4098,8 @@ static int validate_ibt(struct objtool_file *file)
                 * These sections can reference text addresses, but not with
                 * the intent to indirect branch to them.
                 */
-               if (!strncmp(sec->name, ".discard", 8)                  ||
+               if ((!strncmp(sec->name, ".discard", 8) &&
+                    strcmp(sec->name, ".discard.ibt_endbr_noseal"))    ||
                    !strncmp(sec->name, ".debug", 6)                    ||
                    !strcmp(sec->name, ".altinstructions")              ||
                    !strcmp(sec->name, ".ibt_endbr_seal")               ||
index c930209..e7a776a 100644 (file)
@@ -21,11 +21,6 @@ cat /sys/devices/cpu_atom/cpus
 
 It indicates cpu0-cpu15 are core cpus and cpu16-cpu23 are atom cpus.
 
-Quickstart
-
-List hybrid event
------------------
-
 As before, use perf-list to list the symbolic event.
 
 perf list
@@ -40,7 +35,6 @@ the event is belong to. Same event name but with different pmu can
 be supported.
 
 Enable hybrid event with a specific pmu
----------------------------------------
 
 To enable a core only event or atom only event, following syntax is supported:
 
@@ -53,7 +47,6 @@ For example, count the 'cycles' event on core cpus.
        perf stat -e cpu_core/cycles/
 
 Create two events for one hardware event automatically
-------------------------------------------------------
 
 When creating one event and the event is available on both atom and core,
 two events are created automatically. One is for atom, the other is for
@@ -132,7 +125,6 @@ For perf-stat result, it displays two events:
 The first 'cycles' is core event, the second 'cycles' is atom event.
 
 Thread mode example:
---------------------
 
 perf-stat reports the scaled counts for hybrid event and with a percentage
 displayed. The percentage is the event's running time/enabling time.
@@ -176,14 +168,12 @@ perf_event_attr:
        604,097,080      cpu_atom/cycles/                                              (99.57%)
 
 perf-record:
-------------
 
 If there is no '-e' specified in perf record, on hybrid platform,
 it creates two default 'cycles' and adds them to event list. One
 is for core, the other is for atom.
 
 perf-stat:
-----------
 
 If there is no '-e' specified in perf stat, on hybrid platform,
 besides of software events, following events are created and
index 099817e..0228efc 100644 (file)
@@ -397,6 +397,9 @@ following filters are defined:
        - abort_tx: only when the target is a hardware transaction abort
        - cond: conditional branches
        - save_type: save branch type during sampling in case binary is not available later
+                    For the platforms with Intel Arch LBR support (12th-Gen+ client or
+                    4th-Gen Xeon+ server), the save branch type is unconditionally enabled
+                    when the taken branch stack sampling is enabled.
 
 +
 The option requires at least one branch type among any, any_call, any_ret, ind_call, cond.
@@ -757,8 +760,6 @@ events in data directory files. Option specified with no or empty value
 defaults to CPU layout. Masks defined or provided by the option value are
 filtered through the mask provided by -C option.
 
-include::intel-hybrid.txt[]
-
 --debuginfod[=URLs]::
        Specify debuginfod URL to be used when cacheing perf.data binaries,
        it follows the same syntax as the DEBUGINFOD_URLS variable, like:
@@ -778,6 +779,8 @@ include::intel-hybrid.txt[]
        only, as of now.  So the applications built without the frame
        pointer might see bogus addresses.
 
+include::intel-hybrid.txt[]
+
 SEE ALSO
 --------
 linkperf:perf-stat[1], linkperf:perf-list[1], linkperf:perf-intel-pt[1]
index 0661a1c..2171f02 100644 (file)
@@ -265,7 +265,7 @@ endif
 # defined. get-executable-or-default fails with an error if the first argument is supplied but
 # doesn't exist.
 override PYTHON_CONFIG := $(call get-executable-or-default,PYTHON_CONFIG,$(PYTHON_AUTO))
-override PYTHON := $(call get-executable-or-default,PYTHON,$(subst -config,,$(PYTHON_AUTO)))
+override PYTHON := $(call get-executable-or-default,PYTHON,$(subst -config,,$(PYTHON_CONFIG)))
 
 grep-libs  = $(filter -l%,$(1))
 strip-libs  = $(filter-out -l%,$(1))
index e5921b3..bd94788 100644 (file)
@@ -954,11 +954,11 @@ ifndef NO_LIBBPF
        $(call QUIET_INSTALL, bpf-headers) \
                $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perf_include_instdir_SQ)/bpf'; \
                $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perf_include_instdir_SQ)/bpf/linux'; \
-               $(INSTALL) include/bpf/*.h -t '$(DESTDIR_SQ)$(perf_include_instdir_SQ)/bpf'; \
-               $(INSTALL) include/bpf/linux/*.h -t '$(DESTDIR_SQ)$(perf_include_instdir_SQ)/bpf/linux'
+               $(INSTALL) include/bpf/*.h -m 644 -t '$(DESTDIR_SQ)$(perf_include_instdir_SQ)/bpf'; \
+               $(INSTALL) include/bpf/linux/*.h -m 644 -t '$(DESTDIR_SQ)$(perf_include_instdir_SQ)/bpf/linux'
        $(call QUIET_INSTALL, bpf-examples) \
                $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perf_examples_instdir_SQ)/bpf'; \
-               $(INSTALL) examples/bpf/*.c -t '$(DESTDIR_SQ)$(perf_examples_instdir_SQ)/bpf'
+               $(INSTALL) examples/bpf/*.c -m 644 -t '$(DESTDIR_SQ)$(perf_examples_instdir_SQ)/bpf'
 endif
        $(call QUIET_INSTALL, perf-archive) \
                $(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
@@ -967,13 +967,13 @@ endif
 ifndef NO_LIBAUDIT
        $(call QUIET_INSTALL, strace/groups) \
                $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(STRACE_GROUPS_INSTDIR_SQ)'; \
-               $(INSTALL) trace/strace/groups/* -t '$(DESTDIR_SQ)$(STRACE_GROUPS_INSTDIR_SQ)'
+               $(INSTALL) trace/strace/groups/* -m 644 -t '$(DESTDIR_SQ)$(STRACE_GROUPS_INSTDIR_SQ)'
 endif
 ifndef NO_LIBPERL
        $(call QUIET_INSTALL, perl-scripts) \
                $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'; \
-               $(INSTALL) scripts/perl/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'; \
-               $(INSTALL) scripts/perl/*.pl -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl'; \
+               $(INSTALL) scripts/perl/Perf-Trace-Util/lib/Perf/Trace/* -m 644 -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'; \
+               $(INSTALL) scripts/perl/*.pl -m 644 -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl'; \
                $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'; \
                $(INSTALL) scripts/perl/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
 endif
@@ -990,23 +990,23 @@ endif
                $(INSTALL) $(DLFILTERS) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/dlfilters';
        $(call QUIET_INSTALL, perf_completion-script) \
                $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d'; \
-               $(INSTALL) perf-completion.sh '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d/perf'
+               $(INSTALL) perf-completion.sh -m 644 '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d/perf'
        $(call QUIET_INSTALL, perf-tip) \
                $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(tip_instdir_SQ)'; \
-               $(INSTALL) Documentation/tips.txt -t '$(DESTDIR_SQ)$(tip_instdir_SQ)'
+               $(INSTALL) Documentation/tips.txt -m 644 -t '$(DESTDIR_SQ)$(tip_instdir_SQ)'
 
 install-tests: all install-gtk
        $(call QUIET_INSTALL, tests) \
                $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \
-               $(INSTALL) tests/attr.py '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \
+               $(INSTALL) tests/attr.py -m 644 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \
                $(INSTALL) tests/pe-file.exe* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \
                $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'; \
-               $(INSTALL) tests/attr/* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'; \
+               $(INSTALL) tests/attr/* -m 644 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'; \
                $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell'; \
                $(INSTALL) tests/shell/*.sh '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell'; \
                $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell/lib'; \
-               $(INSTALL) tests/shell/lib/*.sh '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell/lib'; \
-               $(INSTALL) tests/shell/lib/*.py '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell/lib'
+               $(INSTALL) tests/shell/lib/*.sh -m 644 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell/lib'; \
+               $(INSTALL) tests/shell/lib/*.py -m 644 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell/lib'
 
 install-bin: install-tools install-tests install-traceevent-plugins
 
index 653e13b..438fc22 100644 (file)
@@ -146,15 +146,15 @@ static void *c2c_he_zalloc(size_t size)
 
        c2c_he->cpuset = bitmap_zalloc(c2c.cpus_cnt);
        if (!c2c_he->cpuset)
-               return NULL;
+               goto out_free;
 
        c2c_he->nodeset = bitmap_zalloc(c2c.nodes_cnt);
        if (!c2c_he->nodeset)
-               return NULL;
+               goto out_free;
 
        c2c_he->node_stats = zalloc(c2c.nodes_cnt * sizeof(*c2c_he->node_stats));
        if (!c2c_he->node_stats)
-               return NULL;
+               goto out_free;
 
        init_stats(&c2c_he->cstats.lcl_hitm);
        init_stats(&c2c_he->cstats.rmt_hitm);
@@ -163,6 +163,12 @@ static void *c2c_he_zalloc(size_t size)
        init_stats(&c2c_he->cstats.load);
 
        return &c2c_he->he;
+
+out_free:
+       free(c2c_he->nodeset);
+       free(c2c_he->cpuset);
+       free(c2c_he);
+       return NULL;
 }
 
 static void c2c_he_free(void *he)
index dd11d34..ea40ae5 100644 (file)
@@ -1874,8 +1874,7 @@ int cmd_lock(int argc, const char **argv)
                NULL
        };
        const char *const lock_subcommands[] = { "record", "report", "script",
-                                                "info", "contention",
-                                                "contention", NULL };
+                                                "info", "contention", NULL };
        const char *lock_usage[] = {
                NULL,
                NULL
index 4713f0f..0f711f8 100644 (file)
@@ -1906,14 +1906,18 @@ static int record__synthesize(struct record *rec, bool tail)
 
        err = perf_event__synthesize_bpf_events(session, process_synthesized_event,
                                                machine, opts);
-       if (err < 0)
+       if (err < 0) {
                pr_warning("Couldn't synthesize bpf events.\n");
+               err = 0;
+       }
 
        if (rec->opts.synth & PERF_SYNTH_CGROUP) {
                err = perf_event__synthesize_cgroups(tool, process_synthesized_event,
                                                     machine);
-               if (err < 0)
+               if (err < 0) {
                        pr_warning("Couldn't synthesize cgroup events.\n");
+                       err = 0;
+               }
        }
 
        if (rec->opts.nr_threads_synthesize > 1) {
@@ -3358,16 +3362,24 @@ static struct option __record_options[] = {
 
 struct option *record_options = __record_options;
 
-static void record__mmap_cpu_mask_init(struct mmap_cpu_mask *mask, struct perf_cpu_map *cpus)
+static int record__mmap_cpu_mask_init(struct mmap_cpu_mask *mask, struct perf_cpu_map *cpus)
 {
        struct perf_cpu cpu;
        int idx;
 
        if (cpu_map__is_dummy(cpus))
-               return;
+               return 0;
 
-       perf_cpu_map__for_each_cpu(cpu, idx, cpus)
+       perf_cpu_map__for_each_cpu(cpu, idx, cpus) {
+               if (cpu.cpu == -1)
+                       continue;
+               /* Return ENODEV is input cpu is greater than max cpu */
+               if ((unsigned long)cpu.cpu > mask->nbits)
+                       return -ENODEV;
                set_bit(cpu.cpu, mask->bits);
+       }
+
+       return 0;
 }
 
 static int record__mmap_cpu_mask_init_spec(struct mmap_cpu_mask *mask, const char *mask_spec)
@@ -3379,7 +3391,9 @@ static int record__mmap_cpu_mask_init_spec(struct mmap_cpu_mask *mask, const cha
                return -ENOMEM;
 
        bitmap_zero(mask->bits, mask->nbits);
-       record__mmap_cpu_mask_init(mask, cpus);
+       if (record__mmap_cpu_mask_init(mask, cpus))
+               return -ENODEV;
+
        perf_cpu_map__put(cpus);
 
        return 0;
@@ -3461,7 +3475,12 @@ static int record__init_thread_masks_spec(struct record *rec, struct perf_cpu_ma
                pr_err("Failed to allocate CPUs mask\n");
                return ret;
        }
-       record__mmap_cpu_mask_init(&cpus_mask, cpus);
+
+       ret = record__mmap_cpu_mask_init(&cpus_mask, cpus);
+       if (ret) {
+               pr_err("Failed to init cpu mask\n");
+               goto out_free_cpu_mask;
+       }
 
        ret = record__thread_mask_alloc(&full_mask, cpu__max_cpu().cpu);
        if (ret) {
@@ -3702,7 +3721,8 @@ static int record__init_thread_default_masks(struct record *rec, struct perf_cpu
        if (ret)
                return ret;
 
-       record__mmap_cpu_mask_init(&rec->thread_masks->maps, cpus);
+       if (record__mmap_cpu_mask_init(&rec->thread_masks->maps, cpus))
+               return -ENODEV;
 
        rec->nr_threads = 1;
 
index 2f6cd1b..a5cf243 100644 (file)
@@ -3355,7 +3355,8 @@ static bool schedstat_events_exposed(void)
 static int __cmd_record(int argc, const char **argv)
 {
        unsigned int rec_argc, i, j;
-       const char **rec_argv;
+       char **rec_argv;
+       const char **rec_argv_copy;
        const char * const record_args[] = {
                "record",
                "-a",
@@ -3384,6 +3385,7 @@ static int __cmd_record(int argc, const char **argv)
                ARRAY_SIZE(schedstat_args) : 0;
 
        struct tep_event *waking_event;
+       int ret;
 
        /*
         * +2 for either "-e", "sched:sched_wakeup" or
@@ -3391,14 +3393,18 @@ static int __cmd_record(int argc, const char **argv)
         */
        rec_argc = ARRAY_SIZE(record_args) + 2 + schedstat_argc + argc - 1;
        rec_argv = calloc(rec_argc + 1, sizeof(char *));
-
        if (rec_argv == NULL)
                return -ENOMEM;
+       rec_argv_copy = calloc(rec_argc + 1, sizeof(char *));
+       if (rec_argv_copy == NULL) {
+               free(rec_argv);
+               return -ENOMEM;
+       }
 
        for (i = 0; i < ARRAY_SIZE(record_args); i++)
                rec_argv[i] = strdup(record_args[i]);
 
-       rec_argv[i++] = "-e";
+       rec_argv[i++] = strdup("-e");
        waking_event = trace_event__tp_format("sched", "sched_waking");
        if (!IS_ERR(waking_event))
                rec_argv[i++] = strdup("sched:sched_waking");
@@ -3409,11 +3415,19 @@ static int __cmd_record(int argc, const char **argv)
                rec_argv[i++] = strdup(schedstat_args[j]);
 
        for (j = 1; j < (unsigned int)argc; j++, i++)
-               rec_argv[i] = argv[j];
+               rec_argv[i] = strdup(argv[j]);
 
        BUG_ON(i != rec_argc);
 
-       return cmd_record(i, rec_argv);
+       memcpy(rec_argv_copy, rec_argv, sizeof(char *) * rec_argc);
+       ret = cmd_record(rec_argc, rec_argv_copy);
+
+       for (i = 0; i < rec_argc; i++)
+               free(rec_argv[i]);
+       free(rec_argv);
+       free(rec_argv_copy);
+
+       return ret;
 }
 
 int cmd_sched(int argc, const char **argv)
index 13580a9..029b433 100644 (file)
@@ -445,6 +445,9 @@ static int evsel__check_attr(struct evsel *evsel, struct perf_session *session)
        struct perf_event_attr *attr = &evsel->core.attr;
        bool allow_user_set;
 
+       if (evsel__is_dummy_event(evsel))
+               return 0;
+
        if (perf_header__has_feat(&session->header, HEADER_STAT))
                return 0;
 
@@ -566,6 +569,8 @@ static struct evsel *find_first_output_type(struct evlist *evlist,
        struct evsel *evsel;
 
        evlist__for_each_entry(evlist, evsel) {
+               if (evsel__is_dummy_event(evsel))
+                       continue;
                if (output_type(evsel->core.attr.type) == (int)type)
                        return evsel;
        }
index 7fb81a4..0b4a62e 100644 (file)
@@ -826,6 +826,7 @@ static int __run_perf_stat(int argc, const char **argv, int run_idx)
        }
 
        evlist__for_each_entry(evsel_list, counter) {
+               counter->reset_group = false;
                if (bpf_counter__load(counter, &target))
                        return -1;
                if (!evsel__is_bpf(counter))
@@ -1931,6 +1932,9 @@ setup_metrics:
                free(str);
        }
 
+       if (!stat_config.topdown_level)
+               stat_config.topdown_level = TOPDOWN_MAX_LEVEL;
+
        if (!evsel_list->core.nr_entries) {
                if (target__has_cpu(&target))
                        default_attrs0[0].config = PERF_COUNT_SW_CPU_CLOCK;
@@ -1947,8 +1951,6 @@ setup_metrics:
                }
                if (evlist__add_default_attrs(evsel_list, default_attrs1) < 0)
                        return -1;
-
-               stat_config.topdown_level = TOPDOWN_MAX_LEVEL;
                /* Platform specific attrs */
                if (evlist__add_default_attrs(evsel_list, default_null_attrs) < 0)
                        return -1;
index 9eccc97..6d47298 100644 (file)
@@ -98,9 +98,9 @@ int filter_event_early(void *data, const struct perf_dlfilter_sample *sample, vo
 static void print_vals(__u64 cycles, __u64 delta)
 {
        if (delta)
-               printf("%10llu %10llu ", cycles, delta);
+               printf("%10llu %10llu ", (unsigned long long)cycles, (unsigned long long)delta);
        else
-               printf("%10llu %10s ", cycles, "");
+               printf("%10llu %10s ", (unsigned long long)cycles, "");
 }
 
 int filter_event(void *data, const struct perf_dlfilter_sample *sample, void *ctx)
index f94929e..7ea150c 100644 (file)
@@ -17,21 +17,23 @@ static int process_event_mask(struct perf_tool *tool __maybe_unused,
                         struct machine *machine __maybe_unused)
 {
        struct perf_record_cpu_map *map_event = &event->cpu_map;
-       struct perf_record_record_cpu_map *mask;
        struct perf_record_cpu_map_data *data;
        struct perf_cpu_map *map;
        int i;
+       unsigned int long_size;
 
        data = &map_event->data;
 
        TEST_ASSERT_VAL("wrong type", data->type == PERF_CPU_MAP__MASK);
 
-       mask = (struct perf_record_record_cpu_map *)data->data;
+       long_size = data->mask32_data.long_size;
 
-       TEST_ASSERT_VAL("wrong nr",   mask->nr == 1);
+       TEST_ASSERT_VAL("wrong long_size", long_size == 4 || long_size == 8);
+
+       TEST_ASSERT_VAL("wrong nr",   data->mask32_data.nr == 1);
 
        for (i = 0; i < 20; i++) {
-               TEST_ASSERT_VAL("wrong cpu", test_bit(i, mask->mask));
+               TEST_ASSERT_VAL("wrong cpu", perf_record_cpu_map_data__test_bit(i, data));
        }
 
        map = cpu_map__new_data(data);
@@ -51,7 +53,6 @@ static int process_event_cpus(struct perf_tool *tool __maybe_unused,
                         struct machine *machine __maybe_unused)
 {
        struct perf_record_cpu_map *map_event = &event->cpu_map;
-       struct cpu_map_entries *cpus;
        struct perf_record_cpu_map_data *data;
        struct perf_cpu_map *map;
 
@@ -59,11 +60,9 @@ static int process_event_cpus(struct perf_tool *tool __maybe_unused,
 
        TEST_ASSERT_VAL("wrong type", data->type == PERF_CPU_MAP__CPUS);
 
-       cpus = (struct cpu_map_entries *)data->data;
-
-       TEST_ASSERT_VAL("wrong nr",   cpus->nr == 2);
-       TEST_ASSERT_VAL("wrong cpu",  cpus->cpu[0] == 1);
-       TEST_ASSERT_VAL("wrong cpu",  cpus->cpu[1] == 256);
+       TEST_ASSERT_VAL("wrong nr",   data->cpus_data.nr == 2);
+       TEST_ASSERT_VAL("wrong cpu",  data->cpus_data.cpu[0] == 1);
+       TEST_ASSERT_VAL("wrong cpu",  data->cpus_data.cpu[1] == 256);
 
        map = cpu_map__new_data(data);
        TEST_ASSERT_VAL("wrong nr",  perf_cpu_map__nr(map) == 2);
index 07f2411..20930dd 100644 (file)
@@ -86,10 +86,15 @@ static bool samples_same(const struct perf_sample *s1,
                        COMP(read.time_running);
                /* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */
                if (read_format & PERF_FORMAT_GROUP) {
-                       for (i = 0; i < s1->read.group.nr; i++)
-                               MCOMP(read.group.values[i]);
+                       for (i = 0; i < s1->read.group.nr; i++) {
+                               /* FIXME: check values without LOST */
+                               if (read_format & PERF_FORMAT_LOST)
+                                       MCOMP(read.group.values[i]);
+                       }
                } else {
                        COMP(read.one.id);
+                       if (read_format & PERF_FORMAT_LOST)
+                               COMP(read.one.lost);
                }
        }
 
@@ -263,7 +268,7 @@ static int do_test(u64 sample_type, u64 sample_regs, u64 read_format)
                        .data   = (void *)aux_data,
                },
        };
-       struct sample_read_value values[] = {{1, 5}, {9, 3}, {2, 7}, {6, 4},};
+       struct sample_read_value values[] = {{1, 5, 0}, {9, 3, 0}, {2, 7, 0}, {6, 4, 1},};
        struct perf_sample sample_out, sample_out_endian;
        size_t i, sz, bufsz;
        int err, ret = -1;
@@ -286,6 +291,7 @@ static int do_test(u64 sample_type, u64 sample_regs, u64 read_format)
        } else {
                sample.read.one.value = 0x08789faeb786aa87ULL;
                sample.read.one.id    = 99;
+               sample.read.one.lost  = 1;
        }
 
        sz = perf_event__sample_event_size(&sample, sample_type, read_format);
@@ -370,7 +376,7 @@ out_free:
  */
 static int test__sample_parsing(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
 {
-       const u64 rf[] = {4, 5, 6, 7, 12, 13, 14, 15};
+       const u64 rf[] = {4, 5, 6, 7, 12, 13, 14, 15, 20, 21, 22, 28, 29, 30, 31};
        u64 sample_type;
        u64 sample_regs;
        size_t i;
index 9313ef2..26a51b4 100755 (executable)
@@ -28,6 +28,24 @@ test_stat_record_report() {
   echo "stat record and report test [Success]"
 }
 
+test_stat_repeat_weak_groups() {
+  echo "stat repeat weak groups test"
+  if ! perf stat -e '{cycles,cycles,cycles,cycles,cycles,cycles,cycles,cycles,cycles,cycles}' \
+     true 2>&1 | grep -q 'seconds time elapsed'
+  then
+    echo "stat repeat weak groups test [Skipped event parsing failed]"
+    return
+  fi
+  if ! perf stat -r2 -e '{cycles,cycles,cycles,cycles,cycles,cycles,cycles,cycles,cycles,cycles}:W' \
+    true > /dev/null 2>&1
+  then
+    echo "stat repeat weak groups test [Failed]"
+    err=1
+    return
+  fi
+  echo "stat repeat weak groups test [Success]"
+}
+
 test_topdown_groups() {
   # Topdown events must be grouped with the slots event first. Test that
   # parse-events reorders this.
@@ -75,6 +93,7 @@ test_topdown_weak_groups() {
 
 test_default_stat
 test_stat_record_report
+test_stat_repeat_weak_groups
 test_topdown_groups
 test_topdown_weak_groups
 exit $err
diff --git a/tools/perf/tests/shell/stat_bpf_counters_cgrp.sh b/tools/perf/tests/shell/stat_bpf_counters_cgrp.sh
new file mode 100755 (executable)
index 0000000..d724855
--- /dev/null
@@ -0,0 +1,83 @@
+#!/bin/sh
+# perf stat --bpf-counters --for-each-cgroup test
+# SPDX-License-Identifier: GPL-2.0
+
+set -e
+
+test_cgroups=
+if [ "$1" = "-v" ]; then
+       verbose="1"
+fi
+
+# skip if --bpf-counters --for-each-cgroup is not supported
+check_bpf_counter()
+{
+       if ! perf stat -a --bpf-counters --for-each-cgroup / true > /dev/null 2>&1; then
+               if [ "${verbose}" = "1" ]; then
+                       echo "Skipping: --bpf-counters --for-each-cgroup not supported"
+                       perf --no-pager stat -a --bpf-counters --for-each-cgroup / true || true
+               fi
+               exit 2
+       fi
+}
+
+# find two cgroups to measure
+find_cgroups()
+{
+       # try usual systemd slices first
+       if [ -d /sys/fs/cgroup/system.slice -a -d /sys/fs/cgroup/user.slice ]; then
+               test_cgroups="system.slice,user.slice"
+               return
+       fi
+
+       # try root and self cgroups
+       local self_cgrp=$(grep perf_event /proc/self/cgroup | cut -d: -f3)
+       if [ -z ${self_cgrp} ]; then
+               # cgroup v2 doesn't specify perf_event
+               self_cgrp=$(grep ^0: /proc/self/cgroup | cut -d: -f3)
+       fi
+
+       if [ -z ${self_cgrp} ]; then
+               test_cgroups="/"
+       else
+               test_cgroups="/,${self_cgrp}"
+       fi
+}
+
+# As cgroup events are cpu-wide, we cannot simply compare the result.
+# Just check if it runs without failure and has non-zero results.
+check_system_wide_counted()
+{
+       local output
+
+       output=$(perf stat -a --bpf-counters --for-each-cgroup ${test_cgroups} -e cpu-clock -x, sleep 1  2>&1)
+       if echo ${output} | grep -q -F "<not "; then
+               echo "Some system-wide events are not counted"
+               if [ "${verbose}" = "1" ]; then
+                       echo ${output}
+               fi
+               exit 1
+       fi
+}
+
+check_cpu_list_counted()
+{
+       local output
+
+       output=$(perf stat -C 1 --bpf-counters --for-each-cgroup ${test_cgroups} -e cpu-clock -x, taskset -c 1 sleep 1  2>&1)
+       if echo ${output} | grep -q -F "<not "; then
+               echo "Some CPU events are not counted"
+               if [ "${verbose}" = "1" ]; then
+                       echo ${output}
+               fi
+               exit 1
+       fi
+}
+
+check_bpf_counter
+find_cgroups
+
+check_system_wide_counted
+check_cpu_list_counted
+
+exit 0
index 9d4c451..56455da 100644 (file)
@@ -2,7 +2,9 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <errno.h>
 #include <sys/ioctl.h>
+#include <linux/compiler.h>
 #include <linux/hw_breakpoint.h>
 #include <linux/kernel.h>
 #include "tests.h"
@@ -137,8 +139,7 @@ static int test__wp_rw(struct test_suite *test __maybe_unused,
 #endif
 }
 
-static int test__wp_modify(struct test_suite *test __maybe_unused,
-                          int subtest __maybe_unused)
+static int test__wp_modify(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
 {
 #if defined(__s390x__)
        return TEST_SKIP;
@@ -160,6 +161,11 @@ static int test__wp_modify(struct test_suite *test __maybe_unused,
        new_attr.disabled = 1;
        ret = ioctl(fd, PERF_EVENT_IOC_MODIFY_ATTRIBUTES, &new_attr);
        if (ret < 0) {
+               if (errno == ENOTTY) {
+                       test->test_cases[subtest].skip_reason = "missing kernel support";
+                       ret = TEST_SKIP;
+               }
+
                pr_debug("ioctl(PERF_EVENT_IOC_MODIFY_ATTRIBUTES) failed\n");
                close(fd);
                return ret;
index 17311ad..de3701a 100644 (file)
@@ -14,6 +14,8 @@ struct file;
 struct pid;
 struct cred;
 struct socket;
+struct sock;
+struct sk_buff;
 
 #define __sockaddr_check_size(size)    \
        BUILD_BUG_ON(((size) > sizeof(struct __kernel_sockaddr_storage)))
@@ -69,6 +71,9 @@ struct msghdr {
        unsigned int    msg_flags;      /* flags on received message */
        __kernel_size_t msg_controllen; /* ancillary data buffer length */
        struct kiocb    *msg_iocb;      /* ptr to iocb for async requests */
+       struct ubuf_info *msg_ubuf;
+       int (*sg_from_iter)(struct sock *sk, struct sk_buff *skb,
+                           struct iov_iter *from, size_t length);
 };
 
 struct user_msghdr {
@@ -416,10 +421,9 @@ extern int recvmsg_copy_msghdr(struct msghdr *msg,
                               struct user_msghdr __user *umsg, unsigned flags,
                               struct sockaddr __user **uaddr,
                               struct iovec **iov);
-extern int __copy_msghdr_from_user(struct msghdr *kmsg,
-                                  struct user_msghdr __user *umsg,
-                                  struct sockaddr __user **save_addr,
-                                  struct iovec __user **uiov, size_t *nsegs);
+extern int __copy_msghdr(struct msghdr *kmsg,
+                        struct user_msghdr *umsg,
+                        struct sockaddr __user **save_addr);
 
 /* helpers which do the actual work for syscalls */
 extern int __sys_recvfrom(int fd, void __user *ubuf, size_t size,
@@ -428,10 +432,6 @@ extern int __sys_recvfrom(int fd, void __user *ubuf, size_t size,
 extern int __sys_sendto(int fd, void __user *buff, size_t len,
                        unsigned int flags, struct sockaddr __user *addr,
                        int addr_len);
-extern int __sys_accept4_file(struct file *file, unsigned file_flags,
-                       struct sockaddr __user *upeer_sockaddr,
-                        int __user *upeer_addrlen, int flags,
-                        unsigned long nofile);
 extern struct file *do_accept(struct file *file, unsigned file_flags,
                              struct sockaddr __user *upeer_sockaddr,
                              int __user *upeer_addrlen, int flags);
index 4d216c0..4ee96b3 100644 (file)
@@ -49,8 +49,14 @@ void affinity__set(struct affinity *a, int cpu)
 {
        int cpu_set_size = get_cpu_set_size();
 
-       if (cpu == -1)
+       /*
+        * Return:
+        * - if cpu is -1
+        * - restrict out of bound access to sched_cpus
+        */
+       if (cpu == -1 || ((cpu >= (cpu_set_size * 8))))
                return;
+
        a->changed = true;
        set_bit(cpu, a->sched_cpus);
        /*
index 63b9db6..3c2df75 100644 (file)
@@ -95,7 +95,7 @@ static int bperf_load_program(struct evlist *evlist)
 
        perf_cpu_map__for_each_cpu(cpu, i, evlist->core.all_cpus) {
                link = bpf_program__attach_perf_event(skel->progs.on_cgrp_switch,
-                                                     FD(cgrp_switch, cpu.cpu));
+                                                     FD(cgrp_switch, i));
                if (IS_ERR(link)) {
                        pr_err("Failed to attach cgroup program\n");
                        err = PTR_ERR(link);
@@ -115,15 +115,15 @@ static int bperf_load_program(struct evlist *evlist)
                        evsel->cgrp = NULL;
 
                        /* open single copy of the events w/o cgroup */
-                       err = evsel__open_per_cpu(evsel, evlist->core.all_cpus, -1);
+                       err = evsel__open_per_cpu(evsel, evsel->core.cpus, -1);
                        if (err) {
                                pr_err("Failed to open first cgroup events\n");
                                goto out;
                        }
 
                        map_fd = bpf_map__fd(skel->maps.events);
-                       perf_cpu_map__for_each_cpu(cpu, j, evlist->core.all_cpus) {
-                               int fd = FD(evsel, cpu.cpu);
+                       perf_cpu_map__for_each_cpu(cpu, j, evsel->core.cpus) {
+                               int fd = FD(evsel, j);
                                __u32 idx = evsel->core.idx * total_cpus + cpu.cpu;
 
                                err = bpf_map_update_elem(map_fd, &idx, &fd,
@@ -269,7 +269,7 @@ static int bperf_cgrp__read(struct evsel *evsel)
                        goto out;
                }
 
-               perf_cpu_map__for_each_cpu(cpu, i, evlist->core.all_cpus) {
+               perf_cpu_map__for_each_cpu(cpu, i, evsel->core.cpus) {
                        counts = perf_counts(evsel->counts, i, 0);
                        counts->val = values[cpu.cpu].counter;
                        counts->ena = values[cpu.cpu].enabled;
index 292c430..c72f8ad 100644 (file)
@@ -176,7 +176,7 @@ static int bperf_cgroup_count(void)
 }
 
 // This will be attached to cgroup-switches event for each cpu
-SEC("perf_events")
+SEC("perf_event")
 int BPF_PROG(on_cgrp_switch)
 {
        return bperf_cgroup_count();
index 12b2243..ae43fb8 100644 (file)
@@ -22,54 +22,102 @@ static int max_node_num;
  */
 static int *cpunode_map;
 
-static struct perf_cpu_map *cpu_map__from_entries(struct cpu_map_entries *cpus)
+bool perf_record_cpu_map_data__test_bit(int i,
+                                       const struct perf_record_cpu_map_data *data)
+{
+       int bit_word32 = i / 32;
+       __u32 bit_mask32 = 1U << (i & 31);
+       int bit_word64 = i / 64;
+       __u64 bit_mask64 = ((__u64)1) << (i & 63);
+
+       return (data->mask32_data.long_size == 4)
+               ? (bit_word32 < data->mask32_data.nr) &&
+               (data->mask32_data.mask[bit_word32] & bit_mask32) != 0
+               : (bit_word64 < data->mask64_data.nr) &&
+               (data->mask64_data.mask[bit_word64] & bit_mask64) != 0;
+}
+
+/* Read ith mask value from data into the given 64-bit sized bitmap */
+static void perf_record_cpu_map_data__read_one_mask(const struct perf_record_cpu_map_data *data,
+                                                   int i, unsigned long *bitmap)
+{
+#if __SIZEOF_LONG__ == 8
+       if (data->mask32_data.long_size == 4)
+               bitmap[0] = data->mask32_data.mask[i];
+       else
+               bitmap[0] = data->mask64_data.mask[i];
+#else
+       if (data->mask32_data.long_size == 4) {
+               bitmap[0] = data->mask32_data.mask[i];
+               bitmap[1] = 0;
+       } else {
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+               bitmap[0] = (unsigned long)(data->mask64_data.mask[i] >> 32);
+               bitmap[1] = (unsigned long)data->mask64_data.mask[i];
+#else
+               bitmap[0] = (unsigned long)data->mask64_data.mask[i];
+               bitmap[1] = (unsigned long)(data->mask64_data.mask[i] >> 32);
+#endif
+       }
+#endif
+}
+static struct perf_cpu_map *cpu_map__from_entries(const struct perf_record_cpu_map_data *data)
 {
        struct perf_cpu_map *map;
 
-       map = perf_cpu_map__empty_new(cpus->nr);
+       map = perf_cpu_map__empty_new(data->cpus_data.nr);
        if (map) {
                unsigned i;
 
-               for (i = 0; i < cpus->nr; i++) {
+               for (i = 0; i < data->cpus_data.nr; i++) {
                        /*
                         * Special treatment for -1, which is not real cpu number,
                         * and we need to use (int) -1 to initialize map[i],
                         * otherwise it would become 65535.
                         */
-                       if (cpus->cpu[i] == (u16) -1)
+                       if (data->cpus_data.cpu[i] == (u16) -1)
                                map->map[i].cpu = -1;
                        else
-                               map->map[i].cpu = (int) cpus->cpu[i];
+                               map->map[i].cpu = (int) data->cpus_data.cpu[i];
                }
        }
 
        return map;
 }
 
-static struct perf_cpu_map *cpu_map__from_mask(struct perf_record_record_cpu_map *mask)
+static struct perf_cpu_map *cpu_map__from_mask(const struct perf_record_cpu_map_data *data)
 {
+       DECLARE_BITMAP(local_copy, 64);
+       int weight = 0, mask_nr = data->mask32_data.nr;
        struct perf_cpu_map *map;
-       int nr, nbits = mask->nr * mask->long_size * BITS_PER_BYTE;
 
-       nr = bitmap_weight(mask->mask, nbits);
+       for (int i = 0; i < mask_nr; i++) {
+               perf_record_cpu_map_data__read_one_mask(data, i, local_copy);
+               weight += bitmap_weight(local_copy, 64);
+       }
+
+       map = perf_cpu_map__empty_new(weight);
+       if (!map)
+               return NULL;
 
-       map = perf_cpu_map__empty_new(nr);
-       if (map) {
-               int cpu, i = 0;
+       for (int i = 0, j = 0; i < mask_nr; i++) {
+               int cpus_per_i = (i * data->mask32_data.long_size  * BITS_PER_BYTE);
+               int cpu;
 
-               for_each_set_bit(cpu, mask->mask, nbits)
-                       map->map[i++].cpu = cpu;
+               perf_record_cpu_map_data__read_one_mask(data, i, local_copy);
+               for_each_set_bit(cpu, local_copy, 64)
+                       map->map[j++].cpu = cpu + cpus_per_i;
        }
        return map;
 
 }
 
-struct perf_cpu_map *cpu_map__new_data(struct perf_record_cpu_map_data *data)
+struct perf_cpu_map *cpu_map__new_data(const struct perf_record_cpu_map_data *data)
 {
        if (data->type == PERF_CPU_MAP__CPUS)
-               return cpu_map__from_entries((struct cpu_map_entries *)data->data);
+               return cpu_map__from_entries(data);
        else
-               return cpu_map__from_mask((struct perf_record_record_cpu_map *)data->data);
+               return cpu_map__from_mask(data);
 }
 
 size_t cpu_map__fprintf(struct perf_cpu_map *map, FILE *fp)
index 703ae6d..fa8a5ac 100644 (file)
@@ -37,9 +37,11 @@ struct cpu_aggr_map {
 
 struct perf_record_cpu_map_data;
 
+bool perf_record_cpu_map_data__test_bit(int i, const struct perf_record_cpu_map_data *data);
+
 struct perf_cpu_map *perf_cpu_map__empty_new(int nr);
 
-struct perf_cpu_map *cpu_map__new_data(struct perf_record_cpu_map_data *data);
+struct perf_cpu_map *cpu_map__new_data(const struct perf_record_cpu_map_data *data);
 size_t cpu_map__snprint(struct perf_cpu_map *map, char *buf, size_t size);
 size_t cpu_map__snprint_mask(struct perf_cpu_map *map, char *buf, size_t size);
 size_t cpu_map__fprintf(struct perf_cpu_map *map, FILE *fp);
index a7b0931..12eae69 100644 (file)
@@ -65,7 +65,8 @@ struct stack_dump {
 
 struct sample_read_value {
        u64 value;
-       u64 id;
+       u64 id;   /* only if PERF_FORMAT_ID */
+       u64 lost; /* only if PERF_FORMAT_LOST */
 };
 
 struct sample_read {
@@ -80,6 +81,24 @@ struct sample_read {
        };
 };
 
+static inline size_t sample_read_value_size(u64 read_format)
+{
+       /* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */
+       if (read_format & PERF_FORMAT_LOST)
+               return sizeof(struct sample_read_value);
+       else
+               return offsetof(struct sample_read_value, lost);
+}
+
+static inline struct sample_read_value *
+next_sample_read_value(struct sample_read_value *v, u64 read_format)
+{
+       return (void *)v + sample_read_value_size(read_format);
+}
+
+#define sample_read_group__for_each(v, nr, rf)         \
+       for (int __i = 0; __i < (int)nr; v = next_sample_read_value(v, rf), __i++)
+
 struct ip_callchain {
        u64 nr;
        u64 ips[];
@@ -463,10 +482,6 @@ size_t perf_event__fprintf(union perf_event *event, struct machine *machine, FIL
 int kallsyms__get_function_start(const char *kallsyms_filename,
                                 const char *symbol_name, u64 *addr);
 
-void *cpu_map_data__alloc(struct perf_cpu_map *map, size_t *size, u16 *type, int *max);
-void  cpu_map_data__synthesize(struct perf_record_cpu_map_data *data, struct perf_cpu_map *map,
-                              u16 type, int max);
-
 void event_attr_init(struct perf_event_attr *attr);
 
 int perf_event_paranoid(void);
index 4852089..18c3eb8 100644 (file)
@@ -1541,7 +1541,7 @@ static int evsel__read_one(struct evsel *evsel, int cpu_map_idx, int thread)
 }
 
 static void evsel__set_count(struct evsel *counter, int cpu_map_idx, int thread,
-                            u64 val, u64 ena, u64 run)
+                            u64 val, u64 ena, u64 run, u64 lost)
 {
        struct perf_counts_values *count;
 
@@ -1550,6 +1550,7 @@ static void evsel__set_count(struct evsel *counter, int cpu_map_idx, int thread,
        count->val    = val;
        count->ena    = ena;
        count->run    = run;
+       count->lost   = lost;
 
        perf_counts__set_loaded(counter->counts, cpu_map_idx, thread, true);
 }
@@ -1558,7 +1559,7 @@ static int evsel__process_group_data(struct evsel *leader, int cpu_map_idx, int
 {
        u64 read_format = leader->core.attr.read_format;
        struct sample_read_value *v;
-       u64 nr, ena = 0, run = 0, i;
+       u64 nr, ena = 0, run = 0, lost = 0;
 
        nr = *data++;
 
@@ -1571,18 +1572,18 @@ static int evsel__process_group_data(struct evsel *leader, int cpu_map_idx, int
        if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
                run = *data++;
 
-       v = (struct sample_read_value *) data;
-
-       evsel__set_count(leader, cpu_map_idx, thread, v[0].value, ena, run);
-
-       for (i = 1; i < nr; i++) {
+       v = (void *)data;
+       sample_read_group__for_each(v, nr, read_format) {
                struct evsel *counter;
 
-               counter = evlist__id2evsel(leader->evlist, v[i].id);
+               counter = evlist__id2evsel(leader->evlist, v->id);
                if (!counter)
                        return -EINVAL;
 
-               evsel__set_count(counter, cpu_map_idx, thread, v[i].value, ena, run);
+               if (read_format & PERF_FORMAT_LOST)
+                       lost = v->lost;
+
+               evsel__set_count(counter, cpu_map_idx, thread, v->value, ena, run, lost);
        }
 
        return 0;
@@ -2475,8 +2476,8 @@ int evsel__parse_sample(struct evsel *evsel, union perf_event *event,
 
                        if (data->read.group.nr > max_group_nr)
                                return -EFAULT;
-                       sz = data->read.group.nr *
-                            sizeof(struct sample_read_value);
+
+                       sz = data->read.group.nr * sample_read_value_size(read_format);
                        OVERFLOW_CHECK(array, sz, max_size);
                        data->read.group.values =
                                        (struct sample_read_value *)array;
@@ -2485,6 +2486,12 @@ int evsel__parse_sample(struct evsel *evsel, union perf_event *event,
                        OVERFLOW_CHECK_u64(array);
                        data->read.one.id = *array;
                        array++;
+
+                       if (read_format & PERF_FORMAT_LOST) {
+                               OVERFLOW_CHECK_u64(array);
+                               data->read.one.lost = *array;
+                               array++;
+                       }
                }
        }
 
index 953338b..d81b545 100644 (file)
 
 #define BUILD_ID_URANDOM /* different uuid for each run */
 
-// FIXME, remove this and fix the deprecation warnings before its removed and
-// We'll break for good here...
-#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-
 #ifdef HAVE_LIBCRYPTO_SUPPORT
 
 #define BUILD_ID_MD5
@@ -45,6 +41,7 @@
 #endif
 
 #ifdef BUILD_ID_MD5
+#include <openssl/evp.h>
 #include <openssl/md5.h>
 #endif
 #endif
@@ -142,15 +139,20 @@ gen_build_id(struct buildid_note *note,
 static void
 gen_build_id(struct buildid_note *note, unsigned long load_addr, const void *code, size_t csize)
 {
-       MD5_CTX context;
+       EVP_MD_CTX *mdctx;
 
        if (sizeof(note->build_id) < 16)
                errx(1, "build_id too small for MD5");
 
-       MD5_Init(&context);
-       MD5_Update(&context, &load_addr, sizeof(load_addr));
-       MD5_Update(&context, code, csize);
-       MD5_Final((unsigned char *)note->build_id, &context);
+       mdctx = EVP_MD_CTX_new();
+       if (!mdctx)
+               errx(2, "failed to create EVP_MD_CTX");
+
+       EVP_DigestInit_ex(mdctx, EVP_md5(), NULL);
+       EVP_DigestUpdate(mdctx, &load_addr, sizeof(load_addr));
+       EVP_DigestUpdate(mdctx, code, csize);
+       EVP_DigestFinal_ex(mdctx, (unsigned char *)note->build_id, NULL);
+       EVP_MD_CTX_free(mdctx);
 }
 #endif
 
@@ -251,6 +253,7 @@ jit_write_elf(int fd, uint64_t load_addr, const char *sym,
        Elf_Data *d;
        Elf_Scn *scn;
        Elf_Ehdr *ehdr;
+       Elf_Phdr *phdr;
        Elf_Shdr *shdr;
        uint64_t eh_frame_base_offset;
        char *strsym = NULL;
@@ -286,6 +289,19 @@ jit_write_elf(int fd, uint64_t load_addr, const char *sym,
        ehdr->e_shstrndx= unwinding ? 4 : 2; /* shdr index for section name */
 
        /*
+        * setup program header
+        */
+       phdr = elf_newphdr(e, 1);
+       phdr[0].p_type = PT_LOAD;
+       phdr[0].p_offset = 0;
+       phdr[0].p_vaddr = 0;
+       phdr[0].p_paddr = 0;
+       phdr[0].p_filesz = csize;
+       phdr[0].p_memsz = csize;
+       phdr[0].p_flags = PF_X | PF_R;
+       phdr[0].p_align = 8;
+
+       /*
         * setup text section
         */
        scn = elf_newscn(e);
index ae138af..b5c9095 100644 (file)
@@ -53,8 +53,10 @@ int jit_add_debug_info(Elf *e, uint64_t code_addr, void *debug, int nr_debug_ent
 
 #if GEN_ELF_CLASS == ELFCLASS64
 #define elf_newehdr    elf64_newehdr
+#define elf_newphdr    elf64_newphdr
 #define elf_getshdr    elf64_getshdr
 #define Elf_Ehdr       Elf64_Ehdr
+#define Elf_Phdr       Elf64_Phdr
 #define Elf_Shdr       Elf64_Shdr
 #define Elf_Sym                Elf64_Sym
 #define ELF_ST_TYPE(a) ELF64_ST_TYPE(a)
@@ -62,8 +64,10 @@ int jit_add_debug_info(Elf *e, uint64_t code_addr, void *debug, int nr_debug_ent
 #define ELF_ST_VIS(a)  ELF64_ST_VISIBILITY(a)
 #else
 #define elf_newehdr    elf32_newehdr
+#define elf_newphdr    elf32_newphdr
 #define elf_getshdr    elf32_getshdr
 #define Elf_Ehdr       Elf32_Ehdr
+#define Elf_Phdr       Elf32_Phdr
 #define Elf_Shdr       Elf32_Shdr
 #define Elf_Sym                Elf32_Sym
 #define ELF_ST_TYPE(a) ELF32_ST_TYPE(a)
index 464475f..c93bcaf 100644 (file)
@@ -1655,6 +1655,9 @@ int metricgroup__parse_groups(const struct option *opt,
        struct evlist *perf_evlist = *(struct evlist **)opt->value;
        const struct pmu_events_table *table = pmu_events_table__find();
 
+       if (!table)
+               return -EINVAL;
+
        return parse_groups(perf_evlist, str, metric_no_group,
                            metric_no_merge, NULL, metric_events, table);
 }
index 9ef2406..1f2040f 100644 (file)
@@ -642,15 +642,19 @@ exit:
        return pylist;
 }
 
-static PyObject *get_sample_value_as_tuple(struct sample_read_value *value)
+static PyObject *get_sample_value_as_tuple(struct sample_read_value *value,
+                                          u64 read_format)
 {
        PyObject *t;
 
-       t = PyTuple_New(2);
+       t = PyTuple_New(3);
        if (!t)
                Py_FatalError("couldn't create Python tuple");
        PyTuple_SetItem(t, 0, PyLong_FromUnsignedLongLong(value->id));
        PyTuple_SetItem(t, 1, PyLong_FromUnsignedLongLong(value->value));
+       if (read_format & PERF_FORMAT_LOST)
+               PyTuple_SetItem(t, 2, PyLong_FromUnsignedLongLong(value->lost));
+
        return t;
 }
 
@@ -681,12 +685,17 @@ static void set_sample_read_in_dict(PyObject *dict_sample,
                Py_FatalError("couldn't create Python list");
 
        if (read_format & PERF_FORMAT_GROUP) {
-               for (i = 0; i < sample->read.group.nr; i++) {
-                       PyObject *t = get_sample_value_as_tuple(&sample->read.group.values[i]);
+               struct sample_read_value *v = sample->read.group.values;
+
+               i = 0;
+               sample_read_group__for_each(v, sample->read.group.nr, read_format) {
+                       PyObject *t = get_sample_value_as_tuple(v, read_format);
                        PyList_SET_ITEM(values, i, t);
+                       i++;
                }
        } else {
-               PyObject *t = get_sample_value_as_tuple(&sample->read.one);
+               PyObject *t = get_sample_value_as_tuple(&sample->read.one,
+                                                       read_format);
                PyList_SET_ITEM(values, 0, t);
        }
        pydict_set_item_string_decref(dict_sample, "values", values);
index 98e1665..192c927 100644 (file)
@@ -916,30 +916,30 @@ static void perf_event__cpu_map_swap(union perf_event *event,
                                     bool sample_id_all __maybe_unused)
 {
        struct perf_record_cpu_map_data *data = &event->cpu_map.data;
-       struct cpu_map_entries *cpus;
-       struct perf_record_record_cpu_map *mask;
-       unsigned i;
 
        data->type = bswap_16(data->type);
 
        switch (data->type) {
        case PERF_CPU_MAP__CPUS:
-               cpus = (struct cpu_map_entries *)data->data;
-
-               cpus->nr = bswap_16(cpus->nr);
+               data->cpus_data.nr = bswap_16(data->cpus_data.nr);
 
-               for (i = 0; i < cpus->nr; i++)
-                       cpus->cpu[i] = bswap_16(cpus->cpu[i]);
+               for (unsigned i = 0; i < data->cpus_data.nr; i++)
+                       data->cpus_data.cpu[i] = bswap_16(data->cpus_data.cpu[i]);
                break;
        case PERF_CPU_MAP__MASK:
-               mask = (struct perf_record_record_cpu_map *)data->data;
-
-               mask->nr = bswap_16(mask->nr);
-               mask->long_size = bswap_16(mask->long_size);
+               data->mask32_data.long_size = bswap_16(data->mask32_data.long_size);
 
-               switch (mask->long_size) {
-               case 4: mem_bswap_32(&mask->mask, mask->nr); break;
-               case 8: mem_bswap_64(&mask->mask, mask->nr); break;
+               switch (data->mask32_data.long_size) {
+               case 4:
+                       data->mask32_data.nr = bswap_16(data->mask32_data.nr);
+                       for (unsigned i = 0; i < data->mask32_data.nr; i++)
+                               data->mask32_data.mask[i] = bswap_32(data->mask32_data.mask[i]);
+                       break;
+               case 8:
+                       data->mask64_data.nr = bswap_16(data->mask64_data.nr);
+                       for (unsigned i = 0; i < data->mask64_data.nr; i++)
+                               data->mask64_data.mask[i] = bswap_64(data->mask64_data.mask[i]);
+                       break;
                default:
                        pr_err("cpu_map swap: unsupported long size\n");
                }
@@ -1283,21 +1283,25 @@ static void sample_read__printf(struct perf_sample *sample, u64 read_format)
                       sample->read.time_running);
 
        if (read_format & PERF_FORMAT_GROUP) {
-               u64 i;
+               struct sample_read_value *value = sample->read.group.values;
 
                printf(".... group nr %" PRIu64 "\n", sample->read.group.nr);
 
-               for (i = 0; i < sample->read.group.nr; i++) {
-                       struct sample_read_value *value;
-
-                       value = &sample->read.group.values[i];
+               sample_read_group__for_each(value, sample->read.group.nr, read_format) {
                        printf("..... id %016" PRIx64
-                              ", value %016" PRIx64 "\n",
+                              ", value %016" PRIx64,
                               value->id, value->value);
+                       if (read_format & PERF_FORMAT_LOST)
+                               printf(", lost %" PRIu64, value->lost);
+                       printf("\n");
                }
-       } else
-               printf("..... id %016" PRIx64 ", value %016" PRIx64 "\n",
+       } else {
+               printf("..... id %016" PRIx64 ", value %016" PRIx64,
                        sample->read.one.id, sample->read.one.value);
+               if (read_format & PERF_FORMAT_LOST)
+                       printf(", lost %" PRIu64, sample->read.one.lost);
+               printf("\n");
+       }
 }
 
 static void dump_event(struct evlist *evlist, union perf_event *event,
@@ -1411,6 +1415,9 @@ static void dump_read(struct evsel *evsel, union perf_event *event)
 
        if (read_format & PERF_FORMAT_ID)
                printf("... id           : %" PRI_lu64 "\n", read_event->id);
+
+       if (read_format & PERF_FORMAT_LOST)
+               printf("... lost         : %" PRI_lu64 "\n", read_event->lost);
 }
 
 static struct machine *machines__find_for_cpumode(struct machines *machines,
@@ -1479,14 +1486,14 @@ static int deliver_sample_group(struct evlist *evlist,
                                struct perf_tool *tool,
                                union  perf_event *event,
                                struct perf_sample *sample,
-                               struct machine *machine)
+                               struct machine *machine,
+                               u64 read_format)
 {
        int ret = -EINVAL;
-       u64 i;
+       struct sample_read_value *v = sample->read.group.values;
 
-       for (i = 0; i < sample->read.group.nr; i++) {
-               ret = deliver_sample_value(evlist, tool, event, sample,
-                                          &sample->read.group.values[i],
+       sample_read_group__for_each(v, sample->read.group.nr, read_format) {
+               ret = deliver_sample_value(evlist, tool, event, sample, v,
                                           machine);
                if (ret)
                        break;
@@ -1510,7 +1517,7 @@ static int evlist__deliver_sample(struct evlist *evlist, struct perf_tool *tool,
        /* For PERF_SAMPLE_READ we have either single or group mode. */
        if (read_format & PERF_FORMAT_GROUP)
                return deliver_sample_group(evlist, tool, event, sample,
-                                           machine);
+                                           machine, read_format);
        else
                return deliver_sample_value(evlist, tool, event, sample,
                                            &sample->read.one, machine);
index 979c8cb..788ce5e 100644 (file)
@@ -1193,7 +1193,7 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config,
                                                  &rsd);
                if (retiring > 0.7)
                        color = PERF_COLOR_GREEN;
-               print_metric(config, ctxp, color, "%8.1f%%", "retiring",
+               print_metric(config, ctxp, color, "%8.1f%%", "Retiring",
                                retiring * 100.);
        } else if (perf_stat_evsel__is(evsel, TOPDOWN_FE_BOUND) &&
                   full_td(cpu_map_idx, st, &rsd)) {
@@ -1202,7 +1202,7 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config,
                                                  &rsd);
                if (fe_bound > 0.2)
                        color = PERF_COLOR_RED;
-               print_metric(config, ctxp, color, "%8.1f%%", "frontend bound",
+               print_metric(config, ctxp, color, "%8.1f%%", "Frontend Bound",
                                fe_bound * 100.);
        } else if (perf_stat_evsel__is(evsel, TOPDOWN_BE_BOUND) &&
                   full_td(cpu_map_idx, st, &rsd)) {
@@ -1211,7 +1211,7 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config,
                                                  &rsd);
                if (be_bound > 0.2)
                        color = PERF_COLOR_RED;
-               print_metric(config, ctxp, color, "%8.1f%%", "backend bound",
+               print_metric(config, ctxp, color, "%8.1f%%", "Backend Bound",
                                be_bound * 100.);
        } else if (perf_stat_evsel__is(evsel, TOPDOWN_BAD_SPEC) &&
                   full_td(cpu_map_idx, st, &rsd)) {
@@ -1220,7 +1220,7 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config,
                                                  &rsd);
                if (bad_spec > 0.1)
                        color = PERF_COLOR_RED;
-               print_metric(config, ctxp, color, "%8.1f%%", "bad speculation",
+               print_metric(config, ctxp, color, "%8.1f%%", "Bad Speculation",
                                bad_spec * 100.);
        } else if (perf_stat_evsel__is(evsel, TOPDOWN_HEAVY_OPS) &&
                        full_td(cpu_map_idx, st, &rsd) && (config->topdown_level > 1)) {
@@ -1234,13 +1234,13 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config,
 
                if (retiring > 0.7 && heavy_ops > 0.1)
                        color = PERF_COLOR_GREEN;
-               print_metric(config, ctxp, color, "%8.1f%%", "heavy operations",
+               print_metric(config, ctxp, color, "%8.1f%%", "Heavy Operations",
                                heavy_ops * 100.);
                if (retiring > 0.7 && light_ops > 0.6)
                        color = PERF_COLOR_GREEN;
                else
                        color = NULL;
-               print_metric(config, ctxp, color, "%8.1f%%", "light operations",
+               print_metric(config, ctxp, color, "%8.1f%%", "Light Operations",
                                light_ops * 100.);
        } else if (perf_stat_evsel__is(evsel, TOPDOWN_BR_MISPREDICT) &&
                        full_td(cpu_map_idx, st, &rsd) && (config->topdown_level > 1)) {
@@ -1254,13 +1254,13 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config,
 
                if (bad_spec > 0.1 && br_mis > 0.05)
                        color = PERF_COLOR_RED;
-               print_metric(config, ctxp, color, "%8.1f%%", "branch mispredict",
+               print_metric(config, ctxp, color, "%8.1f%%", "Branch Mispredict",
                                br_mis * 100.);
                if (bad_spec > 0.1 && m_clears > 0.05)
                        color = PERF_COLOR_RED;
                else
                        color = NULL;
-               print_metric(config, ctxp, color, "%8.1f%%", "machine clears",
+               print_metric(config, ctxp, color, "%8.1f%%", "Machine Clears",
                                m_clears * 100.);
        } else if (perf_stat_evsel__is(evsel, TOPDOWN_FETCH_LAT) &&
                        full_td(cpu_map_idx, st, &rsd) && (config->topdown_level > 1)) {
@@ -1274,13 +1274,13 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config,
 
                if (fe_bound > 0.2 && fetch_lat > 0.15)
                        color = PERF_COLOR_RED;
-               print_metric(config, ctxp, color, "%8.1f%%", "fetch latency",
+               print_metric(config, ctxp, color, "%8.1f%%", "Fetch Latency",
                                fetch_lat * 100.);
                if (fe_bound > 0.2 && fetch_bw > 0.1)
                        color = PERF_COLOR_RED;
                else
                        color = NULL;
-               print_metric(config, ctxp, color, "%8.1f%%", "fetch bandwidth",
+               print_metric(config, ctxp, color, "%8.1f%%", "Fetch Bandwidth",
                                fetch_bw * 100.);
        } else if (perf_stat_evsel__is(evsel, TOPDOWN_MEM_BOUND) &&
                        full_td(cpu_map_idx, st, &rsd) && (config->topdown_level > 1)) {
@@ -1294,13 +1294,13 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config,
 
                if (be_bound > 0.2 && mem_bound > 0.2)
                        color = PERF_COLOR_RED;
-               print_metric(config, ctxp, color, "%8.1f%%", "memory bound",
+               print_metric(config, ctxp, color, "%8.1f%%", "Memory Bound",
                                mem_bound * 100.);
                if (be_bound > 0.2 && core_bound > 0.1)
                        color = PERF_COLOR_RED;
                else
                        color = NULL;
-               print_metric(config, ctxp, color, "%8.1f%%", "Core bound",
+               print_metric(config, ctxp, color, "%8.1f%%", "Core Bound",
                                core_bound * 100.);
        } else if (evsel->metric_expr) {
                generic_metric(config, evsel->metric_expr, evsel->metric_events, NULL,
index 75bec32..647b7df 100644 (file)
@@ -2102,8 +2102,8 @@ static int kcore_copy__compare_file(const char *from_dir, const char *to_dir,
  * unusual.  One significant peculiarity is that the mapping (start -> pgoff)
  * is not the same for the kernel map and the modules map.  That happens because
  * the data is copied adjacently whereas the original kcore has gaps.  Finally,
- * kallsyms and modules files are compared with their copies to check that
- * modules have not been loaded or unloaded while the copies were taking place.
+ * kallsyms file is compared with its copy to check that modules have not been
+ * loaded or unloaded while the copies were taking place.
  *
  * Return: %0 on success, %-1 on failure.
  */
@@ -2166,9 +2166,6 @@ int kcore_copy(const char *from_dir, const char *to_dir)
                        goto out_extract_close;
        }
 
-       if (kcore_copy__compare_file(from_dir, to_dir, "modules"))
-               goto out_extract_close;
-
        if (kcore_copy__compare_file(from_dir, to_dir, "kallsyms"))
                goto out_extract_close;
 
index 2ae59c0..5387907 100644 (file)
@@ -367,13 +367,24 @@ static void perf_record_mmap2__read_build_id(struct perf_record_mmap2 *event,
                                             bool is_kernel)
 {
        struct build_id bid;
+       struct nsinfo *nsi;
+       struct nscookie nc;
        int rc;
 
-       if (is_kernel)
+       if (is_kernel) {
                rc = sysfs__read_build_id("/sys/kernel/notes", &bid);
-       else
-               rc = filename__read_build_id(event->filename, &bid) > 0 ? 0 : -1;
+               goto out;
+       }
+
+       nsi = nsinfo__new(event->pid);
+       nsinfo__mountns_enter(nsi, &nc);
 
+       rc = filename__read_build_id(event->filename, &bid) > 0 ? 0 : -1;
+
+       nsinfo__mountns_exit(&nc);
+       nsinfo__put(nsi);
+
+out:
        if (rc == 0) {
                memcpy(event->build_id, bid.data, sizeof(bid.data));
                event->build_id_size = (u8) bid.size;
@@ -1184,52 +1195,48 @@ int perf_event__synthesize_thread_map2(struct perf_tool *tool,
        return err;
 }
 
-static void synthesize_cpus(struct cpu_map_entries *cpus,
-                           struct perf_cpu_map *map)
+static void synthesize_cpus(struct perf_record_cpu_map_data *data,
+                           const struct perf_cpu_map *map)
 {
        int i, map_nr = perf_cpu_map__nr(map);
 
-       cpus->nr = map_nr;
+       data->cpus_data.nr = map_nr;
 
        for (i = 0; i < map_nr; i++)
-               cpus->cpu[i] = perf_cpu_map__cpu(map, i).cpu;
+               data->cpus_data.cpu[i] = perf_cpu_map__cpu(map, i).cpu;
 }
 
-static void synthesize_mask(struct perf_record_record_cpu_map *mask,
-                           struct perf_cpu_map *map, int max)
+static void synthesize_mask(struct perf_record_cpu_map_data *data,
+                           const struct perf_cpu_map *map, int max)
 {
-       int i;
+       int idx;
+       struct perf_cpu cpu;
+
+       /* Due to padding, the 4bytes per entry mask variant is always smaller. */
+       data->mask32_data.nr = BITS_TO_U32(max);
+       data->mask32_data.long_size = 4;
 
-       mask->nr = BITS_TO_LONGS(max);
-       mask->long_size = sizeof(long);
+       perf_cpu_map__for_each_cpu(cpu, idx, map) {
+               int bit_word = cpu.cpu / 32;
+               __u32 bit_mask = 1U << (cpu.cpu & 31);
 
-       for (i = 0; i < perf_cpu_map__nr(map); i++)
-               set_bit(perf_cpu_map__cpu(map, i).cpu, mask->mask);
+               data->mask32_data.mask[bit_word] |= bit_mask;
+       }
 }
 
-static size_t cpus_size(struct perf_cpu_map *map)
+static size_t cpus_size(const struct perf_cpu_map *map)
 {
        return sizeof(struct cpu_map_entries) + perf_cpu_map__nr(map) * sizeof(u16);
 }
 
-static size_t mask_size(struct perf_cpu_map *map, int *max)
+static size_t mask_size(const struct perf_cpu_map *map, int *max)
 {
-       int i;
-
-       *max = 0;
-
-       for (i = 0; i < perf_cpu_map__nr(map); i++) {
-               /* bit position of the cpu is + 1 */
-               int bit = perf_cpu_map__cpu(map, i).cpu + 1;
-
-               if (bit > *max)
-                       *max = bit;
-       }
-
-       return sizeof(struct perf_record_record_cpu_map) + BITS_TO_LONGS(*max) * sizeof(long);
+       *max = perf_cpu_map__max(map).cpu;
+       return sizeof(struct perf_record_mask_cpu_map32) + BITS_TO_U32(*max) * sizeof(__u32);
 }
 
-void *cpu_map_data__alloc(struct perf_cpu_map *map, size_t *size, u16 *type, int *max)
+static void *cpu_map_data__alloc(const struct perf_cpu_map *map, size_t *size,
+                                u16 *type, int *max)
 {
        size_t size_cpus, size_mask;
        bool is_dummy = perf_cpu_map__empty(map);
@@ -1258,30 +1265,31 @@ void *cpu_map_data__alloc(struct perf_cpu_map *map, size_t *size, u16 *type, int
                *type  = PERF_CPU_MAP__MASK;
        }
 
-       *size += sizeof(struct perf_record_cpu_map_data);
+       *size += sizeof(__u16); /* For perf_record_cpu_map_data.type. */
        *size = PERF_ALIGN(*size, sizeof(u64));
        return zalloc(*size);
 }
 
-void cpu_map_data__synthesize(struct perf_record_cpu_map_data *data, struct perf_cpu_map *map,
-                             u16 type, int max)
+static void cpu_map_data__synthesize(struct perf_record_cpu_map_data *data,
+                                    const struct perf_cpu_map *map,
+                                    u16 type, int max)
 {
        data->type = type;
 
        switch (type) {
        case PERF_CPU_MAP__CPUS:
-               synthesize_cpus((struct cpu_map_entries *) data->data, map);
+               synthesize_cpus(data, map);
                break;
        case PERF_CPU_MAP__MASK:
-               synthesize_mask((struct perf_record_record_cpu_map *)data->data, map, max);
+               synthesize_mask(data, map, max);
        default:
                break;
        }
 }
 
-static struct perf_record_cpu_map *cpu_map_event__new(struct perf_cpu_map *map)
+static struct perf_record_cpu_map *cpu_map_event__new(const struct perf_cpu_map *map)
 {
-       size_t size = sizeof(struct perf_record_cpu_map);
+       size_t size = sizeof(struct perf_event_header);
        struct perf_record_cpu_map *event;
        int max;
        u16 type;
@@ -1299,7 +1307,7 @@ static struct perf_record_cpu_map *cpu_map_event__new(struct perf_cpu_map *map)
 }
 
 int perf_event__synthesize_cpu_map(struct perf_tool *tool,
-                                  struct perf_cpu_map *map,
+                                  const struct perf_cpu_map *map,
                                   perf_event__handler_t process,
                                   struct machine *machine)
 {
@@ -1432,11 +1440,12 @@ size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
                        result += sizeof(u64);
                /* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */
                if (read_format & PERF_FORMAT_GROUP) {
-                       sz = sample->read.group.nr *
-                            sizeof(struct sample_read_value);
-                       result += sz;
+                       sz = sample_read_value_size(read_format);
+                       result += sz * sample->read.group.nr;
                } else {
                        result += sizeof(u64);
+                       if (read_format & PERF_FORMAT_LOST)
+                               result += sizeof(u64);
                }
        }
 
@@ -1521,6 +1530,20 @@ void __weak arch_perf_synthesize_sample_weight(const struct perf_sample *data,
        *array = data->weight;
 }
 
+static __u64 *copy_read_group_values(__u64 *array, __u64 read_format,
+                                    const struct perf_sample *sample)
+{
+       size_t sz = sample_read_value_size(read_format);
+       struct sample_read_value *v = sample->read.group.values;
+
+       sample_read_group__for_each(v, sample->read.group.nr, read_format) {
+               /* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */
+               memcpy(array, v, sz);
+               array = (void *)array + sz;
+       }
+       return array;
+}
+
 int perf_event__synthesize_sample(union perf_event *event, u64 type, u64 read_format,
                                  const struct perf_sample *sample)
 {
@@ -1602,13 +1625,16 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type, u64 read_fo
 
                /* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */
                if (read_format & PERF_FORMAT_GROUP) {
-                       sz = sample->read.group.nr *
-                            sizeof(struct sample_read_value);
-                       memcpy(array, sample->read.group.values, sz);
-                       array = (void *)array + sz;
+                       array = copy_read_group_values(array, read_format,
+                                                      sample);
                } else {
                        *array = sample->read.one.id;
                        array++;
+
+                       if (read_format & PERF_FORMAT_LOST) {
+                               *array = sample->read.one.lost;
+                               array++;
+                       }
                }
        }
 
index 81cb3d6..53737d1 100644 (file)
@@ -46,7 +46,7 @@ typedef int (*perf_event__handler_t)(struct perf_tool *tool, union perf_event *e
 int perf_event__synthesize_attrs(struct perf_tool *tool, struct evlist *evlist, perf_event__handler_t process);
 int perf_event__synthesize_attr(struct perf_tool *tool, struct perf_event_attr *attr, u32 ids, u64 *id, perf_event__handler_t process);
 int perf_event__synthesize_build_id(struct perf_tool *tool, struct dso *pos, u16 misc, perf_event__handler_t process, struct machine *machine);
-int perf_event__synthesize_cpu_map(struct perf_tool *tool, struct perf_cpu_map *cpus, perf_event__handler_t process, struct machine *machine);
+int perf_event__synthesize_cpu_map(struct perf_tool *tool, const struct perf_cpu_map *cpus, perf_event__handler_t process, struct machine *machine);
 int perf_event__synthesize_event_update_cpus(struct perf_tool *tool, struct evsel *evsel, perf_event__handler_t process);
 int perf_event__synthesize_event_update_name(struct perf_tool *tool, struct evsel *evsel, perf_event__handler_t process);
 int perf_event__synthesize_event_update_scale(struct perf_tool *tool, struct evsel *evsel, perf_event__handler_t process);
index 10b34bb..c2064a3 100644 (file)
@@ -12,6 +12,7 @@ TARGETS += cpu-hotplug
 TARGETS += damon
 TARGETS += drivers/dma-buf
 TARGETS += drivers/s390x/uvdevice
+TARGETS += drivers/net/bonding
 TARGETS += efivarfs
 TARGETS += exec
 TARGETS += filesystems
index e33cab3..db98106 100644 (file)
@@ -65,3 +65,4 @@ send_signal                              # intermittently fails to receive signa
 select_reuseport                         # intermittently fails on new s390x setup
 xdp_synproxy                             # JIT does not support calling kernel function                                (kfunc)
 unpriv_bpf_disabled                      # fentry
+lru_bug                                  # prog 'printk': failed to auto-attach: -524
index 9e75442..6c03a7d 100644 (file)
        .result = VERBOSE_ACCEPT,
        .retval = -1,
 },
+{
+       "precise: mark_chain_precision for ARG_CONST_ALLOC_SIZE_OR_ZERO",
+       .insns = {
+       BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_1, offsetof(struct xdp_md, ingress_ifindex)),
+       BPF_LD_MAP_FD(BPF_REG_6, 0),
+       BPF_MOV64_REG(BPF_REG_1, BPF_REG_6),
+       BPF_MOV64_IMM(BPF_REG_2, 1),
+       BPF_MOV64_IMM(BPF_REG_3, 0),
+       BPF_JMP_IMM(BPF_JEQ, BPF_REG_4, 0, 1),
+       BPF_MOV64_IMM(BPF_REG_2, 0x1000),
+       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_ringbuf_reserve),
+       BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1),
+       BPF_EXIT_INSN(),
+       BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
+       BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_0, 42),
+       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_ringbuf_submit),
+       BPF_MOV64_IMM(BPF_REG_0, 0),
+       BPF_EXIT_INSN(),
+       },
+       .fixup_map_ringbuf = { 1 },
+       .prog_type = BPF_PROG_TYPE_XDP,
+       .flags = BPF_F_TEST_STATE_FREQ,
+       .errstr = "invalid access to memory, mem_size=1 off=42 size=8",
+       .result = REJECT,
+},
diff --git a/tools/testing/selftests/drivers/net/bonding/Makefile b/tools/testing/selftests/drivers/net/bonding/Makefile
new file mode 100644 (file)
index 0000000..ab6c54b
--- /dev/null
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0
+# Makefile for net selftests
+
+TEST_PROGS := bond-break-lacpdu-tx.sh
+
+include ../../../lib.mk
diff --git a/tools/testing/selftests/drivers/net/bonding/bond-break-lacpdu-tx.sh b/tools/testing/selftests/drivers/net/bonding/bond-break-lacpdu-tx.sh
new file mode 100755 (executable)
index 0000000..47ab905
--- /dev/null
@@ -0,0 +1,81 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+
+# Regression Test:
+#   Verify LACPDUs get transmitted after setting the MAC address of
+#   the bond.
+#
+# https://bugzilla.redhat.com/show_bug.cgi?id=2020773
+#
+#       +---------+
+#       | fab-br0 |
+#       +---------+
+#            |
+#       +---------+
+#       |  fbond  |
+#       +---------+
+#        |       |
+#    +------+ +------+
+#    |veth1 | |veth2 |
+#    +------+ +------+
+#
+# We use veths instead of physical interfaces
+
+set -e
+tmp=$(mktemp -q dump.XXXXXX)
+cleanup() {
+       ip link del fab-br0 >/dev/null 2>&1 || :
+       ip link del fbond  >/dev/null 2>&1 || :
+       ip link del veth1-bond  >/dev/null 2>&1 || :
+       ip link del veth2-bond  >/dev/null 2>&1 || :
+       modprobe -r bonding  >/dev/null 2>&1 || :
+       rm -f -- ${tmp}
+}
+
+trap cleanup 0 1 2
+cleanup
+sleep 1
+
+# create the bridge
+ip link add fab-br0 address 52:54:00:3B:7C:A6 mtu 1500 type bridge \
+       forward_delay 15
+
+# create the bond
+ip link add fbond type bond mode 4 miimon 200 xmit_hash_policy 1 \
+       ad_actor_sys_prio 65535 lacp_rate fast
+
+# set bond address
+ip link set fbond address 52:54:00:3B:7C:A6
+ip link set fbond up
+
+# set again bond sysfs parameters
+ip link set fbond type bond ad_actor_sys_prio 65535
+
+# create veths
+ip link add name veth1-bond type veth peer name veth1-end
+ip link add name veth2-bond type veth peer name veth2-end
+
+# add ports
+ip link set fbond master fab-br0
+ip link set veth1-bond down master fbond
+ip link set veth2-bond down master fbond
+
+# bring up
+ip link set veth1-end up
+ip link set veth2-end up
+ip link set fab-br0 up
+ip link set fbond up
+ip addr add dev fab-br0 10.0.0.3
+
+tcpdump -n -i veth1-end -e ether proto 0x8809 >${tmp} 2>&1 &
+sleep 15
+pkill tcpdump >/dev/null 2>&1
+rc=0
+num=$(grep "packets captured" ${tmp} | awk '{print $1}')
+if test "$num" -gt 0; then
+       echo "PASS, captured ${num}"
+else
+       echo "FAIL"
+       rc=1
+fi
+exit $rc
diff --git a/tools/testing/selftests/drivers/net/bonding/config b/tools/testing/selftests/drivers/net/bonding/config
new file mode 100644 (file)
index 0000000..dc1c22d
--- /dev/null
@@ -0,0 +1 @@
+CONFIG_BONDING=y
diff --git a/tools/testing/selftests/drivers/net/bonding/settings b/tools/testing/selftests/drivers/net/bonding/settings
new file mode 100644 (file)
index 0000000..867e118
--- /dev/null
@@ -0,0 +1 @@
+timeout=60
index 45edf45..0cbc71b 100644 (file)
@@ -754,7 +754,7 @@ void vm_install_exception_handler(struct kvm_vm *vm, int vector,
                        void (*handler)(struct ex_regs *));
 
 /* If a toddler were to say "abracadabra". */
-#define KVM_EXCEPTION_MAGIC 0xabacadabaull
+#define KVM_EXCEPTION_MAGIC 0xabacadabaULL
 
 /*
  * KVM selftest exception fixup uses registers to coordinate with the exception
@@ -786,7 +786,7 @@ void vm_install_exception_handler(struct kvm_vm *vm, int vector,
        "lea 1f(%%rip), %%r10\n\t"                              \
        "lea 2f(%%rip), %%r11\n\t"                              \
        "1: " insn "\n\t"                                       \
-       "mov $0, %[vector]\n\t"                                 \
+       "movb $0, %[vector]\n\t"                                \
        "jmp 3f\n\t"                                            \
        "2:\n\t"                                                \
        "mov  %%r9b, %[vector]\n\t"                             \
index a6959df..02868ac 100644 (file)
@@ -9,10 +9,13 @@ TEST_GEN_PROGS := $(src_test:.c=)
 TEST_GEN_PROGS_EXTENDED := true
 
 OVERRIDE_TARGETS := 1
+top_srcdir := ../../../..
 include ../lib.mk
 
+khdr_dir = $(top_srcdir)/usr/include
+
 $(OUTPUT)/true: true.c
        $(LINK.c) $< $(LDLIBS) -o $@ -static
 
-$(OUTPUT)/%_test: %_test.c ../kselftest_harness.h common.h
-       $(LINK.c) $< $(LDLIBS) -o $@ -lcap
+$(OUTPUT)/%_test: %_test.c $(khdr_dir)/linux/landlock.h ../kselftest_harness.h common.h
+       $(LINK.c) $< $(LDLIBS) -o $@ -lcap -I$(khdr_dir)
index 21a2ce8..45de42a 100644 (file)
@@ -4,7 +4,7 @@
  *
  * Copyright © 2017-2020 Mickaël Salaün <mic@digikod.net>
  * Copyright © 2020 ANSSI
- * Copyright © 2020-2021 Microsoft Corporation
+ * Copyright © 2020-2022 Microsoft Corporation
  */
 
 #define _GNU_SOURCE
@@ -371,6 +371,13 @@ TEST_F_FORK(layout1, inval)
        ASSERT_EQ(EINVAL, errno);
        path_beneath.allowed_access &= ~LANDLOCK_ACCESS_FS_EXECUTE;
 
+       /* Tests with denied-by-default access right. */
+       path_beneath.allowed_access |= LANDLOCK_ACCESS_FS_REFER;
+       ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
+                                       &path_beneath, 0));
+       ASSERT_EQ(EINVAL, errno);
+       path_beneath.allowed_access &= ~LANDLOCK_ACCESS_FS_REFER;
+
        /* Test with unknown (64-bits) value. */
        path_beneath.allowed_access |= (1ULL << 60);
        ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
@@ -1826,6 +1833,20 @@ TEST_F_FORK(layout1, link)
        ASSERT_EQ(0, link(file1_s1d3, file2_s1d3));
 }
 
+static int test_rename(const char *const oldpath, const char *const newpath)
+{
+       if (rename(oldpath, newpath))
+               return errno;
+       return 0;
+}
+
+static int test_exchange(const char *const oldpath, const char *const newpath)
+{
+       if (renameat2(AT_FDCWD, oldpath, AT_FDCWD, newpath, RENAME_EXCHANGE))
+               return errno;
+       return 0;
+}
+
 TEST_F_FORK(layout1, rename_file)
 {
        const struct rule rules[] = {
@@ -1867,10 +1888,10 @@ TEST_F_FORK(layout1, rename_file)
         * to a different directory (which allows file removal).
         */
        ASSERT_EQ(-1, rename(file1_s2d1, file1_s1d3));
-       ASSERT_EQ(EXDEV, errno);
+       ASSERT_EQ(EACCES, errno);
        ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d1, AT_FDCWD, file1_s1d3,
                                RENAME_EXCHANGE));
-       ASSERT_EQ(EXDEV, errno);
+       ASSERT_EQ(EACCES, errno);
        ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s2d2, AT_FDCWD, file1_s1d3,
                                RENAME_EXCHANGE));
        ASSERT_EQ(EXDEV, errno);
@@ -1894,7 +1915,7 @@ TEST_F_FORK(layout1, rename_file)
        ASSERT_EQ(EXDEV, errno);
        ASSERT_EQ(0, unlink(file1_s1d3));
        ASSERT_EQ(-1, rename(file1_s2d1, file1_s1d3));
-       ASSERT_EQ(EXDEV, errno);
+       ASSERT_EQ(EACCES, errno);
 
        /* Exchanges and renames files with same parent. */
        ASSERT_EQ(0, renameat2(AT_FDCWD, file2_s2d3, AT_FDCWD, file1_s2d3,
@@ -2014,6 +2035,115 @@ TEST_F_FORK(layout1, reparent_refer)
        ASSERT_EQ(0, rename(dir_s1d3, dir_s2d3));
 }
 
+/* Checks renames beneath dir_s1d1. */
+static void refer_denied_by_default(struct __test_metadata *const _metadata,
+                                   const struct rule layer1[],
+                                   const int layer1_err,
+                                   const struct rule layer2[])
+{
+       int ruleset_fd;
+
+       ASSERT_EQ(0, unlink(file1_s1d2));
+
+       ruleset_fd = create_ruleset(_metadata, layer1[0].access, layer1);
+       ASSERT_LE(0, ruleset_fd);
+       enforce_ruleset(_metadata, ruleset_fd);
+       ASSERT_EQ(0, close(ruleset_fd));
+
+       /*
+        * If the first layer handles LANDLOCK_ACCESS_FS_REFER (according to
+        * layer1_err), then it allows some different-parent renames and links.
+        */
+       ASSERT_EQ(layer1_err, test_rename(file1_s1d1, file1_s1d2));
+       if (layer1_err == 0)
+               ASSERT_EQ(layer1_err, test_rename(file1_s1d2, file1_s1d1));
+       ASSERT_EQ(layer1_err, test_exchange(file2_s1d1, file2_s1d2));
+       ASSERT_EQ(layer1_err, test_exchange(file2_s1d2, file2_s1d1));
+
+       ruleset_fd = create_ruleset(_metadata, layer2[0].access, layer2);
+       ASSERT_LE(0, ruleset_fd);
+       enforce_ruleset(_metadata, ruleset_fd);
+       ASSERT_EQ(0, close(ruleset_fd));
+
+       /*
+        * Now, either the first or the second layer does not handle
+        * LANDLOCK_ACCESS_FS_REFER, which means that any different-parent
+        * renames and links are denied, thus making the layer handling
+        * LANDLOCK_ACCESS_FS_REFER null and void.
+        */
+       ASSERT_EQ(EXDEV, test_rename(file1_s1d1, file1_s1d2));
+       ASSERT_EQ(EXDEV, test_exchange(file2_s1d1, file2_s1d2));
+       ASSERT_EQ(EXDEV, test_exchange(file2_s1d2, file2_s1d1));
+}
+
+const struct rule layer_dir_s1d1_refer[] = {
+       {
+               .path = dir_s1d1,
+               .access = LANDLOCK_ACCESS_FS_REFER,
+       },
+       {},
+};
+
+const struct rule layer_dir_s1d1_execute[] = {
+       {
+               /* Matches a parent directory. */
+               .path = dir_s1d1,
+               .access = LANDLOCK_ACCESS_FS_EXECUTE,
+       },
+       {},
+};
+
+const struct rule layer_dir_s2d1_execute[] = {
+       {
+               /* Does not match a parent directory. */
+               .path = dir_s2d1,
+               .access = LANDLOCK_ACCESS_FS_EXECUTE,
+       },
+       {},
+};
+
+/*
+ * Tests precedence over renames: denied by default for different parent
+ * directories, *with* a rule matching a parent directory, but not directly
+ * denying access (with MAKE_REG nor REMOVE).
+ */
+TEST_F_FORK(layout1, refer_denied_by_default1)
+{
+       refer_denied_by_default(_metadata, layer_dir_s1d1_refer, 0,
+                               layer_dir_s1d1_execute);
+}
+
+/*
+ * Same test but this time turning around the ABI version order: the first
+ * layer does not handle LANDLOCK_ACCESS_FS_REFER.
+ */
+TEST_F_FORK(layout1, refer_denied_by_default2)
+{
+       refer_denied_by_default(_metadata, layer_dir_s1d1_execute, EXDEV,
+                               layer_dir_s1d1_refer);
+}
+
+/*
+ * Tests precedence over renames: denied by default for different parent
+ * directories, *without* a rule matching a parent directory, but not directly
+ * denying access (with MAKE_REG nor REMOVE).
+ */
+TEST_F_FORK(layout1, refer_denied_by_default3)
+{
+       refer_denied_by_default(_metadata, layer_dir_s1d1_refer, 0,
+                               layer_dir_s2d1_execute);
+}
+
+/*
+ * Same test but this time turning around the ABI version order: the first
+ * layer does not handle LANDLOCK_ACCESS_FS_REFER.
+ */
+TEST_F_FORK(layout1, refer_denied_by_default4)
+{
+       refer_denied_by_default(_metadata, layer_dir_s2d1_execute, EXDEV,
+                               layer_dir_s1d1_refer);
+}
+
 TEST_F_FORK(layout1, reparent_link)
 {
        const struct rule layer1[] = {
@@ -2336,11 +2466,12 @@ TEST_F_FORK(layout1, reparent_exdev_layers_rename1)
        ASSERT_EQ(EXDEV, errno);
 
        /*
-        * However, moving the file2_s1d3 file below dir_s2d3 is allowed
-        * because it cannot inherit MAKE_REG nor MAKE_DIR rights (which are
-        * dedicated to directories).
+        * Moving the file2_s1d3 file below dir_s2d3 is denied because the
+        * second layer does not handle REFER, which is always denied by
+        * default.
         */
-       ASSERT_EQ(0, rename(file2_s1d3, file1_s2d3));
+       ASSERT_EQ(-1, rename(file2_s1d3, file1_s2d3));
+       ASSERT_EQ(EXDEV, errno);
 }
 
 TEST_F_FORK(layout1, reparent_exdev_layers_rename2)
@@ -2373,8 +2504,12 @@ TEST_F_FORK(layout1, reparent_exdev_layers_rename2)
        ASSERT_EQ(EACCES, errno);
        ASSERT_EQ(-1, rename(file1_s1d1, file1_s2d3));
        ASSERT_EQ(EXDEV, errno);
-       /* Modify layout! */
-       ASSERT_EQ(0, rename(file2_s1d2, file1_s2d3));
+       /*
+        * Modifying the layout is now denied because the second layer does not
+        * handle REFER, which is always denied by default.
+        */
+       ASSERT_EQ(-1, rename(file2_s1d2, file1_s2d3));
+       ASSERT_EQ(EXDEV, errno);
 
        /* Without REFER source, EACCES wins over EXDEV. */
        ASSERT_EQ(-1, rename(dir_s1d1, file1_s2d2));
index 947fc72..d44c72b 100644 (file)
@@ -40,6 +40,7 @@ ifeq (0,$(MAKELEVEL))
     endif
 endif
 selfdir = $(realpath $(dir $(filter %/lib.mk,$(MAKEFILE_LIST))))
+top_srcdir = $(selfdir)/../../..
 
 # The following are built by lib.mk common compile rules.
 # TEST_CUSTOM_PROGS should be used by tests that require
index 0e5751a..de7d5cc 100644 (file)
@@ -1,42 +1,42 @@
 # SPDX-License-Identifier: GPL-2.0-only
+cmsg_sender
+fin_ack_lat
+gro
+hwtstamp_config
+ioam6_parser
+ip_defrag
 ipsec
+ipv6_flowlabel
+ipv6_flowlabel_mgr
 msg_zerocopy
-socket
+nettest
 psock_fanout
 psock_snd
 psock_tpacket
-stress_reuseport_listen
+reuseaddr_conflict
+reuseaddr_ports_exhausted
 reuseport_addr_any
 reuseport_bpf
 reuseport_bpf_cpu
 reuseport_bpf_numa
 reuseport_dualstack
-reuseaddr_conflict
-tcp_mmap
-udpgso
-udpgso_bench_rx
-udpgso_bench_tx
-tcp_inq
-tls
-txring_overwrite
-ip_defrag
-ipv6_flowlabel
-ipv6_flowlabel_mgr
-so_txtime
-tcp_fastopen_backup_key
-nettest
-fin_ack_lat
-reuseaddr_ports_exhausted
-hwtstamp_config
 rxtimestamp
-timestamping
-txtimestamp
+socket
 so_netns_cookie
+so_txtime
+stress_reuseport_listen
+tap
+tcp_fastopen_backup_key
+tcp_inq
+tcp_mmap
 test_unix_oob
-gro
-ioam6_parser
+timestamping
+tls
 toeplitz
 tun
-cmsg_sender
+txring_overwrite
+txtimestamp
+udpgso
+udpgso_bench_rx
+udpgso_bench_tx
 unix_connect
-tap
\ No newline at end of file
index 9d64c56..8ce48ac 100644 (file)
@@ -47,7 +47,6 @@ enum {
        MODE_MIXED      = 3,
 };
 
-static bool cfg_flush          = false;
 static bool cfg_cork           = false;
 static int  cfg_mode           = MODE_ZC_FIXED;
 static int  cfg_nr_reqs                = 8;
@@ -166,21 +165,6 @@ static int io_uring_register_buffers(struct io_uring *ring,
        return (ret < 0) ? -errno : ret;
 }
 
-static int io_uring_register_notifications(struct io_uring *ring,
-                                          unsigned nr,
-                                          struct io_uring_notification_slot *slots)
-{
-       int ret;
-       struct io_uring_notification_register r = {
-               .nr_slots = nr,
-               .data = (unsigned long)slots,
-       };
-
-       ret = syscall(__NR_io_uring_register, ring->ring_fd,
-                     IORING_REGISTER_NOTIFIERS, &r, sizeof(r));
-       return (ret < 0) ? -errno : ret;
-}
-
 static int io_uring_mmap(int fd, struct io_uring_params *p,
                         struct io_uring_sq *sq, struct io_uring_cq *cq)
 {
@@ -297,11 +281,10 @@ static inline void io_uring_prep_send(struct io_uring_sqe *sqe, int sockfd,
 
 static inline void io_uring_prep_sendzc(struct io_uring_sqe *sqe, int sockfd,
                                        const void *buf, size_t len, int flags,
-                                       unsigned slot_idx, unsigned zc_flags)
+                                       unsigned zc_flags)
 {
        io_uring_prep_send(sqe, sockfd, buf, len, flags);
-       sqe->opcode = (__u8) IORING_OP_SENDZC_NOTIF;
-       sqe->notification_idx = slot_idx;
+       sqe->opcode = (__u8) IORING_OP_SEND_ZC;
        sqe->ioprio = zc_flags;
 }
 
@@ -374,7 +357,6 @@ static int do_setup_tx(int domain, int type, int protocol)
 
 static void do_tx(int domain, int type, int protocol)
 {
-       struct io_uring_notification_slot b[1] = {{.tag = NOTIF_TAG}};
        struct io_uring_sqe *sqe;
        struct io_uring_cqe *cqe;
        unsigned long packets = 0, bytes = 0;
@@ -390,10 +372,6 @@ static void do_tx(int domain, int type, int protocol)
        if (ret)
                error(1, ret, "io_uring: queue init");
 
-       ret = io_uring_register_notifications(&ring, 1, b);
-       if (ret)
-               error(1, ret, "io_uring: tx ctx registration");
-
        iov.iov_base = payload;
        iov.iov_len = cfg_payload_len;
 
@@ -409,9 +387,8 @@ static void do_tx(int domain, int type, int protocol)
                for (i = 0; i < cfg_nr_reqs; i++) {
                        unsigned zc_flags = 0;
                        unsigned buf_idx = 0;
-                       unsigned slot_idx = 0;
                        unsigned mode = cfg_mode;
-                       unsigned msg_flags = 0;
+                       unsigned msg_flags = MSG_WAITALL;
 
                        if (cfg_mode == MODE_MIXED)
                                mode = rand() % 3;
@@ -423,13 +400,10 @@ static void do_tx(int domain, int type, int protocol)
                                                   cfg_payload_len, msg_flags);
                                sqe->user_data = NONZC_TAG;
                        } else {
-                               if (cfg_flush) {
-                                       zc_flags |= IORING_RECVSEND_NOTIF_FLUSH;
-                                       compl_cqes++;
-                               }
+                               compl_cqes++;
                                io_uring_prep_sendzc(sqe, fd, payload,
                                                     cfg_payload_len,
-                                                    msg_flags, slot_idx, zc_flags);
+                                                    msg_flags, zc_flags);
                                if (mode == MODE_ZC_FIXED) {
                                        sqe->ioprio |= IORING_RECVSEND_FIXED_BUF;
                                        sqe->buf_index = buf_idx;
@@ -442,51 +416,57 @@ static void do_tx(int domain, int type, int protocol)
                if (ret != cfg_nr_reqs)
                        error(1, ret, "submit");
 
+               if (cfg_cork)
+                       do_setsockopt(fd, IPPROTO_UDP, UDP_CORK, 0);
                for (i = 0; i < cfg_nr_reqs; i++) {
                        ret = io_uring_wait_cqe(&ring, &cqe);
                        if (ret)
                                error(1, ret, "wait cqe");
 
-                       if (cqe->user_data == NOTIF_TAG) {
+                       if (cqe->user_data != NONZC_TAG &&
+                           cqe->user_data != ZC_TAG)
+                               error(1, -EINVAL, "invalid cqe->user_data");
+
+                       if (cqe->flags & IORING_CQE_F_NOTIF) {
+                               if (cqe->flags & IORING_CQE_F_MORE)
+                                       error(1, -EINVAL, "invalid notif flags");
                                compl_cqes--;
                                i--;
-                       } else if (cqe->user_data != NONZC_TAG &&
-                                  cqe->user_data != ZC_TAG) {
-                               error(1, cqe->res, "invalid user_data");
-                       } else if (cqe->res <= 0 && cqe->res != -EAGAIN) {
+                       } else if (cqe->res <= 0) {
+                               if (cqe->flags & IORING_CQE_F_MORE)
+                                       error(1, cqe->res, "more with a failed send");
                                error(1, cqe->res, "send failed");
                        } else {
-                               if (cqe->res > 0) {
-                                       packets++;
-                                       bytes += cqe->res;
-                               }
-                               /* failed requests don't flush */
-                               if (cfg_flush &&
-                                   cqe->res <= 0 &&
-                                   cqe->user_data == ZC_TAG)
-                                       compl_cqes--;
+                               if (cqe->user_data == ZC_TAG &&
+                                   !(cqe->flags & IORING_CQE_F_MORE))
+                                       error(1, cqe->res, "missing more flag");
+                               packets++;
+                               bytes += cqe->res;
                        }
                        io_uring_cqe_seen(&ring);
                }
-               if (cfg_cork)
-                       do_setsockopt(fd, IPPROTO_UDP, UDP_CORK, 0);
        } while (gettimeofday_ms() < tstop);
 
-       if (close(fd))
-               error(1, errno, "close");
-
-       fprintf(stderr, "tx=%lu (MB=%lu), tx/s=%lu (MB/s=%lu)\n",
-                       packets, bytes >> 20,
-                       packets / (cfg_runtime_ms / 1000),
-                       (bytes >> 20) / (cfg_runtime_ms / 1000));
-
        while (compl_cqes) {
                ret = io_uring_wait_cqe(&ring, &cqe);
                if (ret)
                        error(1, ret, "wait cqe");
+               if (cqe->flags & IORING_CQE_F_MORE)
+                       error(1, -EINVAL, "invalid notif flags");
+               if (!(cqe->flags & IORING_CQE_F_NOTIF))
+                       error(1, -EINVAL, "missing notif flag");
+
                io_uring_cqe_seen(&ring);
                compl_cqes--;
        }
+
+       fprintf(stderr, "tx=%lu (MB=%lu), tx/s=%lu (MB/s=%lu)\n",
+                       packets, bytes >> 20,
+                       packets / (cfg_runtime_ms / 1000),
+                       (bytes >> 20) / (cfg_runtime_ms / 1000));
+
+       if (close(fd))
+               error(1, errno, "close");
 }
 
 static void do_test(int domain, int type, int protocol)
@@ -500,8 +480,8 @@ static void do_test(int domain, int type, int protocol)
 
 static void usage(const char *filepath)
 {
-       error(1, 0, "Usage: %s [-f] [-n<N>] [-z0] [-s<payload size>] "
-                   "(-4|-6) [-t<time s>] -D<dst_ip> udp", filepath);
+       error(1, 0, "Usage: %s (-4|-6) (udp|tcp) -D<dst_ip> [-s<payload size>] "
+                   "[-t<time s>] [-n<batch>] [-p<port>] [-m<mode>]", filepath);
 }
 
 static void parse_opts(int argc, char **argv)
@@ -519,7 +499,7 @@ static void parse_opts(int argc, char **argv)
                usage(argv[0]);
        cfg_payload_len = max_payload_len;
 
-       while ((c = getopt(argc, argv, "46D:p:s:t:n:fc:m:")) != -1) {
+       while ((c = getopt(argc, argv, "46D:p:s:t:n:c:m:")) != -1) {
                switch (c) {
                case '4':
                        if (cfg_family != PF_UNSPEC)
@@ -548,9 +528,6 @@ static void parse_opts(int argc, char **argv)
                case 'n':
                        cfg_nr_reqs = strtoul(optarg, NULL, 0);
                        break;
-               case 'f':
-                       cfg_flush = 1;
-                       break;
                case 'c':
                        cfg_cork = strtol(optarg, NULL, 0);
                        break;
@@ -583,8 +560,6 @@ static void parse_opts(int argc, char **argv)
 
        if (cfg_payload_len > max_payload_len)
                error(1, 0, "-s: payload exceeds max (%d)", max_payload_len);
-       if (cfg_mode == MODE_NONZC && cfg_flush)
-               error(1, 0, "-f: only zerocopy modes support notifications");
        if (optind != argc - 1)
                usage(argv[0]);
 }
index 6a65e44..32aa6e9 100755 (executable)
@@ -25,15 +25,11 @@ readonly path_sysctl_mem="net.core.optmem_max"
 # No arguments: automated test
 if [[ "$#" -eq "0" ]]; then
        IPs=( "4" "6" )
-       protocols=( "tcp" "udp" )
 
        for IP in "${IPs[@]}"; do
-               for proto in "${protocols[@]}"; do
-                       for mode in $(seq 1 3); do
-                               $0 "$IP" "$proto" -m "$mode" -t 1 -n 32
-                               $0 "$IP" "$proto" -m "$mode" -t 1 -n 32 -f
-                               $0 "$IP" "$proto" -m "$mode" -t 1 -n 32 -c -f
-                       done
+               for mode in $(seq 1 3); do
+                       $0 "$IP" udp -m "$mode" -t 1 -n 32
+                       $0 "$IP" tcp -m "$mode" -t 1 -n 32
                done
        done
 
index bf6b962..faa7778 100755 (executable)
@@ -102,26 +102,42 @@ check_for_helper()
 
        ip netns exec ${netns} conntrack -L -f $family -p tcp --dport $port 2> /dev/null |grep -q 'helper=ftp'
        if [ $? -ne 0 ] ; then
-               echo "FAIL: ${netns} did not show attached helper $message" 1>&2
-               ret=1
+               if [ $autoassign -eq 0 ] ;then
+                       echo "FAIL: ${netns} did not show attached helper $message" 1>&2
+                       ret=1
+               else
+                       echo "PASS: ${netns} did not show attached helper $message" 1>&2
+               fi
+       else
+               if [ $autoassign -eq 0 ] ;then
+                       echo "PASS: ${netns} connection on port $port has ftp helper attached" 1>&2
+               else
+                       echo "FAIL: ${netns} connection on port $port has ftp helper attached" 1>&2
+                       ret=1
+               fi
        fi
 
-       echo "PASS: ${netns} connection on port $port has ftp helper attached" 1>&2
        return 0
 }
 
 test_helper()
 {
        local port=$1
-       local msg=$2
+       local autoassign=$2
+
+       if [ $autoassign -eq 0 ] ;then
+               msg="set via ruleset"
+       else
+               msg="auto-assign"
+       fi
 
        sleep 3 | ip netns exec ${ns2} nc -w 2 -l -p $port > /dev/null &
 
        sleep 1 | ip netns exec ${ns1} nc -w 2 10.0.1.2 $port > /dev/null &
        sleep 1
 
-       check_for_helper "$ns1" "ip $msg" $port
-       check_for_helper "$ns2" "ip $msg" $port
+       check_for_helper "$ns1" "ip $msg" $port $autoassign
+       check_for_helper "$ns2" "ip $msg" $port $autoassign
 
        wait
 
@@ -173,9 +189,9 @@ if [ $? -ne 0 ];then
        fi
 fi
 
-test_helper 2121 "set via ruleset"
-ip netns exec ${ns1} sysctl -q 'net.netfilter.nf_conntrack_helper=1'
-ip netns exec ${ns2} sysctl -q 'net.netfilter.nf_conntrack_helper=1'
-test_helper 21 "auto-assign"
+test_helper 2121 0
+ip netns exec ${ns1} sysctl -qe 'net.netfilter.nf_conntrack_helper=1'
+ip netns exec ${ns2} sysctl -qe 'net.netfilter.nf_conntrack_helper=1'
+test_helper 21 1
 
 exit $ret
index d4ffebb..7060bae 100755 (executable)
 # nft_flowtable.sh -o8000 -l1500 -r2000
 #
 
+sfx=$(mktemp -u "XXXXXXXX")
+ns1="ns1-$sfx"
+ns2="ns2-$sfx"
+nsr1="nsr1-$sfx"
+nsr2="nsr2-$sfx"
 
 # Kselftest framework requirement - SKIP code is 4.
 ksft_skip=4
 ret=0
 
-ns1in=""
-ns2in=""
+nsin=""
 ns1out=""
 ns2out=""
 
@@ -36,21 +40,19 @@ checktool (){
 checktool "nft --version" "run test without nft tool"
 checktool "ip -Version" "run test without ip tool"
 checktool "which nc" "run test without nc (netcat)"
-checktool "ip netns add nsr1" "create net namespace"
+checktool "ip netns add $nsr1" "create net namespace $nsr1"
 
-ip netns add ns1
-ip netns add ns2
-
-ip netns add nsr2
+ip netns add $ns1
+ip netns add $ns2
+ip netns add $nsr2
 
 cleanup() {
-       for i in 1 2; do
-               ip netns del ns$i
-               ip netns del nsr$i
-       done
+       ip netns del $ns1
+       ip netns del $ns2
+       ip netns del $nsr1
+       ip netns del $nsr2
 
-       rm -f "$ns1in" "$ns1out"
-       rm -f "$ns2in" "$ns2out"
+       rm -f "$nsin" "$ns1out" "$ns2out"
 
        [ $log_netns -eq 0 ] && sysctl -q net.netfilter.nf_log_all_netns=$log_netns
 }
@@ -59,22 +61,21 @@ trap cleanup EXIT
 
 sysctl -q net.netfilter.nf_log_all_netns=1
 
-ip link add veth0 netns nsr1 type veth peer name eth0 netns ns1
-ip link add veth1 netns nsr1 type veth peer name veth0 netns nsr2
+ip link add veth0 netns $nsr1 type veth peer name eth0 netns $ns1
+ip link add veth1 netns $nsr1 type veth peer name veth0 netns $nsr2
 
-ip link add veth1 netns nsr2 type veth peer name eth0 netns ns2
+ip link add veth1 netns $nsr2 type veth peer name eth0 netns $ns2
 
 for dev in lo veth0 veth1; do
-  for i in 1 2; do
-    ip -net nsr$i link set $dev up
-  done
+    ip -net $nsr1 link set $dev up
+    ip -net $nsr2 link set $dev up
 done
 
-ip -net nsr1 addr add 10.0.1.1/24 dev veth0
-ip -net nsr1 addr add dead:1::1/64 dev veth0
+ip -net $nsr1 addr add 10.0.1.1/24 dev veth0
+ip -net $nsr1 addr add dead:1::1/64 dev veth0
 
-ip -net nsr2 addr add 10.0.2.1/24 dev veth1
-ip -net nsr2 addr add dead:2::1/64 dev veth1
+ip -net $nsr2 addr add 10.0.2.1/24 dev veth1
+ip -net $nsr2 addr add dead:2::1/64 dev veth1
 
 # set different MTUs so we need to push packets coming from ns1 (large MTU)
 # to ns2 (smaller MTU) to stack either to perform fragmentation (ip_no_pmtu_disc=1),
@@ -106,85 +107,76 @@ do
        esac
 done
 
-if ! ip -net nsr1 link set veth0 mtu $omtu; then
+if ! ip -net $nsr1 link set veth0 mtu $omtu; then
        exit 1
 fi
 
-ip -net ns1 link set eth0 mtu $omtu
+ip -net $ns1 link set eth0 mtu $omtu
 
-if ! ip -net nsr2 link set veth1 mtu $rmtu; then
+if ! ip -net $nsr2 link set veth1 mtu $rmtu; then
        exit 1
 fi
 
-ip -net ns2 link set eth0 mtu $rmtu
+ip -net $ns2 link set eth0 mtu $rmtu
 
 # transfer-net between nsr1 and nsr2.
 # these addresses are not used for connections.
-ip -net nsr1 addr add 192.168.10.1/24 dev veth1
-ip -net nsr1 addr add fee1:2::1/64 dev veth1
-
-ip -net nsr2 addr add 192.168.10.2/24 dev veth0
-ip -net nsr2 addr add fee1:2::2/64 dev veth0
-
-for i in 1 2; do
-  ip netns exec nsr$i sysctl net.ipv4.conf.veth0.forwarding=1 > /dev/null
-  ip netns exec nsr$i sysctl net.ipv4.conf.veth1.forwarding=1 > /dev/null
-
-  ip -net ns$i link set lo up
-  ip -net ns$i link set eth0 up
-  ip -net ns$i addr add 10.0.$i.99/24 dev eth0
-  ip -net ns$i route add default via 10.0.$i.1
-  ip -net ns$i addr add dead:$i::99/64 dev eth0
-  ip -net ns$i route add default via dead:$i::1
-  if ! ip netns exec ns$i sysctl net.ipv4.tcp_no_metrics_save=1 > /dev/null; then
+ip -net $nsr1 addr add 192.168.10.1/24 dev veth1
+ip -net $nsr1 addr add fee1:2::1/64 dev veth1
+
+ip -net $nsr2 addr add 192.168.10.2/24 dev veth0
+ip -net $nsr2 addr add fee1:2::2/64 dev veth0
+
+for i in 0 1; do
+  ip netns exec $nsr1 sysctl net.ipv4.conf.veth$i.forwarding=1 > /dev/null
+  ip netns exec $nsr2 sysctl net.ipv4.conf.veth$i.forwarding=1 > /dev/null
+done
+
+for ns in $ns1 $ns2;do
+  ip -net $ns link set lo up
+  ip -net $ns link set eth0 up
+
+  if ! ip netns exec $ns sysctl net.ipv4.tcp_no_metrics_save=1 > /dev/null; then
        echo "ERROR: Check Originator/Responder values (problem during address addition)"
        exit 1
   fi
-
   # don't set ip DF bit for first two tests
-  ip netns exec ns$i sysctl net.ipv4.ip_no_pmtu_disc=1 > /dev/null
+  ip netns exec $ns sysctl net.ipv4.ip_no_pmtu_disc=1 > /dev/null
 done
 
-ip -net nsr1 route add default via 192.168.10.2
-ip -net nsr2 route add default via 192.168.10.1
+ip -net $ns1 addr add 10.0.1.99/24 dev eth0
+ip -net $ns2 addr add 10.0.2.99/24 dev eth0
+ip -net $ns1 route add default via 10.0.1.1
+ip -net $ns2 route add default via 10.0.2.1
+ip -net $ns1 addr add dead:1::99/64 dev eth0
+ip -net $ns2 addr add dead:2::99/64 dev eth0
+ip -net $ns1 route add default via dead:1::1
+ip -net $ns2 route add default via dead:2::1
+
+ip -net $nsr1 route add default via 192.168.10.2
+ip -net $nsr2 route add default via 192.168.10.1
 
-ip netns exec nsr1 nft -f - <<EOF
+ip netns exec $nsr1 nft -f - <<EOF
 table inet filter {
   flowtable f1 {
      hook ingress priority 0
      devices = { veth0, veth1 }
    }
 
+   counter routed_orig { }
+   counter routed_repl { }
+
    chain forward {
       type filter hook forward priority 0; policy drop;
 
       # flow offloaded? Tag ct with mark 1, so we can detect when it fails.
-      meta oif "veth1" tcp dport 12345 flow offload @f1 counter
-
-      # use packet size to trigger 'should be offloaded by now'.
-      # otherwise, if 'flow offload' expression never offloads, the
-      # test will pass.
-      tcp dport 12345 meta length gt 200 ct mark set 1 counter
+      meta oif "veth1" tcp dport 12345 ct mark set 1 flow add @f1 counter name routed_orig accept
 
-      # this turns off flow offloading internally, so expect packets again
-      tcp flags fin,rst ct mark set 0 accept
-
-      # this allows large packets from responder, we need this as long
-      # as PMTUd is off.
-      # This rule is deleted for the last test, when we expect PMTUd
-      # to kick in and ensure all packets meet mtu requirements.
-      meta length gt $lmtu accept comment something-to-grep-for
-
-      # next line blocks connection w.o. working offload.
-      # we only do this for reverse dir, because we expect packets to
-      # enter slow path due to MTU mismatch of veth0 and veth1.
-      tcp sport 12345 ct mark 1 counter log prefix "mark failure " drop
+      # count packets supposedly offloaded as per direction.
+      ct mark 1 counter name ct direction map { original : routed_orig, reply : routed_repl } accept
 
       ct state established,related accept
 
-      # for packets that we can't offload yet, i.e. SYN (any ct that is not confirmed)
-      meta length lt 200 oif "veth1" tcp dport 12345 counter accept
-
       meta nfproto ipv4 meta l4proto icmp accept
       meta nfproto ipv6 meta l4proto icmpv6 accept
    }
@@ -197,30 +189,30 @@ if [ $? -ne 0 ]; then
 fi
 
 # test basic connectivity
-if ! ip netns exec ns1 ping -c 1 -q 10.0.2.99 > /dev/null; then
-  echo "ERROR: ns1 cannot reach ns2" 1>&2
+if ! ip netns exec $ns1 ping -c 1 -q 10.0.2.99 > /dev/null; then
+  echo "ERROR: $ns1 cannot reach ns2" 1>&2
   exit 1
 fi
 
-if ! ip netns exec ns2 ping -c 1 -q 10.0.1.99 > /dev/null; then
-  echo "ERROR: ns2 cannot reach ns1" 1>&2
+if ! ip netns exec $ns2 ping -c 1 -q 10.0.1.99 > /dev/null; then
+  echo "ERROR: $ns2 cannot reach $ns1" 1>&2
   exit 1
 fi
 
 if [ $ret -eq 0 ];then
-       echo "PASS: netns routing/connectivity: ns1 can reach ns2"
+       echo "PASS: netns routing/connectivity: $ns1 can reach $ns2"
 fi
 
-ns1in=$(mktemp)
+nsin=$(mktemp)
 ns1out=$(mktemp)
-ns2in=$(mktemp)
 ns2out=$(mktemp)
 
 make_file()
 {
        name=$1
 
-       SIZE=$((RANDOM % (1024 * 8)))
+       SIZE=$((RANDOM % (1024 * 128)))
+       SIZE=$((SIZE + (1024 * 8)))
        TSIZE=$((SIZE * 1024))
 
        dd if=/dev/urandom of="$name" bs=1024 count=$SIZE 2> /dev/null
@@ -231,6 +223,38 @@ make_file()
        dd if=/dev/urandom conf=notrunc of="$name" bs=1 count=$SIZE 2> /dev/null
 }
 
+check_counters()
+{
+       local what=$1
+       local ok=1
+
+       local orig=$(ip netns exec $nsr1 nft reset counter inet filter routed_orig | grep packets)
+       local repl=$(ip netns exec $nsr1 nft reset counter inet filter routed_repl | grep packets)
+
+       local orig_cnt=${orig#*bytes}
+       local repl_cnt=${repl#*bytes}
+
+       local fs=$(du -sb $nsin)
+       local max_orig=${fs%%/*}
+       local max_repl=$((max_orig/4))
+
+       if [ $orig_cnt -gt $max_orig ];then
+               echo "FAIL: $what: original counter $orig_cnt exceeds expected value $max_orig" 1>&2
+               ret=1
+               ok=0
+       fi
+
+       if [ $repl_cnt -gt $max_repl ];then
+               echo "FAIL: $what: reply counter $repl_cnt exceeds expected value $max_repl" 1>&2
+               ret=1
+               ok=0
+       fi
+
+       if [ $ok -eq 1 ]; then
+               echo "PASS: $what"
+       fi
+}
+
 check_transfer()
 {
        in=$1
@@ -255,11 +279,11 @@ test_tcp_forwarding_ip()
        local dstport=$4
        local lret=0
 
-       ip netns exec $nsb nc -w 5 -l -p 12345 < "$ns2in" > "$ns2out" &
+       ip netns exec $nsb nc -w 5 -l -p 12345 < "$nsin" > "$ns2out" &
        lpid=$!
 
        sleep 1
-       ip netns exec $nsa nc -w 4 "$dstip" "$dstport" < "$ns1in" > "$ns1out" &
+       ip netns exec $nsa nc -w 4 "$dstip" "$dstport" < "$nsin" > "$ns1out" &
        cpid=$!
 
        sleep 3
@@ -274,11 +298,11 @@ test_tcp_forwarding_ip()
 
        wait
 
-       if ! check_transfer "$ns1in" "$ns2out" "ns1 -> ns2"; then
+       if ! check_transfer "$nsin" "$ns2out" "ns1 -> ns2"; then
                lret=1
        fi
 
-       if ! check_transfer "$ns2in" "$ns1out" "ns1 <- ns2"; then
+       if ! check_transfer "$nsin" "$ns1out" "ns1 <- ns2"; then
                lret=1
        fi
 
@@ -295,41 +319,59 @@ test_tcp_forwarding()
 test_tcp_forwarding_nat()
 {
        local lret
+       local pmtu
 
        test_tcp_forwarding_ip "$1" "$2" 10.0.2.99 12345
        lret=$?
 
+       pmtu=$3
+       what=$4
+
        if [ $lret -eq 0 ] ; then
+               if [ $pmtu -eq 1 ] ;then
+                       check_counters "flow offload for ns1/ns2 with masquerade and pmtu discovery $what"
+               else
+                       echo "PASS: flow offload for ns1/ns2 with masquerade $what"
+               fi
+
                test_tcp_forwarding_ip "$1" "$2" 10.6.6.6 1666
                lret=$?
+               if [ $pmtu -eq 1 ] ;then
+                       check_counters "flow offload for ns1/ns2 with dnat and pmtu discovery $what"
+               elif [ $lret -eq 0 ] ; then
+                       echo "PASS: flow offload for ns1/ns2 with dnat $what"
+               fi
        fi
 
        return $lret
 }
 
-make_file "$ns1in"
-make_file "$ns2in"
+make_file "$nsin"
 
 # First test:
 # No PMTU discovery, nsr1 is expected to fragment packets from ns1 to ns2 as needed.
-if test_tcp_forwarding ns1 ns2; then
+# Due to MTU mismatch in both directions, all packets (except small packets like pure
+# acks) have to be handled by normal forwarding path.  Therefore, packet counters
+# are not checked.
+if test_tcp_forwarding $ns1 $ns2; then
        echo "PASS: flow offloaded for ns1/ns2"
 else
        echo "FAIL: flow offload for ns1/ns2:" 1>&2
-       ip netns exec nsr1 nft list ruleset
+       ip netns exec $nsr1 nft list ruleset
        ret=1
 fi
 
 # delete default route, i.e. ns2 won't be able to reach ns1 and
 # will depend on ns1 being masqueraded in nsr1.
 # expect ns1 has nsr1 address.
-ip -net ns2 route del default via 10.0.2.1
-ip -net ns2 route del default via dead:2::1
-ip -net ns2 route add 192.168.10.1 via 10.0.2.1
+ip -net $ns2 route del default via 10.0.2.1
+ip -net $ns2 route del default via dead:2::1
+ip -net $ns2 route add 192.168.10.1 via 10.0.2.1
 
 # Second test:
-# Same, but with NAT enabled.
-ip netns exec nsr1 nft -f - <<EOF
+# Same, but with NAT enabled.  Same as in first test: we expect normal forward path
+# to handle most packets.
+ip netns exec $nsr1 nft -f - <<EOF
 table ip nat {
    chain prerouting {
       type nat hook prerouting priority 0; policy accept;
@@ -343,47 +385,45 @@ table ip nat {
 }
 EOF
 
-if test_tcp_forwarding_nat ns1 ns2; then
-       echo "PASS: flow offloaded for ns1/ns2 with NAT"
-else
+if ! test_tcp_forwarding_nat $ns1 $ns2 0 ""; then
        echo "FAIL: flow offload for ns1/ns2 with NAT" 1>&2
-       ip netns exec nsr1 nft list ruleset
+       ip netns exec $nsr1 nft list ruleset
        ret=1
 fi
 
 # Third test:
-# Same as second test, but with PMTU discovery enabled.
-handle=$(ip netns exec nsr1 nft -a list table inet filter | grep something-to-grep-for | cut -d \# -f 2)
-
-if ! ip netns exec nsr1 nft delete rule inet filter forward $handle; then
-       echo "FAIL: Could not delete large-packet accept rule"
-       exit 1
-fi
-
-ip netns exec ns1 sysctl net.ipv4.ip_no_pmtu_disc=0 > /dev/null
-ip netns exec ns2 sysctl net.ipv4.ip_no_pmtu_disc=0 > /dev/null
-
-if test_tcp_forwarding_nat ns1 ns2; then
-       echo "PASS: flow offloaded for ns1/ns2 with NAT and pmtu discovery"
-else
+# Same as second test, but with PMTU discovery enabled. This
+# means that we expect the fastpath to handle packets as soon
+# as the endpoints adjust the packet size.
+ip netns exec $ns1 sysctl net.ipv4.ip_no_pmtu_disc=0 > /dev/null
+ip netns exec $ns2 sysctl net.ipv4.ip_no_pmtu_disc=0 > /dev/null
+
+# reset counters.
+# With pmtu in-place we'll also check that nft counters
+# are lower than file size and packets were forwarded via flowtable layer.
+# For earlier tests (large mtus), packets cannot be handled via flowtable
+# (except pure acks and other small packets).
+ip netns exec $nsr1 nft reset counters table inet filter >/dev/null
+
+if ! test_tcp_forwarding_nat $ns1 $ns2 1 ""; then
        echo "FAIL: flow offload for ns1/ns2 with NAT and pmtu discovery" 1>&2
-       ip netns exec nsr1 nft list ruleset
+       ip netns exec $nsr1 nft list ruleset
 fi
 
 # Another test:
 # Add bridge interface br0 to Router1, with NAT enabled.
-ip -net nsr1 link add name br0 type bridge
-ip -net nsr1 addr flush dev veth0
-ip -net nsr1 link set up dev veth0
-ip -net nsr1 link set veth0 master br0
-ip -net nsr1 addr add 10.0.1.1/24 dev br0
-ip -net nsr1 addr add dead:1::1/64 dev br0
-ip -net nsr1 link set up dev br0
+ip -net $nsr1 link add name br0 type bridge
+ip -net $nsr1 addr flush dev veth0
+ip -net $nsr1 link set up dev veth0
+ip -net $nsr1 link set veth0 master br0
+ip -net $nsr1 addr add 10.0.1.1/24 dev br0
+ip -net $nsr1 addr add dead:1::1/64 dev br0
+ip -net $nsr1 link set up dev br0
 
-ip netns exec nsr1 sysctl net.ipv4.conf.br0.forwarding=1 > /dev/null
+ip netns exec $nsr1 sysctl net.ipv4.conf.br0.forwarding=1 > /dev/null
 
 # br0 with NAT enabled.
-ip netns exec nsr1 nft -f - <<EOF
+ip netns exec $nsr1 nft -f - <<EOF
 flush table ip nat
 table ip nat {
    chain prerouting {
@@ -398,59 +438,56 @@ table ip nat {
 }
 EOF
 
-if test_tcp_forwarding_nat ns1 ns2; then
-       echo "PASS: flow offloaded for ns1/ns2 with bridge NAT"
-else
+if ! test_tcp_forwarding_nat $ns1 $ns2 1 "on bridge"; then
        echo "FAIL: flow offload for ns1/ns2 with bridge NAT" 1>&2
-       ip netns exec nsr1 nft list ruleset
+       ip netns exec $nsr1 nft list ruleset
        ret=1
 fi
 
+
 # Another test:
 # Add bridge interface br0 to Router1, with NAT and VLAN.
-ip -net nsr1 link set veth0 nomaster
-ip -net nsr1 link set down dev veth0
-ip -net nsr1 link add link veth0 name veth0.10 type vlan id 10
-ip -net nsr1 link set up dev veth0
-ip -net nsr1 link set up dev veth0.10
-ip -net nsr1 link set veth0.10 master br0
-
-ip -net ns1 addr flush dev eth0
-ip -net ns1 link add link eth0 name eth0.10 type vlan id 10
-ip -net ns1 link set eth0 up
-ip -net ns1 link set eth0.10 up
-ip -net ns1 addr add 10.0.1.99/24 dev eth0.10
-ip -net ns1 route add default via 10.0.1.1
-ip -net ns1 addr add dead:1::99/64 dev eth0.10
-
-if test_tcp_forwarding_nat ns1 ns2; then
-       echo "PASS: flow offloaded for ns1/ns2 with bridge NAT and VLAN"
-else
+ip -net $nsr1 link set veth0 nomaster
+ip -net $nsr1 link set down dev veth0
+ip -net $nsr1 link add link veth0 name veth0.10 type vlan id 10
+ip -net $nsr1 link set up dev veth0
+ip -net $nsr1 link set up dev veth0.10
+ip -net $nsr1 link set veth0.10 master br0
+
+ip -net $ns1 addr flush dev eth0
+ip -net $ns1 link add link eth0 name eth0.10 type vlan id 10
+ip -net $ns1 link set eth0 up
+ip -net $ns1 link set eth0.10 up
+ip -net $ns1 addr add 10.0.1.99/24 dev eth0.10
+ip -net $ns1 route add default via 10.0.1.1
+ip -net $ns1 addr add dead:1::99/64 dev eth0.10
+
+if ! test_tcp_forwarding_nat $ns1 $ns2 1 "bridge and VLAN"; then
        echo "FAIL: flow offload for ns1/ns2 with bridge NAT and VLAN" 1>&2
-       ip netns exec nsr1 nft list ruleset
+       ip netns exec $nsr1 nft list ruleset
        ret=1
 fi
 
 # restore test topology (remove bridge and VLAN)
-ip -net nsr1 link set veth0 nomaster
-ip -net nsr1 link set veth0 down
-ip -net nsr1 link set veth0.10 down
-ip -net nsr1 link delete veth0.10 type vlan
-ip -net nsr1 link delete br0 type bridge
-ip -net ns1 addr flush dev eth0.10
-ip -net ns1 link set eth0.10 down
-ip -net ns1 link set eth0 down
-ip -net ns1 link delete eth0.10 type vlan
+ip -net $nsr1 link set veth0 nomaster
+ip -net $nsr1 link set veth0 down
+ip -net $nsr1 link set veth0.10 down
+ip -net $nsr1 link delete veth0.10 type vlan
+ip -net $nsr1 link delete br0 type bridge
+ip -net $ns1 addr flush dev eth0.10
+ip -net $ns1 link set eth0.10 down
+ip -net $ns1 link set eth0 down
+ip -net $ns1 link delete eth0.10 type vlan
 
 # restore address in ns1 and nsr1
-ip -net ns1 link set eth0 up
-ip -net ns1 addr add 10.0.1.99/24 dev eth0
-ip -net ns1 route add default via 10.0.1.1
-ip -net ns1 addr add dead:1::99/64 dev eth0
-ip -net ns1 route add default via dead:1::1
-ip -net nsr1 addr add 10.0.1.1/24 dev veth0
-ip -net nsr1 addr add dead:1::1/64 dev veth0
-ip -net nsr1 link set up dev veth0
+ip -net $ns1 link set eth0 up
+ip -net $ns1 addr add 10.0.1.99/24 dev eth0
+ip -net $ns1 route add default via 10.0.1.1
+ip -net $ns1 addr add dead:1::99/64 dev eth0
+ip -net $ns1 route add default via dead:1::1
+ip -net $nsr1 addr add 10.0.1.1/24 dev veth0
+ip -net $nsr1 addr add dead:1::1/64 dev veth0
+ip -net $nsr1 link set up dev veth0
 
 KEY_SHA="0x"$(ps -xaf | sha1sum | cut -d " " -f 1)
 KEY_AES="0x"$(ps -xaf | md5sum | cut -d " " -f 1)
@@ -480,23 +517,23 @@ do_esp() {
 
 }
 
-do_esp nsr1 192.168.10.1 192.168.10.2 10.0.1.0/24 10.0.2.0/24 $SPI1 $SPI2
+do_esp $nsr1 192.168.10.1 192.168.10.2 10.0.1.0/24 10.0.2.0/24 $SPI1 $SPI2
 
-do_esp nsr2 192.168.10.2 192.168.10.1 10.0.2.0/24 10.0.1.0/24 $SPI2 $SPI1
+do_esp $nsr2 192.168.10.2 192.168.10.1 10.0.2.0/24 10.0.1.0/24 $SPI2 $SPI1
 
-ip netns exec nsr1 nft delete table ip nat
+ip netns exec $nsr1 nft delete table ip nat
 
 # restore default routes
-ip -net ns2 route del 192.168.10.1 via 10.0.2.1
-ip -net ns2 route add default via 10.0.2.1
-ip -net ns2 route add default via dead:2::1
+ip -net $ns2 route del 192.168.10.1 via 10.0.2.1
+ip -net $ns2 route add default via 10.0.2.1
+ip -net $ns2 route add default via dead:2::1
 
-if test_tcp_forwarding ns1 ns2; then
-       echo "PASS: ipsec tunnel mode for ns1/ns2"
+if test_tcp_forwarding $ns1 $ns2; then
+       check_counters "ipsec tunnel mode for ns1/ns2"
 else
        echo "FAIL: ipsec tunnel mode for ns1/ns2"
-       ip netns exec nsr1 nft list ruleset 1>&2
-       ip netns exec nsr1 cat /proc/net/xfrm_stat 1>&2
+       ip netns exec $nsr1 nft list ruleset 1>&2
+       ip netns exec $nsr1 cat /proc/net/xfrm_stat 1>&2
 fi
 
 exit $ret
diff --git a/tools/testing/selftests/powerpc/pmu/event_code_tests/.gitignore b/tools/testing/selftests/powerpc/pmu/event_code_tests/.gitignore
new file mode 100644 (file)
index 0000000..5710683
--- /dev/null
@@ -0,0 +1,20 @@
+blacklisted_events_test
+event_alternatives_tests_p10
+event_alternatives_tests_p9
+generic_events_valid_test
+group_constraint_cache_test
+group_constraint_l2l3_sel_test
+group_constraint_mmcra_sample_test
+group_constraint_pmc56_test
+group_constraint_pmc_count_test
+group_constraint_radix_scope_qual_test
+group_constraint_repeat_test
+group_constraint_thresh_cmp_test
+group_constraint_thresh_ctl_test
+group_constraint_thresh_sel_test
+group_constraint_unit_test
+group_pmc56_exclude_constraints_test
+hw_cache_event_type_test
+invalid_event_code_test
+reserved_bits_mmcra_sample_elig_mode_test
+reserved_bits_mmcra_thresh_ctl_test
index 0fce5a6..f93b4c7 100644 (file)
@@ -1,11 +1,21 @@
-mmcr0_exceptionbits_test
+bhrb_filter_map_test
+bhrb_no_crash_wo_pmu_test
+intr_regs_no_crash_wo_pmu_test
 mmcr0_cc56run_test
-mmcr0_pmccext_test
-mmcr0_pmcjce_test
+mmcr0_exceptionbits_test
 mmcr0_fc56_pmc1ce_test
 mmcr0_fc56_pmc56_test
+mmcr0_pmccext_test
+mmcr0_pmcjce_test
 mmcr1_comb_test
-mmcr2_l2l3_test
+mmcr1_sel_unit_cache_test
 mmcr2_fcs_fch_test
+mmcr2_l2l3_test
 mmcr3_src_test
+mmcra_bhrb_any_test
+mmcra_bhrb_cond_test
+mmcra_bhrb_disable_no_branch_test
+mmcra_bhrb_disable_test
+mmcra_bhrb_ind_call_test
+mmcra_thresh_cmp_test
 mmcra_thresh_marked_sample_test
index 50c5ab1..a07896a 100644 (file)
 #include "defines.h"
 #include "main.h"
 
+/*
+ * FIXME: OpenSSL 3.0 has deprecated some functions. For now just ignore
+ * the warnings.
+ */
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+
 struct q1q2_ctx {
        BN_CTX *bn_ctx;
        BIGNUM *m;
index f0d51d4..3a5936c 100644 (file)
@@ -1,4 +1,4 @@
-TEST_GEN_PROGS := timens timerfd timer clock_nanosleep procfs exec futex vfork_exec
+TEST_GEN_PROGS := timens timerfd timer clock_nanosleep procfs exec futex
 TEST_GEN_PROGS_EXTENDED := gettime_perf
 
 CFLAGS := -Wall -Werror -pthread
diff --git a/tools/testing/selftests/timens/vfork_exec.c b/tools/testing/selftests/timens/vfork_exec.c
deleted file mode 100644 (file)
index e6ccd90..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#define _GNU_SOURCE
-#include <errno.h>
-#include <fcntl.h>
-#include <sched.h>
-#include <stdio.h>
-#include <stdbool.h>
-#include <sys/stat.h>
-#include <sys/syscall.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <time.h>
-#include <unistd.h>
-#include <string.h>
-
-#include "log.h"
-#include "timens.h"
-
-#define OFFSET (36000)
-
-int main(int argc, char *argv[])
-{
-       struct timespec now, tst;
-       int status, i;
-       pid_t pid;
-
-       if (argc > 1) {
-               if (sscanf(argv[1], "%ld", &now.tv_sec) != 1)
-                       return pr_perror("sscanf");
-
-               for (i = 0; i < 2; i++) {
-                       _gettime(CLOCK_MONOTONIC, &tst, i);
-                       if (abs(tst.tv_sec - now.tv_sec) > 5)
-                               return pr_fail("%ld %ld\n", now.tv_sec, tst.tv_sec);
-               }
-               return 0;
-       }
-
-       nscheck();
-
-       ksft_set_plan(1);
-
-       clock_gettime(CLOCK_MONOTONIC, &now);
-
-       if (unshare_timens())
-               return 1;
-
-       if (_settime(CLOCK_MONOTONIC, OFFSET))
-               return 1;
-
-       for (i = 0; i < 2; i++) {
-               _gettime(CLOCK_MONOTONIC, &tst, i);
-               if (abs(tst.tv_sec - now.tv_sec) > 5)
-                       return pr_fail("%ld %ld\n",
-                                       now.tv_sec, tst.tv_sec);
-       }
-
-       pid = vfork();
-       if (pid < 0)
-               return pr_perror("fork");
-
-       if (pid == 0) {
-               char now_str[64];
-               char *cargv[] = {"exec", now_str, NULL};
-               char *cenv[] = {NULL};
-
-               // Check that we are still in the source timens.
-               for (i = 0; i < 2; i++) {
-                       _gettime(CLOCK_MONOTONIC, &tst, i);
-                       if (abs(tst.tv_sec - now.tv_sec) > 5)
-                               return pr_fail("%ld %ld\n",
-                                               now.tv_sec, tst.tv_sec);
-               }
-
-               /* Check for proper vvar offsets after execve. */
-               snprintf(now_str, sizeof(now_str), "%ld", now.tv_sec + OFFSET);
-               execve("/proc/self/exe", cargv, cenv);
-               return pr_perror("execve");
-       }
-
-       if (waitpid(pid, &status, 0) != pid)
-               return pr_perror("waitpid");
-
-       if (status)
-               ksft_exit_fail();
-
-       ksft_test_result_pass("exec\n");
-       ksft_exit_pass();
-       return 0;
-}
index 1bea2d1..22e28b7 100644 (file)
@@ -30,8 +30,8 @@ WOPTS :=      -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_A
 
 TRACEFS_HEADERS        := $$($(PKG_CONFIG) --cflags libtracefs)
 
-CFLAGS :=      -O -g -DVERSION=\"$(VERSION)\" $(FOPTS) $(MOPTS) $(WOPTS) $(TRACEFS_HEADERS)
-LDFLAGS        :=      -ggdb
+CFLAGS :=      -O -g -DVERSION=\"$(VERSION)\" $(FOPTS) $(MOPTS) $(WOPTS) $(TRACEFS_HEADERS) $(EXTRA_CFLAGS)
+LDFLAGS        :=      -ggdb $(EXTRA_LDFLAGS)
 LIBS   :=      $$($(PKG_CONFIG) --libs libtracefs)
 
 SRC    :=      $(wildcard src/*.c)
@@ -61,40 +61,50 @@ endif
 LIBTRACEEVENT_MIN_VERSION = 1.5
 LIBTRACEFS_MIN_VERSION = 1.3
 
+.PHONY:        all warnings show_warnings
+all:   warnings rtla
+
 TEST_LIBTRACEEVENT = $(shell sh -c "$(PKG_CONFIG) --atleast-version $(LIBTRACEEVENT_MIN_VERSION) libtraceevent > /dev/null 2>&1 || echo n")
 ifeq ("$(TEST_LIBTRACEEVENT)", "n")
-.PHONY: warning_traceevent
-warning_traceevent:
-       @echo "********************************************"
-       @echo "** NOTICE: libtraceevent version $(LIBTRACEEVENT_MIN_VERSION) or higher not found"
-       @echo "**"
-       @echo "** Consider installing the latest libtraceevent from your"
-       @echo "** distribution, e.g., 'dnf install libtraceevent' on Fedora,"
-       @echo "** or from source:"
-       @echo "**"
-       @echo "**  https://git.kernel.org/pub/scm/libs/libtrace/libtraceevent.git/ "
-       @echo "**"
-       @echo "********************************************"
+WARNINGS = show_warnings
+MISSING_LIBS += echo "**   libtraceevent version $(LIBTRACEEVENT_MIN_VERSION) or higher";
+MISSING_PACKAGES += "libtraceevent-devel"
+MISSING_SOURCE += echo "**  https://git.kernel.org/pub/scm/libs/libtrace/libtraceevent.git/ ";
 endif
 
 TEST_LIBTRACEFS = $(shell sh -c "$(PKG_CONFIG) --atleast-version $(LIBTRACEFS_MIN_VERSION) libtracefs > /dev/null 2>&1 || echo n")
 ifeq ("$(TEST_LIBTRACEFS)", "n")
-.PHONY: warning_tracefs
-warning_tracefs:
-       @echo "********************************************"
-       @echo "** NOTICE: libtracefs version $(LIBTRACEFS_MIN_VERSION) or higher not found"
-       @echo "**"
-       @echo "** Consider installing the latest libtracefs from your"
-       @echo "** distribution, e.g., 'dnf install libtracefs' on Fedora,"
-       @echo "** or from source:"
-       @echo "**"
-       @echo "**  https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ "
-       @echo "**"
-       @echo "********************************************"
+WARNINGS = show_warnings
+MISSING_LIBS += echo "**   libtracefs version $(LIBTRACEFS_MIN_VERSION) or higher";
+MISSING_PACKAGES += "libtracefs-devel"
+MISSING_SOURCE += echo "**  https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ ";
 endif
 
-.PHONY:        all
-all:   rtla
+define show_dependencies
+       @echo "********************************************";                           \
+       echo "** NOTICE: Failed build dependencies";                                    \
+       echo "**";                                                                      \
+       echo "** Required Libraries:";                                                  \
+       $(MISSING_LIBS)                                                                 \
+       echo "**";                                                                      \
+       echo "** Consider installing the latest libtracefs from your";                  \
+       echo "** distribution, e.g., 'dnf install $(MISSING_PACKAGES)' on Fedora,";     \
+       echo "** or from source:";                                                      \
+       echo "**";                                                                      \
+       $(MISSING_SOURCE)                                                               \
+       echo "**";                                                                      \
+       echo "********************************************"
+endef
+
+show_warnings:
+       $(call show_dependencies);
+
+ifneq ("$(WARNINGS)", "")
+ERROR_OUT = $(error Please add the necessary dependencies)
+
+warnings: $(WARNINGS)
+       $(ERROR_OUT)
+endif
 
 rtla: $(OBJ)
        $(CC) -o rtla $(LDFLAGS) $(OBJ) $(LIBS)
@@ -108,9 +118,9 @@ install: doc_install
        $(INSTALL) rtla -m 755 $(DESTDIR)$(BINDIR)
        $(STRIP) $(DESTDIR)$(BINDIR)/rtla
        @test ! -f $(DESTDIR)$(BINDIR)/osnoise || rm $(DESTDIR)$(BINDIR)/osnoise
-       ln -s $(DESTDIR)$(BINDIR)/rtla $(DESTDIR)$(BINDIR)/osnoise
+       ln -s rtla $(DESTDIR)$(BINDIR)/osnoise
        @test ! -f $(DESTDIR)$(BINDIR)/timerlat || rm $(DESTDIR)$(BINDIR)/timerlat
-       ln -s $(DESTDIR)$(BINDIR)/rtla $(DESTDIR)$(BINDIR)/timerlat
+       ln -s rtla $(DESTDIR)$(BINDIR)/timerlat
 
 .PHONY: clean tarball
 clean: doc_clean
index f3ec628..4b48af8 100644 (file)
@@ -892,7 +892,7 @@ int timerlat_hist_main(int argc, char *argv[])
        return_value = 0;
 
        if (trace_is_off(&tool->trace, &record->trace)) {
-               printf("rtla timelat hit stop tracing\n");
+               printf("rtla timerlat hit stop tracing\n");
                if (params->trace_output) {
                        printf("  Saving trace to %s\n", params->trace_output);
                        save_trace_to_file(record->trace.inst, params->trace_output);
index 35452a1..3342719 100644 (file)
@@ -687,7 +687,7 @@ int timerlat_top_main(int argc, char *argv[])
        return_value = 0;
 
        if (trace_is_off(&top->trace, &record->trace)) {
-               printf("rtla timelat hit stop tracing\n");
+               printf("rtla timerlat hit stop tracing\n");
                if (params->trace_output) {
                        printf("  Saving trace to %s\n", params->trace_output);
                        save_trace_to_file(record->trace.inst, params->trace_output);
index 515dfe9..584a5ba 100644 (file)
@@ -702,30 +702,31 @@ static void kvm_mmu_notifier_change_pte(struct mmu_notifier *mn,
 
        /*
         * .change_pte() must be surrounded by .invalidate_range_{start,end}().
-        * If mmu_notifier_count is zero, then no in-progress invalidations,
-        * including this one, found a relevant memslot at start(); rechecking
-        * memslots here is unnecessary.  Note, a false positive (count elevated
-        * by a different invalidation) is sub-optimal but functionally ok.
+        * If mmu_invalidate_in_progress is zero, then no in-progress
+        * invalidations, including this one, found a relevant memslot at
+        * start(); rechecking memslots here is unnecessary.  Note, a false
+        * positive (count elevated by a different invalidation) is sub-optimal
+        * but functionally ok.
         */
        WARN_ON_ONCE(!READ_ONCE(kvm->mn_active_invalidate_count));
-       if (!READ_ONCE(kvm->mmu_notifier_count))
+       if (!READ_ONCE(kvm->mmu_invalidate_in_progress))
                return;
 
        kvm_handle_hva_range(mn, address, address + 1, pte, kvm_set_spte_gfn);
 }
 
-void kvm_inc_notifier_count(struct kvm *kvm, unsigned long start,
-                                  unsigned long end)
+void kvm_mmu_invalidate_begin(struct kvm *kvm, unsigned long start,
+                             unsigned long end)
 {
        /*
         * The count increase must become visible at unlock time as no
         * spte can be established without taking the mmu_lock and
         * count is also read inside the mmu_lock critical section.
         */
-       kvm->mmu_notifier_count++;
-       if (likely(kvm->mmu_notifier_count == 1)) {
-               kvm->mmu_notifier_range_start = start;
-               kvm->mmu_notifier_range_end = end;
+       kvm->mmu_invalidate_in_progress++;
+       if (likely(kvm->mmu_invalidate_in_progress == 1)) {
+               kvm->mmu_invalidate_range_start = start;
+               kvm->mmu_invalidate_range_end = end;
        } else {
                /*
                 * Fully tracking multiple concurrent ranges has diminishing
@@ -736,10 +737,10 @@ void kvm_inc_notifier_count(struct kvm *kvm, unsigned long start,
                 * accumulate and persist until all outstanding invalidates
                 * complete.
                 */
-               kvm->mmu_notifier_range_start =
-                       min(kvm->mmu_notifier_range_start, start);
-               kvm->mmu_notifier_range_end =
-                       max(kvm->mmu_notifier_range_end, end);
+               kvm->mmu_invalidate_range_start =
+                       min(kvm->mmu_invalidate_range_start, start);
+               kvm->mmu_invalidate_range_end =
+                       max(kvm->mmu_invalidate_range_end, end);
        }
 }
 
@@ -752,7 +753,7 @@ static int kvm_mmu_notifier_invalidate_range_start(struct mmu_notifier *mn,
                .end            = range->end,
                .pte            = __pte(0),
                .handler        = kvm_unmap_gfn_range,
-               .on_lock        = kvm_inc_notifier_count,
+               .on_lock        = kvm_mmu_invalidate_begin,
                .on_unlock      = kvm_arch_guest_memory_reclaimed,
                .flush_on_ret   = true,
                .may_block      = mmu_notifier_range_blockable(range),
@@ -763,7 +764,7 @@ static int kvm_mmu_notifier_invalidate_range_start(struct mmu_notifier *mn,
        /*
         * Prevent memslot modification between range_start() and range_end()
         * so that conditionally locking provides the same result in both
-        * functions.  Without that guarantee, the mmu_notifier_count
+        * functions.  Without that guarantee, the mmu_invalidate_in_progress
         * adjustments will be imbalanced.
         *
         * Pairs with the decrement in range_end().
@@ -779,7 +780,8 @@ static int kvm_mmu_notifier_invalidate_range_start(struct mmu_notifier *mn,
         * any given time, and the caches themselves can check for hva overlap,
         * i.e. don't need to rely on memslot overlap checks for performance.
         * Because this runs without holding mmu_lock, the pfn caches must use
-        * mn_active_invalidate_count (see above) instead of mmu_notifier_count.
+        * mn_active_invalidate_count (see above) instead of
+        * mmu_invalidate_in_progress.
         */
        gfn_to_pfn_cache_invalidate_start(kvm, range->start, range->end,
                                          hva_range.may_block);
@@ -789,22 +791,22 @@ static int kvm_mmu_notifier_invalidate_range_start(struct mmu_notifier *mn,
        return 0;
 }
 
-void kvm_dec_notifier_count(struct kvm *kvm, unsigned long start,
-                                  unsigned long end)
+void kvm_mmu_invalidate_end(struct kvm *kvm, unsigned long start,
+                           unsigned long end)
 {
        /*
         * This sequence increase will notify the kvm page fault that
         * the page that is going to be mapped in the spte could have
         * been freed.
         */
-       kvm->mmu_notifier_seq++;
+       kvm->mmu_invalidate_seq++;
        smp_wmb();
        /*
         * The above sequence increase must be visible before the
         * below count decrease, which is ensured by the smp_wmb above
-        * in conjunction with the smp_rmb in mmu_notifier_retry().
+        * in conjunction with the smp_rmb in mmu_invalidate_retry().
         */
-       kvm->mmu_notifier_count--;
+       kvm->mmu_invalidate_in_progress--;
 }
 
 static void kvm_mmu_notifier_invalidate_range_end(struct mmu_notifier *mn,
@@ -816,7 +818,7 @@ static void kvm_mmu_notifier_invalidate_range_end(struct mmu_notifier *mn,
                .end            = range->end,
                .pte            = __pte(0),
                .handler        = (void *)kvm_null_fn,
-               .on_lock        = kvm_dec_notifier_count,
+               .on_lock        = kvm_mmu_invalidate_end,
                .on_unlock      = (void *)kvm_null_fn,
                .flush_on_ret   = false,
                .may_block      = mmu_notifier_range_blockable(range),
@@ -837,7 +839,7 @@ static void kvm_mmu_notifier_invalidate_range_end(struct mmu_notifier *mn,
        if (wake)
                rcuwait_wake_up(&kvm->mn_memslots_update_rcuwait);
 
-       BUG_ON(kvm->mmu_notifier_count < 0);
+       BUG_ON(kvm->mmu_invalidate_in_progress < 0);
 }
 
 static int kvm_mmu_notifier_clear_flush_young(struct mmu_notifier *mn,
@@ -1134,6 +1136,9 @@ static struct kvm *kvm_create_vm(unsigned long type, const char *fdname)
        if (!kvm)
                return ERR_PTR(-ENOMEM);
 
+       /* KVM is pinned via open("/dev/kvm"), the fd passed to this ioctl(). */
+       __module_get(kvm_chardev_ops.owner);
+
        KVM_MMU_LOCK_INIT(kvm);
        mmgrab(current->mm);
        kvm->mm = current->mm;
@@ -1211,9 +1216,17 @@ static struct kvm *kvm_create_vm(unsigned long type, const char *fdname)
        if (r)
                goto out_err_no_mmu_notifier;
 
+       r = kvm_coalesced_mmio_init(kvm);
+       if (r < 0)
+               goto out_no_coalesced_mmio;
+
+       r = kvm_create_vm_debugfs(kvm, fdname);
+       if (r)
+               goto out_err_no_debugfs;
+
        r = kvm_arch_post_init_vm(kvm);
        if (r)
-               goto out_err_mmu_notifier;
+               goto out_err;
 
        mutex_lock(&kvm_lock);
        list_add(&kvm->vm_list, &vm_list);
@@ -1222,25 +1235,13 @@ static struct kvm *kvm_create_vm(unsigned long type, const char *fdname)
        preempt_notifier_inc();
        kvm_init_pm_notifier(kvm);
 
-       /*
-        * When the fd passed to this ioctl() is opened it pins the module,
-        * but try_module_get() also prevents getting a reference if the module
-        * is in MODULE_STATE_GOING (e.g. if someone ran "rmmod --wait").
-        */
-       if (!try_module_get(kvm_chardev_ops.owner)) {
-               r = -ENODEV;
-               goto out_err_mmu_notifier;
-       }
-
-       r = kvm_create_vm_debugfs(kvm, fdname);
-       if (r)
-               goto out_err;
-
        return kvm;
 
 out_err:
-       module_put(kvm_chardev_ops.owner);
-out_err_mmu_notifier:
+       kvm_destroy_vm_debugfs(kvm);
+out_err_no_debugfs:
+       kvm_coalesced_mmio_free(kvm);
+out_no_coalesced_mmio:
 #if defined(CONFIG_MMU_NOTIFIER) && defined(KVM_ARCH_WANT_MMU_NOTIFIER)
        if (kvm->mmu_notifier.ops)
                mmu_notifier_unregister(&kvm->mmu_notifier, current->mm);
@@ -1259,6 +1260,7 @@ out_err_no_irq_srcu:
 out_err_no_srcu:
        kvm_arch_free_vm(kvm);
        mmdrop(current->mm);
+       module_put(kvm_chardev_ops.owner);
        return ERR_PTR(r);
 }
 
@@ -2516,7 +2518,7 @@ static int hva_to_pfn_slow(unsigned long addr, bool *async, bool write_fault,
 {
        unsigned int flags = FOLL_HWPOISON;
        struct page *page;
-       int npages = 0;
+       int npages;
 
        might_sleep();
 
@@ -4378,7 +4380,7 @@ void kvm_unregister_device_ops(u32 type)
 static int kvm_ioctl_create_device(struct kvm *kvm,
                                   struct kvm_create_device *cd)
 {
-       const struct kvm_device_ops *ops = NULL;
+       const struct kvm_device_ops *ops;
        struct kvm_device *dev;
        bool test = cd->flags & KVM_CREATE_DEVICE_TEST;
        int type;
@@ -4913,11 +4915,6 @@ static int kvm_dev_ioctl_create_vm(unsigned long type)
                goto put_fd;
        }
 
-#ifdef CONFIG_KVM_MMIO
-       r = kvm_coalesced_mmio_init(kvm);
-       if (r < 0)
-               goto put_kvm;
-#endif
        file = anon_inode_getfile("kvm-vm", &kvm_vm_fops, kvm, O_RDWR);
        if (IS_ERR(file)) {
                r = PTR_ERR(file);
index ab519f7..68ff41d 100644 (file)
@@ -112,27 +112,28 @@ static inline bool mmu_notifier_retry_cache(struct kvm *kvm, unsigned long mmu_s
 {
        /*
         * mn_active_invalidate_count acts for all intents and purposes
-        * like mmu_notifier_count here; but the latter cannot be used
-        * here because the invalidation of caches in the mmu_notifier
-        * event occurs _before_ mmu_notifier_count is elevated.
+        * like mmu_invalidate_in_progress here; but the latter cannot
+        * be used here because the invalidation of caches in the
+        * mmu_notifier event occurs _before_ mmu_invalidate_in_progress
+        * is elevated.
         *
         * Note, it does not matter that mn_active_invalidate_count
         * is not protected by gpc->lock.  It is guaranteed to
         * be elevated before the mmu_notifier acquires gpc->lock, and
-        * isn't dropped until after mmu_notifier_seq is updated.
+        * isn't dropped until after mmu_invalidate_seq is updated.
         */
        if (kvm->mn_active_invalidate_count)
                return true;
 
        /*
         * Ensure mn_active_invalidate_count is read before
-        * mmu_notifier_seq.  This pairs with the smp_wmb() in
+        * mmu_invalidate_seq.  This pairs with the smp_wmb() in
         * mmu_notifier_invalidate_range_end() to guarantee either the
         * old (non-zero) value of mn_active_invalidate_count or the
-        * new (incremented) value of mmu_notifier_seq is observed.
+        * new (incremented) value of mmu_invalidate_seq is observed.
         */
        smp_rmb();
-       return kvm->mmu_notifier_seq != mmu_seq;
+       return kvm->mmu_invalidate_seq != mmu_seq;
 }
 
 static kvm_pfn_t hva_to_pfn_retry(struct kvm *kvm, struct gfn_to_pfn_cache *gpc)
@@ -155,7 +156,7 @@ static kvm_pfn_t hva_to_pfn_retry(struct kvm *kvm, struct gfn_to_pfn_cache *gpc)
        gpc->valid = false;
 
        do {
-               mmu_seq = kvm->mmu_notifier_seq;
+               mmu_seq = kvm->mmu_invalidate_seq;
                smp_rmb();
 
                write_unlock_irq(&gpc->lock);