Merge tag 'kvm-x86-pmu-6.6-fixes' of https://github.com/kvm-x86/linux into HEAD
authorPaolo Bonzini <pbonzini@redhat.com>
Sun, 15 Oct 2023 12:24:18 +0000 (08:24 -0400)
committerPaolo Bonzini <pbonzini@redhat.com>
Sun, 15 Oct 2023 12:24:18 +0000 (08:24 -0400)
KVM x86/pmu fixes for 6.6:

 - Truncate writes to PMU counters to the counter's width to avoid spurious
   overflows when emulating counter events in software.

 - Set the LVTPC entry mask bit when handling a PMI (to match Intel-defined
   architectural behavior).

 - Treat KVM_REQ_PMI as a wake event instead of queueing host IRQ work to
   kick the guest out of emulated halt.

927 files changed:
.mailmap
Documentation/admin-guide/cgroup-v1/memory.rst
Documentation/arch/arm64/cpu-feature-registers.rst
Documentation/arch/arm64/elf_hwcaps.rst
Documentation/arch/arm64/silicon-errata.rst
Documentation/arch/loongarch/introduction.rst
Documentation/devicetree/bindings/ata/pata-common.yaml
Documentation/devicetree/bindings/bus/fsl,imx8qxp-pixel-link-msi-bus.yaml
Documentation/devicetree/bindings/cache/andestech,ax45mp-cache.yaml
Documentation/devicetree/bindings/clock/renesas,5p35023.yaml
Documentation/devicetree/bindings/display/imx/fsl,imx6-hdmi.yaml
Documentation/devicetree/bindings/i2c/i2c-mxs.yaml
Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml
Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.yaml
Documentation/devicetree/bindings/interrupt-controller/renesas,rzg2l-irqc.yaml
Documentation/devicetree/bindings/iommu/arm,smmu.yaml
Documentation/devicetree/bindings/media/i2c/sony,imx415.yaml
Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.yaml
Documentation/devicetree/bindings/media/nxp,imx7-csi.yaml
Documentation/devicetree/bindings/media/renesas,vin.yaml
Documentation/devicetree/bindings/media/samsung,fimc.yaml
Documentation/devicetree/bindings/mfd/maxim,max77693.yaml
Documentation/devicetree/bindings/pci/brcm,iproc-pcie.yaml
Documentation/devicetree/bindings/riscv/cpus.yaml
Documentation/devicetree/bindings/soc/loongson/loongson,ls2k-pmc.yaml
Documentation/devicetree/bindings/sound/fsl,micfil.yaml
Documentation/devicetree/bindings/sound/rockchip-spdif.yaml
Documentation/devicetree/bindings/spi/fsl-imx-cspi.yaml
Documentation/devicetree/bindings/trivial-devices.yaml
Documentation/filesystems/erofs.rst
Documentation/filesystems/porting.rst
Documentation/kbuild/kconfig-language.rst
Documentation/networking/ax25.rst
Documentation/sound/designs/midi-2.0.rst
Documentation/tools/rtla/rtla-timerlat-hist.rst
Documentation/translations/zh_CN/arch/loongarch/introduction.rst
MAINTAINERS
Makefile
arch/arm/boot/dts/ti/omap/motorola-mapphone-common.dtsi
arch/arm/boot/dts/ti/omap/omap3-cpu-thermal.dtsi
arch/arm/boot/dts/ti/omap/omap4-cpu-thermal.dtsi
arch/arm/boot/dts/ti/omap/omap443x.dtsi
arch/arm/boot/dts/ti/omap/omap4460.dtsi
arch/arm/include/asm/hardware/locomo.h
arch/arm/mach-omap2/pm44xx.c
arch/arm/mach-sa1100/include/mach/collie.h
arch/arm/mm/cache-uniphier.c
arch/arm/xen/enlighten.c
arch/arm64/Kconfig
arch/arm64/boot/dts/freescale/Makefile
arch/arm64/boot/dts/freescale/imx8mm-evk.dtsi
arch/arm64/boot/dts/freescale/imx8mp-beacon-kit.dts
arch/arm64/boot/dts/freescale/imx8mp.dtsi
arch/arm64/boot/dts/freescale/imx93-tqma9352.dtsi
arch/arm64/boot/dts/mediatek/mt8195.dtsi
arch/arm64/boot/dts/qcom/sm8150.dtsi
arch/arm64/configs/defconfig
arch/arm64/include/asm/acpi.h
arch/arm64/include/asm/cpufeature.h
arch/arm64/include/asm/cputype.h
arch/arm64/include/asm/hugetlb.h
arch/arm64/include/asm/kvm_arm.h
arch/arm64/kernel/cpu_errata.c
arch/arm64/kernel/cpufeature.c
arch/arm64/kernel/entry.S
arch/arm64/kvm/arch_timer.c
arch/arm64/kvm/emulate-nested.c
arch/arm64/kvm/hyp/vhe/switch.c
arch/arm64/kvm/pmu.c
arch/arm64/kvm/sys_regs.c
arch/arm64/mm/hugetlbpage.c
arch/arm64/tools/cpucaps
arch/arm64/tools/sysreg
arch/ia64/kernel/acpi.c
arch/loongarch/include/asm/addrspace.h
arch/loongarch/include/asm/elf.h
arch/loongarch/include/asm/exception.h [new file with mode: 0644]
arch/loongarch/include/asm/kasan.h
arch/loongarch/include/asm/smp.h
arch/loongarch/kernel/Makefile
arch/loongarch/kernel/acpi.c
arch/loongarch/kernel/mem.c
arch/loongarch/kernel/module-sections.c
arch/loongarch/kernel/module.c
arch/loongarch/kernel/numa.c
arch/loongarch/kernel/process.c
arch/loongarch/kernel/relocate_kernel.S
arch/loongarch/kernel/signal.c
arch/loongarch/kernel/smp.c
arch/loongarch/kernel/syscall.c
arch/loongarch/kernel/time.c
arch/loongarch/kernel/topology.c
arch/loongarch/kernel/traps.c
arch/loongarch/kernel/vmlinux.lds.S
arch/loongarch/mm/fault.c
arch/loongarch/mm/hugetlbpage.c
arch/loongarch/mm/ioremap.c
arch/loongarch/mm/kasan_init.c
arch/loongarch/mm/tlb.c
arch/mips/alchemy/devboards/db1000.c
arch/mips/alchemy/devboards/db1200.c
arch/mips/alchemy/devboards/db1300.c
arch/mips/kvm/mmu.c
arch/parisc/include/asm/hugetlb.h
arch/parisc/include/asm/ldcw.h
arch/parisc/include/asm/spinlock_types.h
arch/parisc/kernel/smp.c
arch/parisc/mm/hugetlbpage.c
arch/powerpc/Kconfig
arch/powerpc/include/asm/nohash/32/hugetlb-8xx.h
arch/powerpc/kernel/hw_breakpoint.c
arch/powerpc/kernel/hw_breakpoint_constraints.c
arch/powerpc/kernel/stacktrace.c
arch/powerpc/kernel/traps.c
arch/powerpc/mm/book3s64/hugetlbpage.c
arch/powerpc/mm/book3s64/radix_hugetlbpage.c
arch/powerpc/mm/nohash/8xx.c
arch/powerpc/mm/pgtable.c
arch/powerpc/perf/hv-24x7.c
arch/powerpc/platforms/82xx/Kconfig
arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
arch/riscv/include/asm/hugetlb.h
arch/riscv/mm/hugetlbpage.c
arch/s390/configs/debug_defconfig
arch/s390/configs/defconfig
arch/s390/configs/zfcpdump_defconfig
arch/s390/include/asm/hugetlb.h
arch/s390/kernel/cert_store.c
arch/s390/kvm/interrupt.c
arch/s390/mm/hugetlbpage.c
arch/s390/net/bpf_jit_comp.c
arch/sh/mm/ioremap.c
arch/sparc/include/asm/hugetlb.h
arch/sparc/mm/hugetlbpage.c
arch/x86/entry/common.c
arch/x86/events/amd/core.c
arch/x86/hyperv/hv_init.c
arch/x86/hyperv/hv_vtl.c
arch/x86/include/asm/fpu/api.h
arch/x86/include/asm/linkage.h
arch/x86/include/asm/mmu_context.h
arch/x86/include/asm/mshyperv.h
arch/x86/include/asm/paravirt_types.h
arch/x86/include/asm/pgtable.h
arch/x86/include/asm/processor.h
arch/x86/include/asm/svm.h
arch/x86/include/asm/xen/hypervisor.h
arch/x86/kernel/alternative.c
arch/x86/kernel/callthunks.c
arch/x86/kernel/cpu/amd.c
arch/x86/kernel/cpu/bugs.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/sgx/encl.c
arch/x86/kernel/fpu/core.c
arch/x86/kernel/fpu/xstate.c
arch/x86/kernel/fpu/xstate.h
arch/x86/kernel/kgdb.c
arch/x86/kernel/paravirt.c
arch/x86/kernel/process.c
arch/x86/kernel/setup.c
arch/x86/kernel/sev-shared.c
arch/x86/kernel/sev.c
arch/x86/kernel/shstk.c
arch/x86/kvm/cpuid.c
arch/x86/kvm/svm/avic.c
arch/x86/kvm/svm/nested.c
arch/x86/kvm/svm/svm.c
arch/x86/kvm/x86.c
arch/x86/lib/memcpy_64.S
arch/x86/lib/memmove_64.S
arch/x86/lib/memset_64.S
arch/x86/xen/efi.c
arch/x86/xen/enlighten.c
arch/x86/xen/enlighten_hvm.c
arch/x86/xen/enlighten_pv.c
arch/x86/xen/mmu_pv.c
arch/x86/xen/multicalls.h
arch/xtensa/boot/Makefile
arch/xtensa/boot/lib/zmem.c
arch/xtensa/include/asm/core.h
arch/xtensa/include/asm/hw_breakpoint.h
arch/xtensa/include/asm/processor.h
arch/xtensa/include/asm/ptrace.h
arch/xtensa/include/asm/smp.h
arch/xtensa/include/asm/tlb.h
arch/xtensa/kernel/hw_breakpoint.c
arch/xtensa/kernel/irq.c
arch/xtensa/kernel/ptrace.c
arch/xtensa/kernel/signal.c
arch/xtensa/kernel/smp.c
arch/xtensa/kernel/stacktrace.c
arch/xtensa/kernel/traps.c
arch/xtensa/lib/umulsidi3.S
arch/xtensa/mm/fault.c
arch/xtensa/mm/tlb.c
arch/xtensa/platforms/iss/network.c
block/blk-rq-qos.c
block/disk-events.c
crypto/sm2.c
drivers/accel/ivpu/ivpu_drv.c
drivers/accel/ivpu/ivpu_drv.h
drivers/accel/ivpu/ivpu_fw.c
drivers/accel/ivpu/ivpu_gem.h
drivers/accel/ivpu/ivpu_hw_40xx.c
drivers/accel/ivpu/ivpu_hw_40xx_reg.h
drivers/accel/ivpu/ivpu_ipc.c
drivers/acpi/acpi_video.c
drivers/acpi/nfit/core.c
drivers/acpi/processor_idle.c
drivers/acpi/processor_pdc.c
drivers/ata/libata-core.c
drivers/ata/libata-eh.c
drivers/ata/libata-scsi.c
drivers/ata/libata-transport.c
drivers/ata/libata.h
drivers/ata/pata_parport/fit3.c
drivers/ata/pata_parport/pata_parport.c
drivers/base/regmap/regcache-rbtree.c
drivers/block/nbd.c
drivers/block/rbd.c
drivers/bluetooth/btusb.c
drivers/bus/ti-sysc.c
drivers/clk/clk-si521xx.c
drivers/clk/clk-versaclock3.c
drivers/clk/sprd/ums512-clk.c
drivers/clk/tegra/clk-bpmp.c
drivers/cxl/acpi.c
drivers/cxl/core/mbox.c
drivers/cxl/core/port.c
drivers/cxl/core/region.c
drivers/cxl/pci.c
drivers/dma/ti/k3-udma-glue.c
drivers/firewire/sbp2.c
drivers/firmware/arm_ffa/driver.c
drivers/firmware/arm_scmi/perf.c
drivers/firmware/cirrus/cs_dsp.c
drivers/firmware/efi/efi.c
drivers/firmware/imx/imx-dsp.c
drivers/gpio/gpio-aspeed.c
drivers/gpio/gpio-pmic-eic-sprd.c
drivers/gpio/gpio-pxa.c
drivers/gpio/gpio-sim.c
drivers/gpio/gpio-tb10x.c
drivers/gpio/gpio-timberdale.c
drivers/gpu/drm/Kconfig
drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn20/dcn20_clk_mgr.c
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c
drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mpc.c
drivers/gpu/drm/amd/pm/amdgpu_pm.c
drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
drivers/gpu/drm/drm_panel_orientation_quirks.c
drivers/gpu/drm/i915/gem/i915_gem_pages.c
drivers/gpu/drm/i915/gem/i915_gem_shmem.c
drivers/gpu/drm/i915/gt/gen8_engine_cs.c
drivers/gpu/drm/i915/gt/intel_engine_cs.c
drivers/gpu/drm/i915/gt/intel_execlists_submission.c
drivers/gpu/drm/i915/gt/intel_ggtt.c
drivers/gpu/drm/i915/gt/intel_lrc.c
drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/meson/meson_encoder_hdmi.c
drivers/gpu/drm/nouveau/nouveau_abi16.c
drivers/gpu/drm/nouveau/nouveau_chan.c
drivers/gpu/drm/nouveau/nouveau_dma.h
drivers/gpu/drm/nouveau/nouveau_drv.h
drivers/gpu/drm/nouveau/nouveau_exec.c
drivers/gpu/drm/nouveau/nouveau_exec.h
drivers/gpu/drm/nouveau/nouveau_fence.c
drivers/gpu/drm/nouveau/nouveau_sched.c
drivers/gpu/drm/tests/drm_kunit_helpers.c
drivers/gpu/drm/tests/drm_mm_test.c
drivers/gpu/drm/virtio/virtgpu_submit.c
drivers/hid/Kconfig
drivers/hid/hid-holtek-kbd.c
drivers/hid/hid-ids.h
drivers/hid/hid-input.c
drivers/hid/hid-logitech-hidpp.c
drivers/hid/hid-multitouch.c
drivers/hid/hid-nintendo.c
drivers/hid/hid-nvidia-shield.c
drivers/hid/hid-sony.c
drivers/hid/hid-steelseries.c
drivers/hid/i2c-hid/i2c-hid-core.c
drivers/hid/intel-ish-hid/ipc/pci-ish.c
drivers/hwmon/nct6775-core.c
drivers/i2c/busses/i2c-designware-common.c
drivers/i2c/busses/i2c-designware-core.h
drivers/i2c/busses/i2c-i801.c
drivers/i2c/busses/i2c-npcm7xx.c
drivers/i2c/busses/i2c-xiic.c
drivers/i2c/i2c-mux.c
drivers/i2c/muxes/i2c-demux-pinctrl.c
drivers/i2c/muxes/i2c-mux-gpio.c
drivers/infiniband/core/cma.c
drivers/infiniband/core/cma_configfs.c
drivers/infiniband/core/nldev.c
drivers/infiniband/core/uverbs_main.c
drivers/infiniband/hw/bnxt_re/ib_verbs.c
drivers/infiniband/hw/bnxt_re/qplib_rcfw.c
drivers/infiniband/hw/cxgb4/cm.c
drivers/infiniband/hw/erdma/erdma_verbs.c
drivers/infiniband/hw/mlx4/sysfs.c
drivers/infiniband/hw/mlx5/fs.c
drivers/infiniband/hw/mlx5/main.c
drivers/infiniband/hw/mlx5/mr.c
drivers/infiniband/sw/siw/siw_cm.c
drivers/infiniband/ulp/srp/ib_srp.c
drivers/iommu/apple-dart.c
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
drivers/iommu/intel/iommu.c
drivers/iommu/intel/iommu.h
drivers/iommu/mtk_iommu.c
drivers/irqchip/irq-gic-common.h
drivers/irqchip/irq-gic-v3-its.c
drivers/irqchip/irq-gic-v3.c
drivers/irqchip/irq-renesas-rzg2l.c
drivers/irqchip/irq-riscv-intc.c
drivers/irqchip/irq-stm32-exti.c
drivers/irqchip/irq-xtensa-mx.c
drivers/irqchip/qcom-pdc.c
drivers/leds/led-core.c
drivers/md/dm-crypt.c
drivers/md/dm-zoned-target.c
drivers/md/raid5.c
drivers/media/common/videobuf2/frame_vector.c
drivers/media/i2c/imx219.c
drivers/media/i2c/max9286.c
drivers/media/i2c/rdacm21.c
drivers/media/pci/bt8xx/bttv-risc.c
drivers/media/pci/intel/Kconfig
drivers/media/pci/intel/ipu3/Kconfig
drivers/media/pci/intel/ivsc/Kconfig
drivers/media/platform/intel/pxa_camera.c
drivers/media/platform/marvell/Kconfig
drivers/media/platform/mediatek/vcodec/encoder/venc_vpu_if.c
drivers/media/platform/nxp/imx-mipi-csis.c
drivers/media/platform/via/Kconfig
drivers/media/usb/em28xx/Kconfig
drivers/media/usb/go7007/Kconfig
drivers/media/usb/uvc/uvc_ctrl.c
drivers/mfd/Kconfig
drivers/mfd/cs42l43.c
drivers/misc/cardreader/rts5227.c
drivers/misc/cardreader/rts5228.c
drivers/misc/cardreader/rts5249.c
drivers/misc/cardreader/rts5260.c
drivers/misc/cardreader/rts5261.c
drivers/misc/cardreader/rtsx_pcr.c
drivers/mtd/ubi/build.c
drivers/net/dsa/mv88e6xxx/chip.c
drivers/net/dsa/mv88e6xxx/global1.c
drivers/net/dsa/mv88e6xxx/global1.h
drivers/net/dsa/mv88e6xxx/global2.c
drivers/net/dsa/mv88e6xxx/global2.h
drivers/net/ethernet/amazon/ena/ena_netdev.c
drivers/net/ethernet/broadcom/bnxt/bnxt.c
drivers/net/ethernet/engleder/tsnep_ethtool.c
drivers/net/ethernet/engleder/tsnep_main.c
drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
drivers/net/ethernet/huawei/hinic/hinic_port.c
drivers/net/ethernet/ibm/ibmveth.c
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
drivers/net/ethernet/intel/iavf/iavf.h
drivers/net/ethernet/intel/iavf/iavf_ethtool.c
drivers/net/ethernet/intel/iavf/iavf_main.c
drivers/net/ethernet/intel/ice/ice_virtchnl.c
drivers/net/ethernet/intel/igc/igc_ethtool.c
drivers/net/ethernet/intel/igc/igc_main.c
drivers/net/ethernet/marvell/octeon_ep/octep_main.c
drivers/net/ethernet/marvell/octeon_ep/octep_tx.c
drivers/net/ethernet/marvell/octeon_ep/octep_tx.h
drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c
drivers/net/ethernet/marvell/sky2.h
drivers/net/ethernet/mediatek/mtk_eth_soc.c
drivers/net/ethernet/microchip/Kconfig
drivers/net/ethernet/microchip/vcap/vcap_api_kunit.c
drivers/net/ethernet/microsoft/mana/mana_en.c
drivers/net/ethernet/pensando/ionic/ionic_dev.h
drivers/net/ethernet/pensando/ionic/ionic_txrx.c
drivers/net/ethernet/qlogic/qed/qed_ll2.h
drivers/net/ethernet/renesas/rswitch.c
drivers/net/ethernet/renesas/rswitch.h
drivers/net/ethernet/sfc/tc.c
drivers/net/ethernet/sfc/tc_conntrack.c
drivers/net/ethernet/sfc/tc_counters.c
drivers/net/ethernet/sfc/tc_encap_actions.c
drivers/net/ethernet/stmicro/stmmac/common.h
drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c
drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c
drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
drivers/net/ethernet/stmicro/stmmac/stmmac.h
drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
drivers/net/ethernet/ti/Kconfig
drivers/net/ethernet/ti/am65-cpsw-nuss.c
drivers/net/ethernet/ti/icssg/icssg_prueth.c
drivers/net/team/team.c
drivers/net/thunderbolt/main.c
drivers/net/usb/smsc75xx.c
drivers/net/vxlan/vxlan_core.c
drivers/net/wan/fsl_ucc_hdlc.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
drivers/net/wireless/intel/iwlwifi/fw/error-dump.h
drivers/net/wireless/intel/iwlwifi/mvm/fw.c
drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
drivers/net/wireless/intel/iwlwifi/mvm/scan.c
drivers/net/wireless/intel/iwlwifi/mvm/tx.c
drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c
drivers/net/wireless/marvell/mwifiex/fw.h
drivers/net/wireless/marvell/mwifiex/sta_rx.c
drivers/net/wireless/mediatek/mt76/dma.c
drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.c
drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c
drivers/net/wireless/realtek/rtw88/rtw8723d.h
drivers/of/dynamic.c
drivers/of/overlay.c
drivers/pci/controller/dwc/pcie-qcom.c
drivers/pci/of.c
drivers/pci/of_property.c
drivers/pci/pci-driver.c
drivers/pci/pcie/aer.c
drivers/pci/pcie/portdrv.h
drivers/perf/arm-cmn.c
drivers/platform/mellanox/mlxbf-tmfifo.c
drivers/platform/x86/hp/hp-bioscfg/bioscfg.c
drivers/platform/x86/hp/hp-wmi.c
drivers/platform/x86/intel/ifs/runtest.c
drivers/platform/x86/intel_scu_ipc.c
drivers/platform/x86/think-lmi.c
drivers/platform/x86/thinkpad_acpi.c
drivers/platform/x86/touchscreen_dmi.c
drivers/power/reset/Kconfig
drivers/power/reset/pwr-mlxbf.c
drivers/power/reset/vexpress-poweroff.c
drivers/power/supply/Kconfig
drivers/power/supply/ab8500_btemp.c
drivers/power/supply/ab8500_chargalg.c
drivers/power/supply/mt6370-charger.c
drivers/power/supply/power_supply_sysfs.c
drivers/power/supply/rk817_charger.c
drivers/power/supply/rt9467-charger.c
drivers/power/supply/ucs1002_power.c
drivers/ptp/ptp_ocp.c
drivers/regulator/core.c
drivers/regulator/helpers.c
drivers/regulator/mt6358-regulator.c
drivers/s390/scsi/zfcp_aux.c
drivers/scsi/fnic/fnic.h
drivers/scsi/fnic/fnic_io.h
drivers/scsi/fnic/fnic_main.c
drivers/scsi/fnic/fnic_scsi.c
drivers/scsi/iscsi_tcp.c
drivers/scsi/scsi.c
drivers/scsi/scsi_scan.c
drivers/scsi/sd.c
drivers/scsi/sd.h
drivers/soc/imx/soc-imx8m.c
drivers/soc/loongson/Kconfig
drivers/soc/loongson/loongson2_guts.c
drivers/soc/loongson/loongson2_pm.c
drivers/spi/spi-cs42l43.c
drivers/spi/spi-gxp.c
drivers/spi/spi-imx.c
drivers/spi/spi-intel-pci.c
drivers/spi/spi-nxp-fspi.c
drivers/spi/spi-stm32.c
drivers/spi/spi-zynqmp-gqspi.c
drivers/staging/media/atomisp/Kconfig
drivers/staging/media/tegra-video/vi.c
drivers/target/target_core_device.c
drivers/tee/optee/optee_private.h
drivers/tee/tee_private.h
drivers/thermal/thermal_sysfs.c
drivers/tty/n_gsm.c
drivers/tty/serial/8250/8250_port.c
drivers/vfio/mdev/mdev_sysfs.c
drivers/vfio/pci/pds/Kconfig
drivers/vfio/pci/pds/vfio_dev.c
drivers/vhost/vringh.c
drivers/video/console/Kconfig
drivers/video/fbdev/Kconfig
drivers/video/fbdev/core/Kconfig
drivers/xen/events/events_base.c
drivers/xen/platform-pci.c
fs/aio.c
fs/binfmt_elf_fdpic.c
fs/btrfs/ctree.c
fs/btrfs/delayed-inode.c
fs/btrfs/delayed-inode.h
fs/btrfs/delayed-ref.c
fs/btrfs/delayed-ref.h
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/file.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/super.c
fs/btrfs/transaction.c
fs/btrfs/transaction.h
fs/btrfs/tree-log.c
fs/btrfs/verity.c
fs/btrfs/volumes.c
fs/buffer.c
fs/ceph/crypto.c
fs/erofs/decompressor_lzma.c
fs/erofs/super.c
fs/ext4/super.c
fs/fs-writeback.c
fs/gfs2/glock.c
fs/gfs2/glops.c
fs/gfs2/quota.h
fs/inode.c
fs/iomap/buffered-io.c
fs/libfs.c
fs/netfs/buffered_read.c
fs/nfs/direct.c
fs/nfs/flexfilelayout/flexfilelayout.c
fs/nfs/nfs4client.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c
fs/nfs/write.c
fs/nfsd/nfs4xdr.c
fs/nilfs2/gcinode.c
fs/ntfs3/super.c
fs/overlayfs/copy_up.c
fs/overlayfs/export.c
fs/overlayfs/file.c
fs/overlayfs/ovl_entry.h
fs/overlayfs/params.c
fs/overlayfs/super.c
fs/pipe.c
fs/proc/internal.h
fs/proc/task_nommu.c
fs/quota/dquot.c
fs/reiserfs/reiserfs.h
fs/smb/client/cached_dir.c
fs/smb/client/cifsglob.h
fs/smb/client/cifsproto.h
fs/smb/client/connect.c
fs/smb/client/fs_context.c
fs/smb/client/misc.c
fs/smb/client/smb2inode.c
fs/smb/client/smb2maperror.c
fs/smb/client/smb2pdu.c
fs/smb/client/smbdirect.c
fs/smb/client/trace.h
fs/smb/client/transport.c
fs/smb/server/connection.c
fs/smb/server/connection.h
fs/smb/server/mgmt/tree_connect.c
fs/smb/server/mgmt/tree_connect.h
fs/smb/server/mgmt/user_session.c
fs/smb/server/mgmt/user_session.h
fs/smb/server/server.c
fs/smb/server/smb2misc.c
fs/smb/server/smb2pdu.c
fs/smb/server/vfs_cache.c
fs/smb/server/vfs_cache.h
fs/stat.c
fs/tracefs/event_inode.c
fs/xfs/Kconfig
fs/xfs/libxfs/xfs_log_recover.h
fs/xfs/libxfs/xfs_sb.c
fs/xfs/libxfs/xfs_trans_inode.c
fs/xfs/scrub/scrub.c
fs/xfs/scrub/stats.c
fs/xfs/xfs_attr_inactive.c
fs/xfs/xfs_attr_item.c
fs/xfs/xfs_bmap_item.c
fs/xfs/xfs_discard.c
fs/xfs/xfs_discard.h
fs/xfs/xfs_export.c
fs/xfs/xfs_extent_busy.c
fs/xfs/xfs_extent_busy.h
fs/xfs/xfs_extfree_item.c
fs/xfs/xfs_fsmap.c
fs/xfs/xfs_icache.c
fs/xfs/xfs_icache.h
fs/xfs/xfs_inode.c
fs/xfs/xfs_inode.h
fs/xfs/xfs_iops.c
fs/xfs/xfs_itable.c
fs/xfs/xfs_log.c
fs/xfs/xfs_log_cil.c
fs/xfs/xfs_log_priv.h
fs/xfs/xfs_log_recover.c
fs/xfs/xfs_mount.h
fs/xfs/xfs_qm.c
fs/xfs/xfs_refcount_item.c
fs/xfs/xfs_rmap_item.c
fs/xfs/xfs_super.c
fs/xfs/xfs_trace.h
fs/xfs/xfs_xattr.c
include/asm-generic/hugetlb.h
include/asm-generic/mshyperv.h
include/asm-generic/vmlinux.lds.h
include/kvm/arm_arch_timer.h
include/linux/acpi.h
include/linux/aer.h
include/linux/atomic/atomic-arch-fallback.h
include/linux/bpf.h
include/linux/btf_ids.h
include/linux/ceph/ceph_fs.h
include/linux/cpuhotplug.h
include/linux/fs.h
include/linux/hugetlb.h
include/linux/if_team.h
include/linux/interrupt.h
include/linux/kasan.h
include/linux/libata.h
include/linux/maple_tree.h
include/linux/memcontrol.h
include/linux/netfilter/nf_conntrack_sctp.h
include/linux/nfs_fs_sb.h
include/linux/nfs_page.h
include/linux/pgtable.h
include/linux/quota.h
include/linux/quotaops.h
include/linux/resume_user_mode.h
include/linux/seqlock.h
include/linux/sunrpc/xdr.h
include/linux/swiotlb.h
include/net/bluetooth/hci_core.h
include/net/cfg80211.h
include/net/ip_fib.h
include/net/mana/mana.h
include/net/neighbour.h
include/net/netfilter/nf_tables.h
include/net/page_pool/helpers.h
include/net/tcp.h
include/scsi/scsi.h
include/scsi/scsi_device.h
include/scsi/scsi_host.h
include/sound/soc.h
include/trace/events/xen.h
include/uapi/drm/nouveau_drm.h
include/uapi/linux/bpf.h
include/uapi/linux/stddef.h
include/xen/arm/hypervisor.h
include/xen/events.h
io_uring/fs.c
io_uring/io-wq.c
io_uring/io_uring.c
io_uring/io_uring.h
io_uring/kbuf.c
kernel/bpf/btf.c
kernel/bpf/cgroup.c
kernel/bpf/memalloc.c
kernel/bpf/mprog.c
kernel/bpf/offload.c
kernel/bpf/queue_stack_maps.c
kernel/bpf/verifier.c
kernel/crash_core.c
kernel/dma/swiotlb.c
kernel/pid.c
kernel/power/snapshot.c
kernel/printk/printk.c
kernel/sched/core.c
kernel/sched/cpufreq_schedutil.c
kernel/sched/cpupri.c
kernel/sched/fair.c
kernel/sched/idle.c
kernel/task_work.c
kernel/trace/bpf_trace.c
kernel/trace/ring_buffer.c
kernel/trace/trace_events.c
kernel/trace/trace_events_user.c
kernel/workqueue.c
lib/argv_split.c
lib/maple_tree.c
lib/scatterlist.c
lib/test_maple_tree.c
mm/damon/vaddr-test.h
mm/damon/vaddr.c
mm/filemap.c
mm/hugetlb.c
mm/kasan/kasan.h
mm/memcontrol.c
mm/mempolicy.c
mm/migrate.c
mm/page_alloc.c
mm/rmap.c
mm/shmem.c
mm/slab_common.c
mm/vmalloc.c
mm/zswap.c
net/ax25/Kconfig
net/bluetooth/hci_conn.c
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c
net/bluetooth/hci_request.h
net/bluetooth/hci_sync.c
net/bluetooth/iso.c
net/bridge/br_forward.c
net/bridge/br_input.c
net/bridge/br_netfilter_hooks.c
net/core/dev.c
net/core/flow_dissector.c
net/core/neighbour.c
net/core/sock_map.c
net/dccp/ipv4.c
net/dccp/ipv6.c
net/ethtool/plca.c
net/handshake/handshake-test.c
net/hsr/hsr_framereg.c
net/hsr/hsr_main.h
net/ipv4/fib_semantics.c
net/ipv4/fib_trie.c
net/ipv4/route.c
net/ipv4/tcp.c
net/ipv4/tcp_bpf.c
net/ipv4/tcp_input.c
net/ipv4/tcp_output.c
net/ipv6/tcp_ipv6.c
net/l2tp/l2tp_ip6.c
net/mac80211/cfg.c
net/mac80211/ibss.c
net/mac80211/ieee80211_i.h
net/mac80211/key.c
net/mac80211/mesh.c
net/mac80211/mesh_plink.c
net/mac80211/mlme.c
net/mac80211/tx.c
net/mac80211/vht.c
net/mptcp/options.c
net/mptcp/pm_userspace.c
net/mptcp/protocol.c
net/mptcp/protocol.h
net/mptcp/subflow.c
net/ncsi/ncsi-aen.c
net/netfilter/ipset/ip_set_core.c
net/netfilter/ipvs/ip_vs_sync.c
net/netfilter/nf_conntrack_bpf.c
net/netfilter/nf_conntrack_extend.c
net/netfilter/nf_conntrack_proto_sctp.c
net/netfilter/nf_tables_api.c
net/netfilter/nft_payload.c
net/netfilter/nft_set_hash.c
net/netfilter/nft_set_pipapo.c
net/netfilter/nft_set_rbtree.c
net/netlink/af_netlink.c
net/nfc/llcp_core.c
net/rds/rdma_transport.c
net/rds/tcp_connect.c
net/rds/tcp_listen.c
net/rfkill/core.c
net/sctp/associola.c
net/sctp/socket.c
net/socket.c
net/sunrpc/auth.c
net/sunrpc/auth_tls.c
net/sunrpc/clnt.c
net/sunrpc/xprtsock.c
net/tipc/crypto.c
net/wireless/core.c
net/wireless/core.h
net/wireless/mlme.c
net/wireless/nl80211.c
net/wireless/scan.c
scripts/Makefile.modinst
scripts/atomic/gen-atomic-fallback.sh
scripts/gdb/linux/symbols.py
scripts/mod/file2alias.c
scripts/mod/modpost.c
scripts/package/builddeb
scripts/package/kernel.spec
security/integrity/ima/Kconfig
security/keys/trusted-keys/trusted_core.c
sound/core/init.c
sound/core/rawmidi.c
sound/core/seq/seq_midi.c
sound/core/seq/seq_ump_client.c
sound/core/seq/seq_ump_convert.c
sound/firewire/bebob/bebob_midi.c
sound/firewire/dice/dice-midi.c
sound/firewire/digi00x/digi00x-midi.c
sound/firewire/fireface/ff-midi.c
sound/firewire/fireworks/fireworks.c
sound/firewire/fireworks/fireworks_midi.c
sound/firewire/motu/motu-midi.c
sound/firewire/oxfw/oxfw-midi.c
sound/firewire/oxfw/oxfw.c
sound/firewire/tascam/tascam-midi.c
sound/hda/intel-sdw-acpi.c
sound/isa/ad1848/ad1848.c
sound/isa/cs423x/cs4231.c
sound/isa/cs423x/cs4236.c
sound/isa/es1688/es1688.c
sound/isa/opti9xx/miro.c
sound/isa/opti9xx/opti92x-ad1848.c
sound/isa/sscape.c
sound/pci/cmipci.c
sound/pci/hda/cs35l41_hda.c
sound/pci/hda/cs35l56_hda.c
sound/pci/hda/cs35l56_hda_i2c.c
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_realtek.c
sound/pci/riptide/riptide.c
sound/soc/amd/yc/acp6x-mach.c
sound/soc/codecs/aw88395/aw88395_lib.c
sound/soc/codecs/cs35l56-i2c.c
sound/soc/codecs/cs35l56.c
sound/soc/codecs/cs42l42-sdw.c
sound/soc/codecs/cs42l42.c
sound/soc/codecs/cs42l42.h
sound/soc/codecs/cs42l43.c
sound/soc/codecs/hdmi-codec.c
sound/soc/codecs/rt5640.c
sound/soc/codecs/rt5682-i2c.c
sound/soc/codecs/tlv320adc3xxx.c
sound/soc/codecs/wm8960.c
sound/soc/codecs/wm_adsp.c
sound/soc/fsl/fsl-asoc-card.c
sound/soc/fsl/fsl_sai.c
sound/soc/fsl/imx-audmix.c
sound/soc/fsl/imx-pcm-rpmsg.c
sound/soc/fsl/imx-rpmsg.c
sound/soc/generic/simple-card-utils.c
sound/soc/generic/simple-card.c
sound/soc/intel/avs/boards/hdaudio.c
sound/soc/intel/boards/sof_es8336.c
sound/soc/intel/boards/sof_sdw.c
sound/soc/intel/common/soc-acpi-intel-adl-match.c
sound/soc/intel/common/soc-acpi-intel-mtl-match.c
sound/soc/meson/axg-spdifin.c
sound/soc/sh/rcar/core.c
sound/soc/soc-core.c
sound/soc/soc-generic-dmaengine-pcm.c
sound/soc/soc-pcm.c
sound/soc/soc-utils.c
sound/soc/sof/amd/pci-rmb.c
sound/soc/sof/core.c
sound/soc/sof/intel/mtl.c
sound/soc/sof/intel/mtl.h
sound/soc/sof/ipc4-topology.c
sound/soc/sof/sof-audio.c
sound/soc/tegra/tegra_audio_graph_card.c
sound/usb/caiaq/device.c
sound/usb/mixer.c
sound/usb/mixer_scarlett_gen2.c
sound/usb/quirks.c
sound/xen/xen_snd_front_cfg.c
tools/arch/x86/include/asm/msr-index.h
tools/hv/hv_kvp_daemon.c
tools/hv/hv_set_ifconfig.sh
tools/include/linux/btf_ids.h
tools/include/linux/mm.h
tools/include/linux/seq_file.h
tools/include/uapi/asm-generic/unistd.h
tools/include/uapi/drm/drm.h
tools/include/uapi/linux/bpf.h
tools/include/uapi/linux/seccomp.h [new file with mode: 0644]
tools/perf/arch/mips/entry/syscalls/syscall_n64.tbl
tools/perf/arch/powerpc/entry/syscalls/syscall.tbl
tools/perf/arch/s390/entry/syscalls/syscall.tbl
tools/perf/arch/x86/entry/syscalls/syscall_64.tbl
tools/perf/bench/sched-seccomp-notify.c
tools/perf/check-headers.sh
tools/perf/pmu-events/jevents.py
tools/perf/pmu-events/metric.py
tools/perf/util/bpf-prologue.c [deleted file]
tools/perf/util/bpf_skel/augmented_raw_syscalls.bpf.c
tools/perf/util/hashmap.h
tools/perf/util/pmu.c
tools/testing/memblock/internal.h
tools/testing/memblock/mmzone.c
tools/testing/memblock/tests/basic_api.c
tools/testing/memblock/tests/common.h
tools/testing/selftests/Makefile
tools/testing/selftests/alsa/conf.c
tools/testing/selftests/alsa/mixer-test.c
tools/testing/selftests/alsa/pcm-test.c
tools/testing/selftests/alsa/test-pcmtest-driver.c
tools/testing/selftests/bpf/DENYLIST.aarch64
tools/testing/selftests/bpf/config
tools/testing/selftests/bpf/config.x86_64
tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c
tools/testing/selftests/bpf/prog_tests/empty_skb.c
tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c
tools/testing/selftests/bpf/prog_tests/sockmap_basic.c
tools/testing/selftests/bpf/prog_tests/tc_opts.c
tools/testing/selftests/bpf/prog_tests/test_bpf_ma.c [new file with mode: 0644]
tools/testing/selftests/bpf/prog_tests/xdp_dev_bound_only.c [new file with mode: 0644]
tools/testing/selftests/bpf/progs/bpf_cubic.c
tools/testing/selftests/bpf/progs/kprobe_multi_override.c [new file with mode: 0644]
tools/testing/selftests/bpf/progs/test_bpf_ma.c [new file with mode: 0644]
tools/testing/selftests/bpf/test_verifier.c
tools/testing/selftests/fchmodat2/Makefile
tools/testing/selftests/kvm/include/x86_64/processor.h
tools/testing/selftests/kvm/x86_64/state_test.c
tools/testing/selftests/mm/charge_reserved_hugetlb.sh
tools/testing/selftests/mm/hugetlb_reparenting_test.sh
tools/testing/selftests/net/hsr/hsr_ping.sh
tools/testing/selftests/net/tls.c
tools/testing/selftests/netfilter/.gitignore
tools/testing/selftests/netfilter/Makefile
tools/testing/selftests/netfilter/audit_logread.c [new file with mode: 0644]
tools/testing/selftests/netfilter/config
tools/testing/selftests/netfilter/conntrack_sctp_collision.sh [new file with mode: 0755]
tools/testing/selftests/netfilter/nft_audit.sh [new file with mode: 0755]
tools/testing/selftests/netfilter/sctp_collision.c [new file with mode: 0644]
tools/testing/selftests/openat2/Makefile
tools/testing/selftests/powerpc/Makefile
tools/testing/selftests/powerpc/pmu/Makefile
tools/testing/selftests/proc/proc-empty-vm.c
tools/testing/selftests/user_events/abi_test.c
tools/testing/selftests/user_events/dyn_test.c
tools/testing/selftests/user_events/ftrace_test.c
tools/testing/selftests/user_events/perf_test.c
tools/testing/selftests/user_events/user_events_selftests.h
tools/tracing/rtla/src/timerlat_aa.c
tools/tracing/rtla/src/timerlat_u.c

index a0a6efe..c80903e 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -377,6 +377,7 @@ Matthew Wilcox <willy@infradead.org> <willy@debian.org>
 Matthew Wilcox <willy@infradead.org> <willy@linux.intel.com>
 Matthew Wilcox <willy@infradead.org> <willy@parisc-linux.org>
 Matthias Fuchs <socketcan@esd.eu> <matthias.fuchs@esd.eu>
+Matthieu Baerts <matttbe@kernel.org> <matthieu.baerts@tessares.net>
 Matthieu CASTET <castet.matthieu@free.fr>
 Matti Vaittinen <mazziesaccount@gmail.com> <matti.vaittinen@fi.rohmeurope.com>
 Matt Ranostay <matt.ranostay@konsulko.com> <matt@ranostay.consulting>
index 5f502bf..ff45687 100644 (file)
@@ -92,6 +92,13 @@ Brief summary of control files.
  memory.oom_control                 set/show oom controls.
  memory.numa_stat                   show the number of memory usage per numa
                                     node
+ memory.kmem.limit_in_bytes          Deprecated knob to set and read the kernel
+                                     memory hard limit. Kernel hard limit is not
+                                     supported since 5.16. Writing any value to
+                                     do file will not have any effect same as if
+                                     nokmem kernel parameter was specified.
+                                     Kernel memory is still charged and reported
+                                     by memory.kmem.usage_in_bytes.
  memory.kmem.usage_in_bytes          show current kernel memory allocation
  memory.kmem.failcnt                 show the number of kernel memory usage
                                     hits limits
index 4e4625f..de6d8a4 100644 (file)
@@ -175,6 +175,8 @@ infrastructure:
      +------------------------------+---------+---------+
      | Name                         |  bits   | visible |
      +------------------------------+---------+---------+
+     | SME                          | [27-24] |    y    |
+     +------------------------------+---------+---------+
      | MTE                          | [11-8]  |    y    |
      +------------------------------+---------+---------+
      | SSBS                         | [7-4]   |    y    |
@@ -288,8 +290,18 @@ infrastructure:
      +------------------------------+---------+---------+
      | Name                         |  bits   | visible |
      +------------------------------+---------+---------+
+     | CSSC                         | [55-52] |    y    |
+     +------------------------------+---------+---------+
+     | RPRFM                        | [51-48] |    y    |
+     +------------------------------+---------+---------+
+     | BC                           | [23-20] |    y    |
+     +------------------------------+---------+---------+
      | MOPS                         | [19-16] |    y    |
      +------------------------------+---------+---------+
+     | APA3                         | [15-12] |    y    |
+     +------------------------------+---------+---------+
+     | GPA3                         | [11-8]  |    y    |
+     +------------------------------+---------+---------+
      | RPRES                        | [7-4]   |    y    |
      +------------------------------+---------+---------+
      | WFXT                         | [3-0]   |    y    |
index 8c8addb..76ff9d7 100644 (file)
@@ -305,6 +305,9 @@ HWCAP2_SMEF16F16
 HWCAP2_MOPS
     Functionality implied by ID_AA64ISAR2_EL1.MOPS == 0b0001.
 
+HWCAP2_HBC
+    Functionality implied by ID_AA64ISAR2_EL1.BC == 0b0001.
+
 4. Unused AT_HWCAP bits
 -----------------------
 
index e96f057..f47f63b 100644 (file)
@@ -71,6 +71,8 @@ stable kernels.
 +----------------+-----------------+-----------------+-----------------------------+
 | ARM            | Cortex-A510     | #2658417        | ARM64_ERRATUM_2658417       |
 +----------------+-----------------+-----------------+-----------------------------+
+| ARM            | Cortex-A520     | #2966298        | ARM64_ERRATUM_2966298       |
++----------------+-----------------+-----------------+-----------------------------+
 | ARM            | Cortex-A53      | #826319         | ARM64_ERRATUM_826319        |
 +----------------+-----------------+-----------------+-----------------------------+
 | ARM            | Cortex-A53      | #827319         | ARM64_ERRATUM_827319        |
index 49135d4..8c568cf 100644 (file)
@@ -381,9 +381,9 @@ Documentation of LoongArch ISA:
 
 Documentation of LoongArch ELF psABI:
 
-  https://github.com/loongson/LoongArch-Documentation/releases/latest/download/LoongArch-ELF-ABI-v2.00-CN.pdf (in Chinese)
+  https://github.com/loongson/LoongArch-Documentation/releases/latest/download/LoongArch-ELF-ABI-v2.01-CN.pdf (in Chinese)
 
-  https://github.com/loongson/LoongArch-Documentation/releases/latest/download/LoongArch-ELF-ABI-v2.00-EN.pdf (in English)
+  https://github.com/loongson/LoongArch-Documentation/releases/latest/download/LoongArch-ELF-ABI-v2.01-EN.pdf (in English)
 
 Linux kernel repository of Loongson and LoongArch:
 
index 337ddf1..4e867dd 100644 (file)
@@ -38,6 +38,7 @@ patternProperties:
       ID number 0 and the slave drive will have ID number 1. The PATA port
       nodes will be named "ide-port".
     type: object
+    additionalProperties: false
 
     properties:
       reg:
index b568d0c..7e1ffc5 100644 (file)
@@ -73,9 +73,6 @@ patternProperties:
   "^.*@[0-9a-f]+$":
     description: Devices attached to the bus
     type: object
-    properties:
-      reg:
-        maxItems: 1
 
     required:
       - reg
index 9ab5f0c..d2cbe49 100644 (file)
@@ -69,7 +69,7 @@ examples:
   - |
     #include <dt-bindings/interrupt-controller/irq.h>
 
-    cache-controller@2010000 {
+    cache-controller@13400000 {
         compatible = "andestech,ax45mp-cache", "cache";
         reg = <0x13400000 0x100000>;
         interrupts = <508 IRQ_TYPE_LEVEL_HIGH>;
index 839648e..42b6f80 100644 (file)
@@ -37,6 +37,9 @@ properties:
     maxItems: 1
 
   '#clock-cells':
+    description:
+      The index in the assigned-clocks is mapped to the output clock as below
+      0 - REF, 1 - SE1, 2 - SE2, 3 - SE3, 4 - DIFF1, 5 - DIFF2.
     const: 1
 
   clocks:
@@ -68,7 +71,7 @@ examples:
             reg = <0x68>;
             #clock-cells = <1>;
 
-            clocks = <&x1_x2>;
+            clocks = <&x1>;
 
             renesas,settings = [
                 80 00 11 19 4c 02 23 7f 83 19 08 a9 5f 25 24 bf
@@ -79,8 +82,8 @@ examples:
             assigned-clocks = <&versa3 0>, <&versa3 1>,
                               <&versa3 2>, <&versa3 3>,
                               <&versa3 4>, <&versa3 5>;
-            assigned-clock-rates = <12288000>, <25000000>,
-                                   <12000000>, <11289600>,
-                                   <11289600>, <24000000>;
+            assigned-clock-rates = <24000000>, <11289600>,
+                                   <11289600>, <12000000>,
+                                   <25000000>, <12288000>;
         };
     };
index af7fe9c..7979cf0 100644 (file)
@@ -87,7 +87,7 @@ required:
   - interrupts
   - ports
 
-additionalProperties: false
+unevaluatedProperties: false
 
 examples:
   - |
index 21ae7bc..171a414 100644 (file)
@@ -9,6 +9,9 @@ title: Freescale MXS Inter IC (I2C) Controller
 maintainers:
   - Shawn Guo <shawnguo@kernel.org>
 
+allOf:
+  - $ref: /schemas/i2c/i2c-controller.yaml#
+
 properties:
   compatible:
     enum:
@@ -37,7 +40,7 @@ required:
   - dmas
   - dma-names
 
-additionalProperties: false
+unevaluatedProperties: false
 
 examples:
   - |
index 2bc3847..0f4a062 100644 (file)
@@ -106,6 +106,12 @@ properties:
     $ref: /schemas/types.yaml#/definitions/uint32
     maximum: 4096
 
+  dma-noncoherent:
+    description:
+      Present if the GIC redistributors permit programming shareability
+      and cacheability attributes but are connected to a non-coherent
+      downstream interconnect.
+
   msi-controller:
     description:
       Only present if the Message Based Interrupt functionality is
@@ -193,6 +199,12 @@ patternProperties:
       compatible:
         const: arm,gic-v3-its
 
+      dma-noncoherent:
+        description:
+          Present if the GIC ITS permits programming shareability and
+          cacheability attributes but is connected to a non-coherent
+          downstream interconnect.
+
       msi-controller: true
 
       "#msi-cells":
index 95033cb..b417341 100644 (file)
@@ -37,6 +37,7 @@ properties:
           - renesas,intc-ex-r8a77990    # R-Car E3
           - renesas,intc-ex-r8a77995    # R-Car D3
           - renesas,intc-ex-r8a779a0    # R-Car V3U
+          - renesas,intc-ex-r8a779f0    # R-Car S4-8
           - renesas,intc-ex-r8a779g0    # R-Car V4H
       - const: renesas,irqc
 
index 33b90e9..2ef3081 100644 (file)
@@ -19,20 +19,19 @@ description: |
     - NMI edge select (NMI is not treated as NMI exception and supports fall edge and
       stand-up edge detection interrupts)
 
-allOf:
-  - $ref: /schemas/interrupt-controller.yaml#
-
 properties:
   compatible:
     items:
       - enum:
+          - renesas,r9a07g043u-irqc   # RZ/G2UL
           - renesas,r9a07g044-irqc    # RZ/G2{L,LC}
           - renesas,r9a07g054-irqc    # RZ/V2L
       - const: renesas,rzg2l-irqc
 
   '#interrupt-cells':
-    description: The first cell should contain external interrupt number (IRQ0-7) and the
-                 second cell is used to specify the flag.
+    description: The first cell should contain a macro RZG2L_{NMI,IRQX} included in the
+                 include/dt-bindings/interrupt-controller/irqc-rzg2l.h and the second
+                 cell is used to specify the flag.
     const: 2
 
   '#address-cells':
@@ -44,7 +43,96 @@ properties:
     maxItems: 1
 
   interrupts:
-    maxItems: 41
+    minItems: 41
+    items:
+      - description: NMI interrupt
+      - description: IRQ0 interrupt
+      - description: IRQ1 interrupt
+      - description: IRQ2 interrupt
+      - description: IRQ3 interrupt
+      - description: IRQ4 interrupt
+      - description: IRQ5 interrupt
+      - description: IRQ6 interrupt
+      - description: IRQ7 interrupt
+      - description: GPIO interrupt, TINT0
+      - description: GPIO interrupt, TINT1
+      - description: GPIO interrupt, TINT2
+      - description: GPIO interrupt, TINT3
+      - description: GPIO interrupt, TINT4
+      - description: GPIO interrupt, TINT5
+      - description: GPIO interrupt, TINT6
+      - description: GPIO interrupt, TINT7
+      - description: GPIO interrupt, TINT8
+      - description: GPIO interrupt, TINT9
+      - description: GPIO interrupt, TINT10
+      - description: GPIO interrupt, TINT11
+      - description: GPIO interrupt, TINT12
+      - description: GPIO interrupt, TINT13
+      - description: GPIO interrupt, TINT14
+      - description: GPIO interrupt, TINT15
+      - description: GPIO interrupt, TINT16
+      - description: GPIO interrupt, TINT17
+      - description: GPIO interrupt, TINT18
+      - description: GPIO interrupt, TINT19
+      - description: GPIO interrupt, TINT20
+      - description: GPIO interrupt, TINT21
+      - description: GPIO interrupt, TINT22
+      - description: GPIO interrupt, TINT23
+      - description: GPIO interrupt, TINT24
+      - description: GPIO interrupt, TINT25
+      - description: GPIO interrupt, TINT26
+      - description: GPIO interrupt, TINT27
+      - description: GPIO interrupt, TINT28
+      - description: GPIO interrupt, TINT29
+      - description: GPIO interrupt, TINT30
+      - description: GPIO interrupt, TINT31
+      - description: Bus error interrupt
+
+  interrupt-names:
+    minItems: 41
+    items:
+      - const: nmi
+      - const: irq0
+      - const: irq1
+      - const: irq2
+      - const: irq3
+      - const: irq4
+      - const: irq5
+      - const: irq6
+      - const: irq7
+      - const: tint0
+      - const: tint1
+      - const: tint2
+      - const: tint3
+      - const: tint4
+      - const: tint5
+      - const: tint6
+      - const: tint7
+      - const: tint8
+      - const: tint9
+      - const: tint10
+      - const: tint11
+      - const: tint12
+      - const: tint13
+      - const: tint14
+      - const: tint15
+      - const: tint16
+      - const: tint17
+      - const: tint18
+      - const: tint19
+      - const: tint20
+      - const: tint21
+      - const: tint22
+      - const: tint23
+      - const: tint24
+      - const: tint25
+      - const: tint26
+      - const: tint27
+      - const: tint28
+      - const: tint29
+      - const: tint30
+      - const: tint31
+      - const: bus-err
 
   clocks:
     maxItems: 2
@@ -72,6 +160,23 @@ required:
   - power-domains
   - resets
 
+allOf:
+  - $ref: /schemas/interrupt-controller.yaml#
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: renesas,r9a07g043u-irqc
+    then:
+      properties:
+        interrupts:
+          minItems: 42
+        interrupt-names:
+          minItems: 42
+      required:
+        - interrupt-names
+
 unevaluatedProperties: false
 
 examples:
@@ -80,55 +185,66 @@ examples:
     #include <dt-bindings/clock/r9a07g044-cpg.h>
 
     irqc: interrupt-controller@110a0000 {
-            compatible = "renesas,r9a07g044-irqc", "renesas,rzg2l-irqc";
-            reg = <0x110a0000 0x10000>;
-            #interrupt-cells = <2>;
-            #address-cells = <0>;
-            interrupt-controller;
-            interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
-                         <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>,
-                         <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>,
-                         <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
-                         <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>,
-                         <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>,
-                         <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>,
-                         <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>,
-                         <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
-                         <GIC_SPI 444 IRQ_TYPE_LEVEL_HIGH>,
-                         <GIC_SPI 445 IRQ_TYPE_LEVEL_HIGH>,
-                         <GIC_SPI 446 IRQ_TYPE_LEVEL_HIGH>,
-                         <GIC_SPI 447 IRQ_TYPE_LEVEL_HIGH>,
-                         <GIC_SPI 448 IRQ_TYPE_LEVEL_HIGH>,
-                         <GIC_SPI 449 IRQ_TYPE_LEVEL_HIGH>,
-                         <GIC_SPI 450 IRQ_TYPE_LEVEL_HIGH>,
-                         <GIC_SPI 451 IRQ_TYPE_LEVEL_HIGH>,
-                         <GIC_SPI 452 IRQ_TYPE_LEVEL_HIGH>,
-                         <GIC_SPI 453 IRQ_TYPE_LEVEL_HIGH>,
-                         <GIC_SPI 454 IRQ_TYPE_LEVEL_HIGH>,
-                         <GIC_SPI 455 IRQ_TYPE_LEVEL_HIGH>,
-                         <GIC_SPI 456 IRQ_TYPE_LEVEL_HIGH>,
-                         <GIC_SPI 457 IRQ_TYPE_LEVEL_HIGH>,
-                         <GIC_SPI 458 IRQ_TYPE_LEVEL_HIGH>,
-                         <GIC_SPI 459 IRQ_TYPE_LEVEL_HIGH>,
-                         <GIC_SPI 460 IRQ_TYPE_LEVEL_HIGH>,
-                         <GIC_SPI 461 IRQ_TYPE_LEVEL_HIGH>,
-                         <GIC_SPI 462 IRQ_TYPE_LEVEL_HIGH>,
-                         <GIC_SPI 463 IRQ_TYPE_LEVEL_HIGH>,
-                         <GIC_SPI 464 IRQ_TYPE_LEVEL_HIGH>,
-                         <GIC_SPI 465 IRQ_TYPE_LEVEL_HIGH>,
-                         <GIC_SPI 466 IRQ_TYPE_LEVEL_HIGH>,
-                         <GIC_SPI 467 IRQ_TYPE_LEVEL_HIGH>,
-                         <GIC_SPI 468 IRQ_TYPE_LEVEL_HIGH>,
-                         <GIC_SPI 469 IRQ_TYPE_LEVEL_HIGH>,
-                         <GIC_SPI 470 IRQ_TYPE_LEVEL_HIGH>,
-                         <GIC_SPI 471 IRQ_TYPE_LEVEL_HIGH>,
-                         <GIC_SPI 472 IRQ_TYPE_LEVEL_HIGH>,
-                         <GIC_SPI 473 IRQ_TYPE_LEVEL_HIGH>,
-                         <GIC_SPI 474 IRQ_TYPE_LEVEL_HIGH>,
-                         <GIC_SPI 475 IRQ_TYPE_LEVEL_HIGH>;
-            clocks = <&cpg CPG_MOD R9A07G044_IA55_CLK>,
-                     <&cpg CPG_MOD R9A07G044_IA55_PCLK>;
-            clock-names = "clk", "pclk";
-            power-domains = <&cpg>;
-            resets = <&cpg R9A07G044_IA55_RESETN>;
+        compatible = "renesas,r9a07g044-irqc", "renesas,rzg2l-irqc";
+        reg = <0x110a0000 0x10000>;
+        #interrupt-cells = <2>;
+        #address-cells = <0>;
+        interrupt-controller;
+        interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 444 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 445 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 446 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 447 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 448 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 449 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 450 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 451 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 452 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 453 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 454 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 455 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 456 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 457 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 458 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 459 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 460 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 461 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 462 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 463 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 464 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 465 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 466 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 467 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 468 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 469 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 470 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 471 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 472 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 473 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 474 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 475 IRQ_TYPE_LEVEL_HIGH>;
+        interrupt-names = "nmi",
+                          "irq0", "irq1", "irq2", "irq3",
+                          "irq4", "irq5", "irq6", "irq7",
+                          "tint0", "tint1", "tint2", "tint3",
+                          "tint4", "tint5", "tint6", "tint7",
+                          "tint8", "tint9", "tint10", "tint11",
+                          "tint12", "tint13", "tint14", "tint15",
+                          "tint16", "tint17", "tint18", "tint19",
+                          "tint20", "tint21", "tint22", "tint23",
+                          "tint24", "tint25", "tint26", "tint27",
+                          "tint28", "tint29", "tint30", "tint31";
+        clocks = <&cpg CPG_MOD R9A07G044_IA55_CLK>,
+                 <&cpg CPG_MOD R9A07G044_IA55_PCLK>;
+        clock-names = "clk", "pclk";
+        power-domains = <&cpg>;
+        resets = <&cpg R9A07G044_IA55_RESETN>;
     };
index cf29ab1..b1b2cf8 100644 (file)
@@ -270,6 +270,7 @@ allOf:
           contains:
             enum:
               - qcom,msm8998-smmu-v2
+              - qcom,sdm630-smmu-v2
     then:
       anyOf:
         - properties:
@@ -311,7 +312,6 @@ allOf:
         compatible:
           contains:
             enum:
-              - qcom,sdm630-smmu-v2
               - qcom,sm6375-smmu-v2
     then:
       anyOf:
index ffccf5f..642f9b1 100644 (file)
@@ -54,6 +54,7 @@ properties:
 
   port:
     $ref: /schemas/graph.yaml#/$defs/port-base
+    unevaluatedProperties: false
 
     properties:
       endpoint:
index c5cab54..1c476b6 100644 (file)
@@ -69,6 +69,7 @@ properties:
     properties:
       port@0:
         $ref: /schemas/graph.yaml#/$defs/port-base
+        unevaluatedProperties: false
         description: Input port
 
         properties:
@@ -89,6 +90,7 @@ properties:
 
       port@1:
         $ref: /schemas/graph.yaml#/$defs/port-base
+        unevaluatedProperties: false
         description: Output port
 
         properties:
index 358019e..326284e 100644 (file)
@@ -59,7 +59,6 @@ allOf:
         compatible:
           contains:
             enum:
-              - fsl,imx8mq-csi
               - fsl,imx8mm-csi
     then:
       required:
index 324703b..5539d0f 100644 (file)
@@ -95,7 +95,7 @@ properties:
               synchronization is selected.
             default: 1
 
-          field-active-even: true
+          field-even-active: true
 
           bus-width: true
 
@@ -144,7 +144,7 @@ properties:
                   synchronization is selected.
                 default: 1
 
-              field-active-even: true
+              field-even-active: true
 
               bus-width: true
 
index 79ff6d8..b3486c3 100644 (file)
@@ -57,6 +57,7 @@ properties:
     patternProperties:
       "^port@[01]$":
         $ref: /schemas/graph.yaml#/$defs/port-base
+        unevaluatedProperties: false
         description:
           Camera A and camera B inputs.
 
index 9804d13..6a6f222 100644 (file)
@@ -31,10 +31,6 @@ properties:
   charger:
     $ref: /schemas/power/supply/maxim,max77693.yaml
 
-  connector:
-    $ref: /schemas/connector/usb-connector.yaml#
-    unevaluatedProperties: false
-
   led:
     $ref: /schemas/leds/maxim,max77693.yaml
 
index 0972868..0e07ab6 100644 (file)
@@ -12,7 +12,6 @@ maintainers:
 
 allOf:
   - $ref: /schemas/pci/pci-bus.yaml#
-  - $ref: /schemas/interrupt-controller/msi-controller.yaml#
 
 properties:
   compatible:
@@ -34,13 +33,6 @@ properties:
     description: >
        Base address and length of the PCIe controller I/O register space
 
-  interrupt-map: true
-
-  interrupt-map-mask: true
-
-  "#interrupt-cells":
-    const: 1
-
   ranges:
     minItems: 1
     maxItems: 2
@@ -54,16 +46,8 @@ properties:
     items:
       - const: pcie-phy
 
-  bus-range: true
-
   dma-coherent: true
 
-  "#address-cells": true
-
-  "#size-cells": true
-
-  device_type: true
-
   brcm,pcie-ob:
     type: boolean
     description: >
@@ -78,20 +62,24 @@ properties:
 
   msi:
     type: object
+    $ref: /schemas/interrupt-controller/msi-controller.yaml#
+    unevaluatedProperties: false
+
     properties:
       compatible:
         items:
           - const: brcm,iproc-msi
 
-  msi-parent: true
+      interrupts:
+        maxItems: 4
 
-  msi-controller: true
+      brcm,pcie-msi-inten:
+        type: boolean
+        description:
+          Needs to be present for some older iProc platforms that require the
+          interrupt enable registers to be set explicitly to enable MSI
 
-  brcm,pcie-msi-inten:
-    type: boolean
-    description: >
-      Needs to be present for some older iProc platforms that require the
-      interrupt enable registers to be set explicitly to enable MSI
+  msi-parent: true
 
 dependencies:
   brcm,pcie-ob-axi-offset: ["brcm,pcie-ob"]
@@ -117,68 +105,69 @@ unevaluatedProperties: false
 
 examples:
   - |
-   #include <dt-bindings/interrupt-controller/arm-gic.h>
-
-   bus {
-      #address-cells = <1>;
-      #size-cells = <1>;
-           pcie0: pcie@18012000 {
-              compatible = "brcm,iproc-pcie";
-              reg = <0x18012000 0x1000>;
-
-              #interrupt-cells = <1>;
-              interrupt-map-mask = <0 0 0 0>;
-              interrupt-map = <0 0 0 0 &gic GIC_SPI 100 IRQ_TYPE_NONE>;
-
-              linux,pci-domain = <0>;
-
-              bus-range = <0x00 0xff>;
-
-              #address-cells = <3>;
-              #size-cells = <2>;
-              device_type = "pci";
-              ranges = <0x81000000 0 0     0x28000000 0 0x00010000>,
-                   <0x82000000 0 0x20000000 0x20000000 0 0x04000000>;
-
-              phys = <&phy 0 5>;
-              phy-names = "pcie-phy";
-
-              brcm,pcie-ob;
-              brcm,pcie-ob-axi-offset = <0x00000000>;
-
-              msi-parent = <&msi0>;
-
-              /* iProc event queue based MSI */
-              msi0: msi {
-                 compatible = "brcm,iproc-msi";
-                 msi-controller;
-                 interrupt-parent = <&gic>;
-                 interrupts = <GIC_SPI 96 IRQ_TYPE_NONE>,
-                         <GIC_SPI 97 IRQ_TYPE_NONE>,
-                         <GIC_SPI 98 IRQ_TYPE_NONE>,
-                         <GIC_SPI 99 IRQ_TYPE_NONE>;
-              };
-           };
-
-           pcie1: pcie@18013000 {
-              compatible = "brcm,iproc-pcie";
-              reg = <0x18013000 0x1000>;
-
-              #interrupt-cells = <1>;
-              interrupt-map-mask = <0 0 0 0>;
-              interrupt-map = <0 0 0 0 &gic GIC_SPI 106 IRQ_TYPE_NONE>;
-
-              linux,pci-domain = <1>;
-
-              bus-range = <0x00 0xff>;
-
-              #address-cells = <3>;
-              #size-cells = <2>;
-              device_type = "pci";
-              ranges = <0x81000000 0 0     0x48000000 0 0x00010000>,
-                   <0x82000000 0 0x40000000 0x40000000 0 0x04000000>;
-
-              phys = <&phy 1 6>;
-              phy-names = "pcie-phy";
-           };
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    gic: interrupt-controller {
+        interrupt-controller;
+        #interrupt-cells = <3>;
+    };
+
+    pcie@18012000 {
+        compatible = "brcm,iproc-pcie";
+        reg = <0x18012000 0x1000>;
+
+        #interrupt-cells = <1>;
+        interrupt-map-mask = <0 0 0 0>;
+        interrupt-map = <0 0 0 0 &gic GIC_SPI 100 IRQ_TYPE_NONE>;
+
+        linux,pci-domain = <0>;
+
+        bus-range = <0x00 0xff>;
+
+        #address-cells = <3>;
+        #size-cells = <2>;
+        device_type = "pci";
+        ranges = <0x81000000 0          0 0x28000000 0 0x00010000>,
+                 <0x82000000 0 0x20000000 0x20000000 0 0x04000000>;
+
+        phys = <&phy 0 5>;
+        phy-names = "pcie-phy";
+
+        brcm,pcie-ob;
+        brcm,pcie-ob-axi-offset = <0x00000000>;
+
+        msi-parent = <&msi0>;
+
+        /* iProc event queue based MSI */
+        msi0: msi {
+            compatible = "brcm,iproc-msi";
+            msi-controller;
+            interrupt-parent = <&gic>;
+            interrupts = <GIC_SPI 96 IRQ_TYPE_NONE>,
+                    <GIC_SPI 97 IRQ_TYPE_NONE>,
+                    <GIC_SPI 98 IRQ_TYPE_NONE>,
+                    <GIC_SPI 99 IRQ_TYPE_NONE>;
+        };
+    };
+  - |
+    pcie@18013000 {
+        compatible = "brcm,iproc-pcie";
+        reg = <0x18013000 0x1000>;
+
+        #interrupt-cells = <1>;
+        interrupt-map-mask = <0 0 0 0>;
+        interrupt-map = <0 0 0 0 &gic GIC_SPI 106 IRQ_TYPE_NONE>;
+
+        linux,pci-domain = <1>;
+
+        bus-range = <0x00 0xff>;
+
+        #address-cells = <3>;
+        #size-cells = <2>;
+        device_type = "pci";
+        ranges = <0x81000000 0          0 0x48000000 0 0x00010000>,
+                 <0x82000000 0 0x40000000 0x40000000 0 0x04000000>;
+
+        phys = <&phy 1 6>;
+        phy-names = "pcie-phy";
     };
index 38c0b52..97e8441 100644 (file)
@@ -91,6 +91,7 @@ properties:
 
   interrupt-controller:
     type: object
+    additionalProperties: false
     description: Describes the CPU's local interrupt controller
 
     properties:
index da2dcfe..510f6cb 100644 (file)
@@ -11,11 +11,16 @@ maintainers:
 
 properties:
   compatible:
-    items:
-      - enum:
-          - loongson,ls2k0500-pmc
-          - loongson,ls2k1000-pmc
-      - const: syscon
+    oneOf:
+      - items:
+          - const: loongson,ls2k0500-pmc
+          - const: syscon
+      - items:
+          - enum:
+              - loongson,ls2k1000-pmc
+              - loongson,ls2k2000-pmc
+          - const: loongson,ls2k0500-pmc
+          - const: syscon
 
   reg:
     maxItems: 1
@@ -32,6 +37,18 @@ properties:
       addition, the PM need according to it to indicate that current
       SoC whether support Suspend To RAM.
 
+  syscon-poweroff:
+    $ref: /schemas/power/reset/syscon-poweroff.yaml#
+    type: object
+    description:
+      Node for power off method
+
+  syscon-reboot:
+    $ref: /schemas/power/reset/syscon-reboot.yaml#
+    type: object
+    description:
+      Node for reboot method
+
 required:
   - compatible
   - reg
@@ -44,9 +61,23 @@ examples:
     #include <dt-bindings/interrupt-controller/irq.h>
 
     power-management@1fe27000 {
-        compatible = "loongson,ls2k1000-pmc", "syscon";
+        compatible = "loongson,ls2k1000-pmc", "loongson,ls2k0500-pmc", "syscon";
         reg = <0x1fe27000 0x58>;
         interrupt-parent = <&liointc1>;
         interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
         loongson,suspend-address = <0x0 0x1c000500>;
+
+        syscon-reboot {
+            compatible = "syscon-reboot";
+            offset = <0x30>;
+            mask = <0x1>;
+        };
+
+        syscon-poweroff {
+            compatible = "syscon-poweroff";
+            regmap = <&pmc>;
+            offset = <0x14>;
+            mask = <0x3c00>;
+            value = <0x3c00>;
+        };
     };
index 4b99a18..b7e6058 100644 (file)
@@ -56,6 +56,9 @@ properties:
       - const: clkext3
     minItems: 2
 
+  "#sound-dai-cells":
+    const: 0
+
 required:
   - compatible
   - reg
index 4f51b2f..c3c989e 100644 (file)
@@ -26,6 +26,7 @@ properties:
       - const: rockchip,rk3568-spdif
       - items:
           - enum:
+              - rockchip,rk3128-spdif
               - rockchip,rk3188-spdif
               - rockchip,rk3288-spdif
               - rockchip,rk3308-spdif
index 2f593c7..14cac0e 100644 (file)
@@ -23,6 +23,13 @@ properties:
       - const: fsl,imx51-ecspi
       - const: fsl,imx53-ecspi
       - items:
+          - enum:
+              - fsl,imx25-cspi
+              - fsl,imx50-cspi
+              - fsl,imx51-cspi
+              - fsl,imx53-cspi
+          - const: fsl,imx35-cspi
+      - items:
           - const: fsl,imx8mp-ecspi
           - const: fsl,imx6ul-ecspi
       - items:
index cd58179..430a814 100644 (file)
@@ -232,7 +232,7 @@ properties:
             # MEMSIC magnetometer
           - memsic,mmc35240
             # MEMSIC 3-axis accelerometer
-          - memsic,mx4005
+          - memsic,mxc4005
             # MEMSIC 2-axis 8-bit digital accelerometer
           - memsic,mxc6225
             # MEMSIC 2-axis 8-bit digital accelerometer
index 4654ee5..f200d78 100644 (file)
@@ -58,12 +58,14 @@ Here are the main features of EROFS:
 
  - Support extended attributes as an option;
 
+ - Support a bloom filter that speeds up negative extended attribute lookups;
+
  - Support POSIX.1e ACLs by using extended attributes;
 
  - Support transparent data compression as an option:
-   LZ4 and MicroLZMA algorithms can be used on a per-file basis; In addition,
-   inplace decompression is also supported to avoid bounce compressed buffers
-   and page cache thrashing.
+   LZ4, MicroLZMA and DEFLATE algorithms can be used on a per-file basis; In
+   addition, inplace decompression is also supported to avoid bounce compressed
+   buffers and unnecessary page cache thrashing.
 
  - Support chunk-based data deduplication and rolling-hash compressed data
    deduplication;
@@ -268,6 +270,38 @@ details.)
 
 By the way, chunk-based files are all uncompressed for now.
 
+Long extended attribute name prefixes
+-------------------------------------
+There are use cases where extended attributes with different values can have
+only a few common prefixes (such as overlayfs xattrs).  The predefined prefixes
+work inefficiently in both image size and runtime performance in such cases.
+
+The long xattr name prefixes feature is introduced to address this issue.  The
+overall idea is that, apart from the existing predefined prefixes, the xattr
+entry could also refer to user-specified long xattr name prefixes, e.g.
+"trusted.overlay.".
+
+When referring to a long xattr name prefix, the highest bit (bit 7) of
+erofs_xattr_entry.e_name_index is set, while the lower bits (bit 0-6) as a whole
+represent the index of the referred long name prefix among all long name
+prefixes.  Therefore, only the trailing part of the name apart from the long
+xattr name prefix is stored in erofs_xattr_entry.e_name, which could be empty if
+the full xattr name matches exactly as its long xattr name prefix.
+
+All long xattr prefixes are stored one by one in the packed inode as long as
+the packed inode is valid, or in the meta inode otherwise.  The
+xattr_prefix_count (of the on-disk superblock) indicates the total number of
+long xattr name prefixes, while (xattr_prefix_start * 4) indicates the start
+offset of long name prefixes in the packed/meta inode.  Note that, long extended
+attribute name prefixes are disabled if xattr_prefix_count is 0.
+
+Each long name prefix is stored in the format: ALIGN({__le16 len, data}, 4),
+where len represents the total size of the data part.  The data part is actually
+represented by 'struct erofs_xattr_long_prefix', where base_index represents the
+index of the predefined xattr name prefix, e.g. EROFS_XATTR_INDEX_TRUSTED for
+"trusted.overlay." long name prefix, while the infix string keeps the string
+after stripping the short prefix, e.g. "overlay." for the example above.
+
 Data compression
 ----------------
 EROFS implements fixed-sized output compression which generates fixed-sized
index deac4e9..4d05b98 100644 (file)
@@ -949,3 +949,99 @@ mmap_lock held.  All in-tree users have been audited and do not seem to
 depend on the mmap_lock being held, but out of tree users should verify
 for themselves.  If they do need it, they can return VM_FAULT_RETRY to
 be called with the mmap_lock held.
+
+---
+
+**mandatory**
+
+The order of opening block devices and matching or creating superblocks has
+changed.
+
+The old logic opened block devices first and then tried to find a
+suitable superblock to reuse based on the block device pointer.
+
+The new logic tries to find a suitable superblock first based on the device
+number, and opening the block device afterwards.
+
+Since opening block devices cannot happen under s_umount because of lock
+ordering requirements s_umount is now dropped while opening block devices and
+reacquired before calling fill_super().
+
+In the old logic concurrent mounters would find the superblock on the list of
+superblocks for the filesystem type. Since the first opener of the block device
+would hold s_umount they would wait until the superblock became either born or
+was discarded due to initialization failure.
+
+Since the new logic drops s_umount concurrent mounters could grab s_umount and
+would spin. Instead they are now made to wait using an explicit wait-wake
+mechanism without having to hold s_umount.
+
+---
+
+**mandatory**
+
+The holder of a block device is now the superblock.
+
+The holder of a block device used to be the file_system_type which wasn't
+particularly useful. It wasn't possible to go from block device to owning
+superblock without matching on the device pointer stored in the superblock.
+This mechanism would only work for a single device so the block layer couldn't
+find the owning superblock of any additional devices.
+
+In the old mechanism reusing or creating a superblock for a racing mount(2) and
+umount(2) relied on the file_system_type as the holder. This was severly
+underdocumented however:
+
+(1) Any concurrent mounter that managed to grab an active reference on an
+    existing superblock was made to wait until the superblock either became
+    ready or until the superblock was removed from the list of superblocks of
+    the filesystem type. If the superblock is ready the caller would simple
+    reuse it.
+
+(2) If the mounter came after deactivate_locked_super() but before
+    the superblock had been removed from the list of superblocks of the
+    filesystem type the mounter would wait until the superblock was shutdown,
+    reuse the block device and allocate a new superblock.
+
+(3) If the mounter came after deactivate_locked_super() and after
+    the superblock had been removed from the list of superblocks of the
+    filesystem type the mounter would reuse the block device and allocate a new
+    superblock (the bd_holder point may still be set to the filesystem type).
+
+Because the holder of the block device was the file_system_type any concurrent
+mounter could open the block devices of any superblock of the same
+file_system_type without risking seeing EBUSY because the block device was
+still in use by another superblock.
+
+Making the superblock the owner of the block device changes this as the holder
+is now a unique superblock and thus block devices associated with it cannot be
+reused by concurrent mounters. So a concurrent mounter in (2) could suddenly
+see EBUSY when trying to open a block device whose holder was a different
+superblock.
+
+The new logic thus waits until the superblock and the devices are shutdown in
+->kill_sb(). Removal of the superblock from the list of superblocks of the
+filesystem type is now moved to a later point when the devices are closed:
+
+(1) Any concurrent mounter managing to grab an active reference on an existing
+    superblock is made to wait until the superblock is either ready or until
+    the superblock and all devices are shutdown in ->kill_sb(). If the
+    superblock is ready the caller will simply reuse it.
+
+(2) If the mounter comes after deactivate_locked_super() but before
+    the superblock has been removed from the list of superblocks of the
+    filesystem type the mounter is made to wait until the superblock and the
+    devices are shut down in ->kill_sb() and the superblock is removed from the
+    list of superblocks of the filesystem type. The mounter will allocate a new
+    superblock and grab ownership of the block device (the bd_holder pointer of
+    the block device will be set to the newly allocated superblock).
+
+(3) This case is now collapsed into (2) as the superblock is left on the list
+    of superblocks of the filesystem type until all devices are shutdown in
+    ->kill_sb(). In other words, if the superblock isn't on the list of
+    superblock of the filesystem type anymore then it has given up ownership of
+    all associated block devices (the bd_holder pointer is NULL).
+
+As this is a VFS level change it has no practical consequences for filesystems
+other than that all of them must use one of the provided kill_litter_super(),
+kill_anon_super(), or kill_block_super() helpers.
index 858ed5d..0135905 100644 (file)
@@ -573,6 +573,32 @@ above, leading to:
        bool "Support for foo hardware"
        depends on ARCH_FOO_VENDOR || COMPILE_TEST
 
+Optional dependencies
+~~~~~~~~~~~~~~~~~~~~~
+
+Some drivers are able to optionally use a feature from another module
+or build cleanly with that module disabled, but cause a link failure
+when trying to use that loadable module from a built-in driver.
+
+The most common way to express this optional dependency in Kconfig logic
+uses the slightly counterintuitive::
+
+  config FOO
+       tristate "Support for foo hardware"
+       depends on BAR || !BAR
+
+This means that there is either a dependency on BAR that disallows
+the combination of FOO=y with BAR=m, or BAR is completely disabled.
+For a more formalized approach if there are multiple drivers that have
+the same dependency, a helper symbol can be used, like::
+
+  config FOO
+       tristate "Support for foo hardware"
+       depends on BAR_OPTIONAL
+
+  config BAR_OPTIONAL
+       def_tristate BAR || !BAR
+
 Kconfig recursive dependency limitations
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
index f060cfb..605e72c 100644 (file)
@@ -7,9 +7,9 @@ AX.25
 To use the amateur radio protocols within Linux you will need to get a
 suitable copy of the AX.25 Utilities. More detailed information about
 AX.25, NET/ROM and ROSE, associated programs and utilities can be
-found on http://www.linux-ax25.org.
+found on https://linux-ax25.in-berlin.de.
 
-There is an active mailing list for discussing Linux amateur radio matters
+There is a mailing list for discussing Linux amateur radio matters
 called linux-hams@vger.kernel.org. To subscribe to it, send a message to
 majordomo@vger.kernel.org with the words "subscribe linux-hams" in the body
 of the message, the subject field is ignored.  You don't need to be
index 45987f2..086487c 100644 (file)
@@ -74,8 +74,8 @@ topology based on those information.  When the device is older and
 doesn't respond to the new UMP inquiries, the driver falls back and
 builds the topology based on Group Terminal Block (GTB) information
 from the USB descriptor.  Some device might be screwed up by the
-unexpected UMP command; in such a case, pass `midi2_probe=0` option to
-snd-usb-audio driver for skipping the UMP v1.1 inquiries.
+unexpected UMP command; in such a case, pass `midi2_ump_probe=0`
+option to snd-usb-audio driver for skipping the UMP v1.1 inquiries.
 
 When the MIDI 2.0 device is probed, the kernel creates a rawmidi
 device for each UMP Endpoint of the device.  Its device name is
index 057db78..03b7f3d 100644 (file)
@@ -36,11 +36,11 @@ 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 *timerlat* threads to run under
-*SCHED_DEADLINE* priority, with a *10us* runtime every *1ms* period. The
+*SCHED_DEADLINE* priority, with a *100us* runtime every *1ms* period. The
 *1ms* period is also passed to the *timerlat* tracer. Auto-analysis is disabled
 to reduce overhead ::
 
-  [root@alien ~]# timerlat hist -d 10m -c 0-4 -P d:100us:1ms -p 1ms --no-aa
+  [root@alien ~]# timerlat hist -d 10m -c 0-4 -P d:100us:1ms -p 1000 --no-aa
   # RTLA timerlat histogram
   # Time unit is microseconds (us)
   # Duration:   0 00:10:00
index cba04be..59d6bf3 100644 (file)
@@ -344,9 +344,9 @@ LoongArch指令集架构的文档:
 
 LoongArch的ELF psABI文档:
 
-  https://github.com/loongson/LoongArch-Documentation/releases/latest/download/LoongArch-ELF-ABI-v2.00-CN.pdf (中文版)
+  https://github.com/loongson/LoongArch-Documentation/releases/latest/download/LoongArch-ELF-ABI-v2.01-CN.pdf (中文版)
 
-  https://github.com/loongson/LoongArch-Documentation/releases/latest/download/LoongArch-ELF-ABI-v2.00-EN.pdf (英文版)
+  https://github.com/loongson/LoongArch-Documentation/releases/latest/download/LoongArch-ELF-ABI-v2.01-EN.pdf (英文版)
 
 Loongson与LoongArch的Linux内核源码仓库:
 
index bf0f54c..7608b71 100644 (file)
@@ -470,7 +470,6 @@ F:  drivers/hwmon/adm1029.c
 ADM8211 WIRELESS DRIVER
 L:     linux-wireless@vger.kernel.org
 S:     Orphan
-W:     https://wireless.wiki.kernel.org/
 F:     drivers/net/wireless/admtek/adm8211.*
 
 ADP1653 FLASH CONTROLLER DRIVER
@@ -1585,6 +1584,17 @@ F:       arch/arm/include/asm/arch_timer.h
 F:     arch/arm64/include/asm/arch_timer.h
 F:     drivers/clocksource/arm_arch_timer.c
 
+ARM GENERIC INTERRUPT CONTROLLER DRIVERS
+M:     Marc Zyngier <maz@kernel.org>
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:     Maintained
+F:     Documentation/devicetree/bindings/interrupt-controller/arm,gic*
+F:     arch/arm/include/asm/arch_gicv3.h
+F:     arch/arm64/include/asm/arch_gicv3.h
+F:     drivers/irqchip/irq-gic*.[ch]
+F:     include/linux/irqchip/arm-gic*.h
+F:     include/linux/irqchip/arm-vgic-info.h
+
 ARM HDLCD DRM DRIVER
 M:     Liviu Dudau <liviu.dudau@arm.com>
 S:     Supported
@@ -1662,7 +1672,7 @@ F:        arch/arm*/include/asm/perf_event.h
 F:     arch/arm*/kernel/hw_breakpoint.c
 F:     arch/arm*/kernel/perf_*
 F:     drivers/perf/
-F:     include/linux/perf/arm_pmu.h
+F:     include/linux/perf/arm_pmu*.h
 
 ARM PORT
 M:     Russell King <linux@armlinux.org.uk>
@@ -1963,12 +1973,12 @@ F:      drivers/irqchip/irq-aspeed-i2c-ic.c
 
 ARM/ASPEED MACHINE SUPPORT
 M:     Joel Stanley <joel@jms.id.au>
-R:     Andrew Jeffery <andrew@aj.id.au>
+R:     Andrew Jeffery <andrew@codeconstruct.com.au>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 L:     linux-aspeed@lists.ozlabs.org (moderated for non-subscribers)
 S:     Supported
 Q:     https://patchwork.ozlabs.org/project/linux-aspeed/list/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/joel/aspeed.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/joel/bmc.git
 F:     Documentation/devicetree/bindings/arm/aspeed/
 F:     arch/arm/boot/dts/aspeed/
 F:     arch/arm/mach-aspeed/
@@ -3058,7 +3068,7 @@ F:        Documentation/devicetree/bindings/peci/peci-aspeed.yaml
 F:     drivers/peci/controller/peci-aspeed.c
 
 ASPEED PINCTRL DRIVERS
-M:     Andrew Jeffery <andrew@aj.id.au>
+M:     Andrew Jeffery <andrew@codeconstruct.com.au>
 L:     linux-aspeed@lists.ozlabs.org (moderated for non-subscribers)
 L:     openbmc@lists.ozlabs.org (moderated for non-subscribers)
 L:     linux-gpio@vger.kernel.org
@@ -3075,7 +3085,7 @@ F:        drivers/irqchip/irq-aspeed-scu-ic.c
 F:     include/dt-bindings/interrupt-controller/aspeed-scu-ic.h
 
 ASPEED SD/MMC DRIVER
-M:     Andrew Jeffery <andrew@aj.id.au>
+M:     Andrew Jeffery <andrew@codeconstruct.com.au>
 L:     linux-aspeed@lists.ozlabs.org (moderated for non-subscribers)
 L:     openbmc@lists.ozlabs.org (moderated for non-subscribers)
 L:     linux-mmc@vger.kernel.org
@@ -3344,7 +3354,7 @@ AX.25 NETWORK LAYER
 M:     Ralf Baechle <ralf@linux-mips.org>
 L:     linux-hams@vger.kernel.org
 S:     Maintained
-W:     http://www.linux-ax25.org/
+W:     https://linux-ax25.in-berlin.de
 F:     include/net/ax25.h
 F:     include/uapi/linux/ax25.h
 F:     net/ax25/
@@ -4082,7 +4092,7 @@ F:        drivers/net/wireless/broadcom/brcm80211/
 
 BROADCOM BRCMSTB GPIO DRIVER
 M:     Doug Berger <opendmb@gmail.com>
-M:     Florian Fainelli <florian.fainelli@broadcom>
+M:     Florian Fainelli <florian.fainelli@broadcom.com>
 R:     Broadcom internal kernel review list <bcm-kernel-feedback-list@broadcom.com>
 S:     Supported
 F:     Documentation/devicetree/bindings/gpio/brcm,brcmstb-gpio.yaml
@@ -5985,8 +5995,8 @@ F:        include/linux/devm-helpers.h
 DEVICE-MAPPER  (LVM)
 M:     Alasdair Kergon <agk@redhat.com>
 M:     Mike Snitzer <snitzer@kernel.org>
-M:     dm-devel@redhat.com
-L:     dm-devel@redhat.com
+M:     dm-devel@lists.linux.dev
+L:     dm-devel@lists.linux.dev
 S:     Maintained
 W:     http://sources.redhat.com/dm
 Q:     http://patchwork.kernel.org/project/dm-devel/list/
@@ -6645,9 +6655,9 @@ F:        Documentation/devicetree/bindings/display/panel/novatek,nt36672a.yaml
 F:     drivers/gpu/drm/panel/panel-novatek-nt36672a.c
 
 DRM DRIVER FOR NVIDIA GEFORCE/QUADRO GPUS
-M:     Ben Skeggs <bskeggs@redhat.com>
 M:     Karol Herbst <kherbst@redhat.com>
 M:     Lyude Paul <lyude@redhat.com>
+M:     Danilo Krummrich <dakr@redhat.com>
 L:     dri-devel@lists.freedesktop.org
 L:     nouveau@lists.freedesktop.org
 S:     Supported
@@ -8874,7 +8884,7 @@ F:        drivers/gpio/gpio-mockup.c
 F:     tools/testing/selftests/gpio/
 
 GPIO REGMAP
-R:     Michael Walle <michael@walle.cc>
+M:     Michael Walle <michael@walle.cc>
 S:     Maintained
 F:     drivers/gpio/gpio-regmap.c
 F:     include/linux/gpio/regmap.h
@@ -9531,10 +9541,8 @@ F:       Documentation/devicetree/bindings/iio/pressure/honeywell,mprls0025pa.yaml
 F:     drivers/iio/pressure/mprls0025pa.c
 
 HOST AP DRIVER
-M:     Jouni Malinen <j@w1.fi>
 L:     linux-wireless@vger.kernel.org
 S:     Obsolete
-W:     http://w1.fi/hostap-driver.html
 F:     drivers/net/wireless/intersil/hostap/
 
 HP BIOSCFG DRIVER
@@ -11063,7 +11071,7 @@ F:      Documentation/devicetree/bindings/sound/irondevice,*
 F:     sound/soc/codecs/sma*
 
 IRQ DOMAINS (IRQ NUMBER MAPPING LIBRARY)
-M:     Marc Zyngier <maz@kernel.org>
+M:     Thomas Gleixner <tglx@linutronix.de>
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq/core
 F:     Documentation/core-api/irq/irq-domain.rst
@@ -11082,7 +11090,6 @@ F:      lib/group_cpus.c
 
 IRQCHIP DRIVERS
 M:     Thomas Gleixner <tglx@linutronix.de>
-M:     Marc Zyngier <maz@kernel.org>
 L:     linux-kernel@vger.kernel.org
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq/core
@@ -13616,6 +13623,7 @@ F:      drivers/net/ethernet/mellanox/mlxfw/
 
 MELLANOX HARDWARE PLATFORM SUPPORT
 M:     Hans de Goede <hdegoede@redhat.com>
+M:     Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
 M:     Mark Gross <markgross@kernel.org>
 M:     Vadim Pasternak <vadimp@nvidia.com>
 L:     platform-driver-x86@vger.kernel.org
@@ -14210,6 +14218,7 @@ F:      drivers/platform/surface/surface_gpe.c
 
 MICROSOFT SURFACE HARDWARE PLATFORM SUPPORT
 M:     Hans de Goede <hdegoede@redhat.com>
+M:     Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
 M:     Mark Gross <markgross@kernel.org>
 M:     Maximilian Luz <luzmaximilian@gmail.com>
 L:     platform-driver-x86@vger.kernel.org
@@ -14756,7 +14765,7 @@ NETROM NETWORK LAYER
 M:     Ralf Baechle <ralf@linux-mips.org>
 L:     linux-hams@vger.kernel.org
 S:     Maintained
-W:     http://www.linux-ax25.org/
+W:     https://linux-ax25.in-berlin.de
 F:     include/net/netrom.h
 F:     include/uapi/linux/netrom.h
 F:     net/netrom/
@@ -14945,7 +14954,7 @@ K:      macsec
 K:     \bmdo_
 
 NETWORKING [MPTCP]
-M:     Matthieu Baerts <matthieu.baerts@tessares.net>
+M:     Matthieu Baerts <matttbe@kernel.org>
 M:     Mat Martineau <martineau@kernel.org>
 L:     netdev@vger.kernel.org
 L:     mptcp@lists.linux.dev
@@ -17600,6 +17609,7 @@ M:      Kalle Valo <kvalo@kernel.org>
 M:     Jeff Johnson <quic_jjohnson@quicinc.com>
 L:     ath12k@lists.infradead.org
 S:     Supported
+W:     https://wireless.wiki.kernel.org/en/users/Drivers/ath12k
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
 F:     drivers/net/wireless/ath/ath12k/
 
@@ -18130,8 +18140,6 @@ REALTEK WIRELESS DRIVER (rtlwifi family)
 M:     Ping-Ke Shih <pkshih@realtek.com>
 L:     linux-wireless@vger.kernel.org
 S:     Maintained
-W:     https://wireless.wiki.kernel.org/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
 F:     drivers/net/wireless/realtek/rtlwifi/
 
 REALTEK WIRELESS DRIVER (rtw88)
@@ -18607,7 +18615,7 @@ ROSE NETWORK LAYER
 M:     Ralf Baechle <ralf@linux-mips.org>
 L:     linux-hams@vger.kernel.org
 S:     Maintained
-W:     http://www.linux-ax25.org/
+W:     https://linux-ax25.in-berlin.de
 F:     include/net/rose.h
 F:     include/uapi/linux/rose.h
 F:     net/rose/
@@ -18659,7 +18667,6 @@ F:      drivers/media/dvb-frontends/rtl2832_sdr*
 RTL8180 WIRELESS DRIVER
 L:     linux-wireless@vger.kernel.org
 S:     Orphan
-W:     https://wireless.wiki.kernel.org/
 F:     drivers/net/wireless/realtek/rtl818x/rtl8180/
 
 RTL8187 WIRELESS DRIVER
@@ -18667,14 +18674,12 @@ M:    Hin-Tak Leung <hintak.leung@gmail.com>
 M:     Larry Finger <Larry.Finger@lwfinger.net>
 L:     linux-wireless@vger.kernel.org
 S:     Maintained
-W:     https://wireless.wiki.kernel.org/
 F:     drivers/net/wireless/realtek/rtl818x/rtl8187/
 
 RTL8XXXU WIRELESS DRIVER (rtl8xxxu)
 M:     Jes Sorensen <Jes.Sorensen@gmail.com>
 L:     linux-wireless@vger.kernel.org
 S:     Maintained
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jes/linux.git rtl8xxxu-devel
 F:     drivers/net/wireless/realtek/rtl8xxxu/
 
 RTRS TRANSPORT DRIVERS
@@ -21656,7 +21661,6 @@ L:      linux-wireless@vger.kernel.org
 S:     Orphan
 W:     https://wireless.wiki.kernel.org/en/users/Drivers/wl12xx
 W:     https://wireless.wiki.kernel.org/en/users/Drivers/wl1251
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/luca/wl12xx.git
 F:     drivers/net/wireless/ti/
 
 TIMEKEEPING, CLOCKSOURCE CORE, NTP, ALARMTIMER
@@ -23423,9 +23427,11 @@ F:     drivers/platform/x86/x86-android-tablets/
 
 X86 PLATFORM DRIVERS
 M:     Hans de Goede <hdegoede@redhat.com>
+M:     Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
 M:     Mark Gross <markgross@kernel.org>
 L:     platform-driver-x86@vger.kernel.org
 S:     Maintained
+Q:     https://patchwork.kernel.org/project/platform-driver-x86/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86.git
 F:     drivers/platform/olpc/
 F:     drivers/platform/x86/
index 57698d0..88ebf65 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
 VERSION = 6
 PATCHLEVEL = 6
 SUBLEVEL = 0
-EXTRAVERSION = -rc2
+EXTRAVERSION = -rc5
 NAME = Hurr durr I'ma ninja sloth
 
 # *DOCUMENTATION*
index 091ba31..d2d516d 100644 (file)
 /* Configure pwm clock source for timers 8 & 9 */
 &timer8 {
        assigned-clocks = <&abe_clkctrl OMAP4_TIMER8_CLKCTRL 24>;
-       assigned-clock-parents = <&sys_clkin_ck>;
+       assigned-clock-parents = <&sys_32k_ck>;
 };
 
 &timer9 {
        assigned-clocks = <&l4_per_clkctrl OMAP4_TIMER9_CLKCTRL 24>;
-       assigned-clock-parents = <&sys_clkin_ck>;
+       assigned-clock-parents = <&sys_32k_ck>;
 };
 
 /*
 &uart3 {
        interrupts-extended = <&wakeupgen GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH
                               &omap4_pmx_core 0x17c>;
+       overrun-throttle-ms = <500>;
 };
 
 &uart4 {
index 0da759f..7dd2340 100644 (file)
@@ -12,8 +12,7 @@ cpu_thermal: cpu-thermal {
        polling-delay = <1000>; /* milliseconds */
        coefficients = <0 20000>;
 
-                       /* sensor       ID */
-       thermal-sensors = <&bandgap     0>;
+       thermal-sensors = <&bandgap>;
 
        cpu_trips: trips {
                cpu_alert0: cpu_alert {
index 801b4f1..d484ec1 100644 (file)
@@ -12,7 +12,10 @@ cpu_thermal: cpu_thermal {
        polling-delay-passive = <250>; /* milliseconds */
        polling-delay = <1000>; /* milliseconds */
 
-                       /* sensor       ID */
+       /*
+        * See 44xx files for single sensor addressing, omap5 and dra7 need
+        * also sensor ID for addressing.
+        */
        thermal-sensors = <&bandgap     0>;
 
        cpu_trips: trips {
index 238aceb..2104170 100644 (file)
@@ -69,6 +69,7 @@
 };
 
 &cpu_thermal {
+       thermal-sensors = <&bandgap>;
        coefficients = <0 20000>;
 };
 
index 1b27a86..a676475 100644 (file)
@@ -79,6 +79,7 @@
 };
 
 &cpu_thermal {
+       thermal-sensors = <&bandgap>;
        coefficients = <348 (-9301)>;
 };
 
index 246a3de..aaaedaf 100644 (file)
@@ -195,7 +195,7 @@ struct locomo_driver {
 
 #define LOCOMO_DRIVER_NAME(_ldev) ((_ldev)->dev.driver->name)
 
-void locomo_lcd_power(struct locomo_dev *, int, unsigned int);
+extern void locomolcd_power(int on);
 
 int locomo_driver_register(struct locomo_driver *);
 void locomo_driver_unregister(struct locomo_driver *);
index f57802f..37b1681 100644 (file)
@@ -99,7 +99,7 @@ static int omap4_pm_suspend(void)
                 * possible causes.
                 * http://www.spinics.net/lists/arm-kernel/msg218641.html
                 */
-               pr_warn("A possible cause could be an old bootloader - try u-boot >= v2012.07\n");
+               pr_debug("A possible cause could be an old bootloader - try u-boot >= v2012.07\n");
        } else {
                pr_info("Successfully put all powerdomains to target state\n");
        }
@@ -257,7 +257,7 @@ int __init omap4_pm_init(void)
         * http://www.spinics.net/lists/arm-kernel/msg218641.html
         */
        if (cpu_is_omap44xx())
-               pr_warn("OMAP4 PM: u-boot >= v2012.07 is required for full PM support\n");
+               pr_debug("OMAP4 PM: u-boot >= v2012.07 is required for full PM support\n");
 
        ret = pwrdm_for_each(pwrdms_setup, NULL);
        if (ret) {
index b7bc23f..c95273c 100644 (file)
@@ -16,8 +16,6 @@
 
 #include "hardware.h" /* Gives GPIO_MAX */
 
-extern void locomolcd_power(int on);
-
 #define COLLIE_SCOOP_GPIO_BASE (GPIO_MAX + 1)
 #define COLLIE_GPIO_CHARGE_ON  (COLLIE_SCOOP_GPIO_BASE + 0)
 #define COLLIE_SCP_DIAG_BOOT1  SCOOP_GPCR_PA12
index ff28814..84a2f17 100644 (file)
                ((op & UNIPHIER_SSCOQM_S_MASK) == UNIPHIER_SSCOQM_S_RANGE)
 
 /**
- * uniphier_cache_data - UniPhier outer cache specific data
+ * struct uniphier_cache_data - UniPhier outer cache specific data
  *
  * @ctrl_base: virtual base address of control registers
  * @rev_base: virtual base address of revision registers
  * @op_base: virtual base address of operation registers
+ * @way_ctrl_base: virtual address of the way control registers for this
+ *     SoC revision
  * @way_mask: each bit specifies if the way is present
  * @nsets: number of associativity sets
  * @line_size: line size in bytes
index 7d59765..c392e18 100644 (file)
@@ -207,7 +207,7 @@ static void xen_power_off(void)
 
 static irqreturn_t xen_arm_callback(int irq, void *arg)
 {
-       xen_hvm_evtchn_do_upcall();
+       xen_evtchn_do_upcall();
        return IRQ_HANDLED;
 }
 
index b10515c..78f20e6 100644 (file)
@@ -1037,6 +1037,19 @@ config ARM64_ERRATUM_2645198
 
          If unsure, say Y.
 
+config ARM64_ERRATUM_2966298
+       bool "Cortex-A520: 2966298: workaround for speculatively executed unprivileged load"
+       default y
+       help
+         This option adds the workaround for ARM Cortex-A520 erratum 2966298.
+
+         On an affected Cortex-A520 core, a speculatively executed unprivileged
+         load might leak data from a privileged level via a cache side channel.
+
+         Work around this problem by executing a TLBI before returning to EL0.
+
+         If unsure, say Y.
+
 config CAVIUM_ERRATUM_22375
        bool "Cavium erratum 22375, 24313"
        default y
index c6872b7..89aee6c 100644 (file)
@@ -66,6 +66,7 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mm-mx8menlo.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-nitrogen-r2.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-phg.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-phyboard-polis-rdk.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8mm-prt8mm.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-tqma8mqml-mba8mx.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-var-som-symphony.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-venice-gw71xx-0x.dtb
index e31ab8b..a882c86 100644 (file)
@@ -26,7 +26,7 @@
 
                port {
                        hdmi_connector_in: endpoint {
-                               remote-endpoint = <&adv7533_out>;
+                               remote-endpoint = <&adv7535_out>;
                        };
                };
        };
                enable-active-high;
        };
 
+       reg_vddext_3v3: regulator-vddext-3v3 {
+               compatible = "regulator-fixed";
+               regulator-name = "VDDEXT_3V3";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+       };
+
        backlight: backlight {
                compatible = "pwm-backlight";
                pwms = <&pwm1 0 5000000 0>;
 
        hdmi@3d {
                compatible = "adi,adv7535";
-               reg = <0x3d>, <0x3c>, <0x3e>, <0x3f>;
-               reg-names = "main", "cec", "edid", "packet";
+               reg = <0x3d>;
+               interrupt-parent = <&gpio1>;
+               interrupts = <9 IRQ_TYPE_EDGE_FALLING>;
                adi,dsi-lanes = <4>;
-
-               adi,input-depth = <8>;
-               adi,input-colorspace = "rgb";
-               adi,input-clock = "1x";
-               adi,input-style = <1>;
-               adi,input-justification = "evenly";
+               avdd-supply = <&buck5_reg>;
+               dvdd-supply = <&buck5_reg>;
+               pvdd-supply = <&buck5_reg>;
+               a2vdd-supply = <&buck5_reg>;
+               v3p3-supply = <&reg_vddext_3v3>;
+               v1p2-supply = <&buck5_reg>;
 
                ports {
                        #address-cells = <1>;
                        port@0 {
                                reg = <0>;
 
-                               adv7533_in: endpoint {
+                               adv7535_in: endpoint {
                                        remote-endpoint = <&dsi_out>;
                                };
                        };
                        port@1 {
                                reg = <1>;
 
-                               adv7533_out: endpoint {
+                               adv7535_out: endpoint {
                                        remote-endpoint = <&hdmi_connector_in>;
                                };
                        };
                        reg = <1>;
 
                        dsi_out: endpoint {
-                               remote-endpoint = <&adv7533_in>;
+                               remote-endpoint = <&adv7535_in>;
                                data-lanes = <1 2 3 4>;
                        };
                };
index 06e9129..acd265d 100644 (file)
 &sai3 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_sai3>;
-       assigned-clocks = <&clk IMX8MP_CLK_SAI3>;
+       assigned-clocks = <&clk IMX8MP_CLK_SAI3>,
+                         <&clk IMX8MP_AUDIO_PLL2> ;
        assigned-clock-parents = <&clk IMX8MP_AUDIO_PLL2_OUT>;
-       assigned-clock-rates = <12288000>;
+       assigned-clock-rates = <12288000>, <361267200>;
        fsl,sai-mclk-direction-output;
        status = "okay";
 };
index 6f2f50e..83d9072 100644 (file)
                                                reg = <IMX8MP_POWER_DOMAIN_AUDIOMIX>;
                                                clocks = <&clk IMX8MP_CLK_AUDIO_ROOT>,
                                                         <&clk IMX8MP_CLK_AUDIO_AXI>;
+                                               assigned-clocks = <&clk IMX8MP_CLK_AUDIO_AHB>,
+                                                                 <&clk IMX8MP_CLK_AUDIO_AXI_SRC>;
+                                               assigned-clock-parents =  <&clk IMX8MP_SYS_PLL1_800M>,
+                                                                         <&clk IMX8MP_SYS_PLL1_800M>;
+                                               assigned-clock-rates = <400000000>,
+                                                                      <600000000>;
                                        };
 
                                        pgc_gpu2d: power-domain@6 {
index 1c71c08..f6e422d 100644 (file)
@@ -81,7 +81,7 @@
 &gpio1 {
        pmic-irq-hog {
                gpio-hog;
-               gpios = <2 GPIO_ACTIVE_LOW>;
+               gpios = <3 GPIO_ACTIVE_LOW>;
                input;
                line-name = "PMIC_IRQ#";
        };
index 4dbbf8f..a9e52b5 100644 (file)
                        clock-names = "merge","merge_async";
                        power-domains = <&spm MT8195_POWER_DOMAIN_VDOSYS1>;
                        mediatek,gce-client-reg = <&gce0 SUBSYS_1c10XXXX 0xc000 0x1000>;
-                       mediatek,merge-mute = <1>;
+                       mediatek,merge-mute;
                        resets = <&vdosys1 MT8195_VDOSYS1_SW0_RST_B_MERGE0_DL_ASYNC>;
                };
 
                        clock-names = "merge","merge_async";
                        power-domains = <&spm MT8195_POWER_DOMAIN_VDOSYS1>;
                        mediatek,gce-client-reg = <&gce0 SUBSYS_1c10XXXX 0xd000 0x1000>;
-                       mediatek,merge-mute = <1>;
+                       mediatek,merge-mute;
                        resets = <&vdosys1 MT8195_VDOSYS1_SW0_RST_B_MERGE1_DL_ASYNC>;
                };
 
                        clock-names = "merge","merge_async";
                        power-domains = <&spm MT8195_POWER_DOMAIN_VDOSYS1>;
                        mediatek,gce-client-reg = <&gce0 SUBSYS_1c10XXXX 0xe000 0x1000>;
-                       mediatek,merge-mute = <1>;
+                       mediatek,merge-mute;
                        resets = <&vdosys1 MT8195_VDOSYS1_SW0_RST_B_MERGE2_DL_ASYNC>;
                };
 
                        clock-names = "merge","merge_async";
                        power-domains = <&spm MT8195_POWER_DOMAIN_VDOSYS1>;
                        mediatek,gce-client-reg = <&gce0 SUBSYS_1c10XXXX 0xf000 0x1000>;
-                       mediatek,merge-mute = <1>;
+                       mediatek,merge-mute;
                        resets = <&vdosys1 MT8195_VDOSYS1_SW0_RST_B_MERGE3_DL_ASYNC>;
                };
 
                        clock-names = "merge","merge_async";
                        power-domains = <&spm MT8195_POWER_DOMAIN_VDOSYS1>;
                        mediatek,gce-client-reg = <&gce0 SUBSYS_1c11XXXX 0x0000 0x1000>;
-                       mediatek,merge-fifo-en = <1>;
+                       mediatek,merge-fifo-en;
                        resets = <&vdosys1 MT8195_VDOSYS1_SW0_RST_B_MERGE4_DL_ASYNC>;
                };
 
index a7c3020..06c5300 100644 (file)
 
                pdc: interrupt-controller@b220000 {
                        compatible = "qcom,sm8150-pdc", "qcom,pdc";
-                       reg = <0 0x0b220000 0 0x400>;
+                       reg = <0 0x0b220000 0 0x30000>;
                        qcom,pdc-ranges = <0 480 94>, <94 609 31>,
                                          <125 63 1>;
                        #interrupt-cells = <2>;
index 5315789..a789119 100644 (file)
@@ -636,6 +636,7 @@ CONFIG_POWER_RESET_MSM=y
 CONFIG_POWER_RESET_QCOM_PON=m
 CONFIG_POWER_RESET_XGENE=y
 CONFIG_POWER_RESET_SYSCON=y
+CONFIG_POWER_RESET_SYSCON_POWEROFF=y
 CONFIG_SYSCON_REBOOT_MODE=y
 CONFIG_NVMEM_REBOOT_MODE=m
 CONFIG_BATTERY_SBS=m
@@ -1175,7 +1176,6 @@ CONFIG_COMMON_CLK_S2MPS11=y
 CONFIG_COMMON_CLK_PWM=y
 CONFIG_COMMON_CLK_RS9_PCIE=y
 CONFIG_COMMON_CLK_VC5=y
-CONFIG_COMMON_CLK_NPCM8XX=y
 CONFIG_COMMON_CLK_BD718XX=m
 CONFIG_CLK_RASPBERRYPI=m
 CONFIG_CLK_IMX8MM=y
index 4d537d5..6792a1f 100644 (file)
@@ -9,6 +9,7 @@
 #ifndef _ASM_ACPI_H
 #define _ASM_ACPI_H
 
+#include <linux/cpuidle.h>
 #include <linux/efi.h>
 #include <linux/memblock.h>
 #include <linux/psci.h>
 
 #define ACPI_MADT_GICC_TRBE  (offsetof(struct acpi_madt_generic_interrupt, \
        trbe_interrupt) + sizeof(u16))
+/*
+ * Arm® Functional Fixed Hardware Specification Version 1.2.
+ * Table 2: Arm Architecture context loss flags
+ */
+#define CPUIDLE_CORE_CTXT              BIT(0) /* Core context Lost */
+
+static inline unsigned int arch_get_idle_state_flags(u32 arch_flags)
+{
+       if (arch_flags & CPUIDLE_CORE_CTXT)
+               return CPUIDLE_FLAG_TIMER_STOP;
+
+       return 0;
+}
+#define arch_get_idle_state_flags arch_get_idle_state_flags
+
+#define CPUIDLE_TRACE_CTXT             BIT(1) /* Trace context loss */
+#define CPUIDLE_GICR_CTXT              BIT(2) /* GICR */
+#define CPUIDLE_GICD_CTXT              BIT(3) /* GICD */
 
 /* Basic configuration for ACPI */
 #ifdef CONFIG_ACPI
index 96e5022..5bba393 100644 (file)
@@ -663,7 +663,7 @@ static inline bool supports_clearbhb(int scope)
                isar2 = read_sanitised_ftr_reg(SYS_ID_AA64ISAR2_EL1);
 
        return cpuid_feature_extract_unsigned_field(isar2,
-                                                   ID_AA64ISAR2_EL1_BC_SHIFT);
+                                                   ID_AA64ISAR2_EL1_CLRBHB_SHIFT);
 }
 
 const struct cpumask *system_32bit_el0_cpumask(void);
index 5f6f848..74d00fe 100644 (file)
@@ -79,6 +79,7 @@
 #define ARM_CPU_PART_CORTEX_A78AE      0xD42
 #define ARM_CPU_PART_CORTEX_X1         0xD44
 #define ARM_CPU_PART_CORTEX_A510       0xD46
+#define ARM_CPU_PART_CORTEX_A520       0xD80
 #define ARM_CPU_PART_CORTEX_A710       0xD47
 #define ARM_CPU_PART_CORTEX_A715       0xD4D
 #define ARM_CPU_PART_CORTEX_X2         0xD48
 #define MIDR_CORTEX_A78AE      MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A78AE)
 #define MIDR_CORTEX_X1 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X1)
 #define MIDR_CORTEX_A510 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A510)
+#define MIDR_CORTEX_A520 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A520)
 #define MIDR_CORTEX_A710 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A710)
 #define MIDR_CORTEX_A715 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A715)
 #define MIDR_CORTEX_X2 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X2)
index f43a38a..2ddc33d 100644 (file)
@@ -28,7 +28,7 @@ pte_t arch_make_huge_pte(pte_t entry, unsigned int shift, vm_flags_t flags);
 #define arch_make_huge_pte arch_make_huge_pte
 #define __HAVE_ARCH_HUGE_SET_HUGE_PTE_AT
 extern void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
-                           pte_t *ptep, pte_t pte);
+                           pte_t *ptep, pte_t pte, unsigned long sz);
 #define __HAVE_ARCH_HUGE_PTEP_SET_ACCESS_FLAGS
 extern int huge_ptep_set_access_flags(struct vm_area_struct *vma,
                                      unsigned long addr, pte_t *ptep,
index 5882b24..1095c66 100644 (file)
  */
 #define __HFGRTR_EL2_RES0      (GENMASK(63, 56) | GENMASK(53, 51))
 #define __HFGRTR_EL2_MASK      GENMASK(49, 0)
-#define __HFGRTR_EL2_nMASK     (GENMASK(55, 54) | BIT(50))
+#define __HFGRTR_EL2_nMASK     (GENMASK(58, 57) | GENMASK(55, 54) | BIT(50))
 
 #define __HFGWTR_EL2_RES0      (GENMASK(63, 56) | GENMASK(53, 51) |    \
                                 BIT(46) | BIT(42) | BIT(40) | BIT(28) | \
                                 GENMASK(26, 25) | BIT(21) | BIT(18) |  \
                                 GENMASK(15, 14) | GENMASK(10, 9) | BIT(2))
 #define __HFGWTR_EL2_MASK      GENMASK(49, 0)
-#define __HFGWTR_EL2_nMASK     (GENMASK(55, 54) | BIT(50))
+#define __HFGWTR_EL2_nMASK     (GENMASK(58, 57) | GENMASK(55, 54) | BIT(50))
 
 #define __HFGITR_EL2_RES0      GENMASK(63, 57)
 #define __HFGITR_EL2_MASK      GENMASK(54, 0)
index be66e94..5706e74 100644 (file)
@@ -730,6 +730,14 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
                .cpu_enable = cpu_clear_bf16_from_user_emulation,
        },
 #endif
+#ifdef CONFIG_ARM64_ERRATUM_2966298
+       {
+               .desc = "ARM erratum 2966298",
+               .capability = ARM64_WORKAROUND_2966298,
+               /* Cortex-A520 r0p0 - r0p1 */
+               ERRATA_MIDR_REV_RANGE(MIDR_CORTEX_A520, 0, 0, 1),
+       },
+#endif
 #ifdef CONFIG_AMPERE_ERRATUM_AC03_CPU_38
        {
                .desc = "AmpereOne erratum AC03_CPU_38",
index b018ae1..444a73c 100644 (file)
@@ -222,7 +222,8 @@ static const struct arm64_ftr_bits ftr_id_aa64isar1[] = {
 static const struct arm64_ftr_bits ftr_id_aa64isar2[] = {
        ARM64_FTR_BITS(FTR_VISIBLE, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64ISAR2_EL1_CSSC_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_VISIBLE, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64ISAR2_EL1_RPRFM_SHIFT, 4, 0),
-       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_HIGHER_SAFE, ID_AA64ISAR2_EL1_BC_SHIFT, 4, 0),
+       ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR2_EL1_CLRBHB_SHIFT, 4, 0),
+       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR2_EL1_BC_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR2_EL1_MOPS_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_PTR_AUTH),
                       FTR_STRICT, FTR_EXACT, ID_AA64ISAR2_EL1_APA3_SHIFT, 4, 0),
index 6ad61de..a603091 100644 (file)
@@ -428,6 +428,10 @@ alternative_else_nop_endif
        ldp     x28, x29, [sp, #16 * 14]
 
        .if     \el == 0
+alternative_if ARM64_WORKAROUND_2966298
+       tlbi    vale1, xzr
+       dsb     nsh
+alternative_else_nop_endif
 alternative_if_not ARM64_UNMAP_KERNEL_AT_EL0
        ldr     lr, [sp, #S_LR]
        add     sp, sp, #PT_REGS_SIZE           // restore sp
index 6dcdae4..a1e2422 100644 (file)
@@ -55,11 +55,6 @@ static struct irq_ops arch_timer_irq_ops = {
        .get_input_level = kvm_arch_timer_get_input_level,
 };
 
-static bool has_cntpoff(void)
-{
-       return (has_vhe() && cpus_have_final_cap(ARM64_HAS_ECV_CNTPOFF));
-}
-
 static int nr_timers(struct kvm_vcpu *vcpu)
 {
        if (!vcpu_has_nv(vcpu))
@@ -180,7 +175,7 @@ u64 kvm_phys_timer_read(void)
        return timecounter->cc->read(timecounter->cc);
 }
 
-static void get_timer_map(struct kvm_vcpu *vcpu, struct timer_map *map)
+void get_timer_map(struct kvm_vcpu *vcpu, struct timer_map *map)
 {
        if (vcpu_has_nv(vcpu)) {
                if (is_hyp_ctxt(vcpu)) {
@@ -548,8 +543,7 @@ static void timer_save_state(struct arch_timer_context *ctx)
                timer_set_ctl(ctx, read_sysreg_el0(SYS_CNTP_CTL));
                cval = read_sysreg_el0(SYS_CNTP_CVAL);
 
-               if (!has_cntpoff())
-                       cval -= timer_get_offset(ctx);
+               cval -= timer_get_offset(ctx);
 
                timer_set_cval(ctx, cval);
 
@@ -636,8 +630,7 @@ static void timer_restore_state(struct arch_timer_context *ctx)
                cval = timer_get_cval(ctx);
                offset = timer_get_offset(ctx);
                set_cntpoff(offset);
-               if (!has_cntpoff())
-                       cval += offset;
+               cval += offset;
                write_sysreg_el0(cval, SYS_CNTP_CVAL);
                isb();
                write_sysreg_el0(timer_get_ctl(ctx), SYS_CNTP_CTL);
index 9ced1bf..ee902ff 100644 (file)
@@ -977,6 +977,8 @@ enum fg_filter_id {
 
 static const struct encoding_to_trap_config encoding_to_fgt[] __initconst = {
        /* HFGRTR_EL2, HFGWTR_EL2 */
+       SR_FGT(SYS_PIR_EL1,             HFGxTR, nPIR_EL1, 0),
+       SR_FGT(SYS_PIRE0_EL1,           HFGxTR, nPIRE0_EL1, 0),
        SR_FGT(SYS_TPIDR2_EL0,          HFGxTR, nTPIDR2_EL0, 0),
        SR_FGT(SYS_SMPRI_EL1,           HFGxTR, nSMPRI_EL1, 0),
        SR_FGT(SYS_ACCDATA_EL1,         HFGxTR, nACCDATA_EL1, 0),
index 6537f58..448b170 100644 (file)
@@ -39,6 +39,26 @@ static void __activate_traps(struct kvm_vcpu *vcpu)
 
        ___activate_traps(vcpu);
 
+       if (has_cntpoff()) {
+               struct timer_map map;
+
+               get_timer_map(vcpu, &map);
+
+               /*
+                * We're entrering the guest. Reload the correct
+                * values from memory now that TGE is clear.
+                */
+               if (map.direct_ptimer == vcpu_ptimer(vcpu))
+                       val = __vcpu_sys_reg(vcpu, CNTP_CVAL_EL0);
+               if (map.direct_ptimer == vcpu_hptimer(vcpu))
+                       val = __vcpu_sys_reg(vcpu, CNTHP_CVAL_EL2);
+
+               if (map.direct_ptimer) {
+                       write_sysreg_el0(val, SYS_CNTP_CVAL);
+                       isb();
+               }
+       }
+
        val = read_sysreg(cpacr_el1);
        val |= CPACR_ELx_TTA;
        val &= ~(CPACR_EL1_ZEN_EL0EN | CPACR_EL1_ZEN_EL1EN |
@@ -77,6 +97,30 @@ static void __deactivate_traps(struct kvm_vcpu *vcpu)
 
        write_sysreg(HCR_HOST_VHE_FLAGS, hcr_el2);
 
+       if (has_cntpoff()) {
+               struct timer_map map;
+               u64 val, offset;
+
+               get_timer_map(vcpu, &map);
+
+               /*
+                * We're exiting the guest. Save the latest CVAL value
+                * to memory and apply the offset now that TGE is set.
+                */
+               val = read_sysreg_el0(SYS_CNTP_CVAL);
+               if (map.direct_ptimer == vcpu_ptimer(vcpu))
+                       __vcpu_sys_reg(vcpu, CNTP_CVAL_EL0) = val;
+               if (map.direct_ptimer == vcpu_hptimer(vcpu))
+                       __vcpu_sys_reg(vcpu, CNTHP_CVAL_EL2) = val;
+
+               offset = read_sysreg_s(SYS_CNTPOFF_EL2);
+
+               if (map.direct_ptimer && offset) {
+                       write_sysreg_el0(val + offset, SYS_CNTP_CVAL);
+                       isb();
+               }
+       }
+
        /*
         * ARM errata 1165522 and 1530923 require the actual execution of the
         * above before we can switch to the EL2/EL0 translation regime used by
index 0eea225..a243934 100644 (file)
@@ -39,7 +39,7 @@ void kvm_set_pmu_events(u32 set, struct perf_event_attr *attr)
 {
        struct kvm_pmu_events *pmu = kvm_get_pmu_events();
 
-       if (!kvm_arm_support_pmu_v3() || !pmu || !kvm_pmu_switch_needed(attr))
+       if (!kvm_arm_support_pmu_v3() || !kvm_pmu_switch_needed(attr))
                return;
 
        if (!attr->exclude_host)
@@ -55,7 +55,7 @@ void kvm_clr_pmu_events(u32 clr)
 {
        struct kvm_pmu_events *pmu = kvm_get_pmu_events();
 
-       if (!kvm_arm_support_pmu_v3() || !pmu)
+       if (!kvm_arm_support_pmu_v3())
                return;
 
        pmu->events_host &= ~clr;
index e92ec81..0afd613 100644 (file)
@@ -2122,8 +2122,8 @@ static const struct sys_reg_desc sys_reg_descs[] = {
        { SYS_DESC(SYS_PMMIR_EL1), trap_raz_wi },
 
        { SYS_DESC(SYS_MAIR_EL1), access_vm_reg, reset_unknown, MAIR_EL1 },
-       { SYS_DESC(SYS_PIRE0_EL1), access_vm_reg, reset_unknown, PIRE0_EL1 },
-       { SYS_DESC(SYS_PIR_EL1), access_vm_reg, reset_unknown, PIR_EL1 },
+       { SYS_DESC(SYS_PIRE0_EL1), NULL, reset_unknown, PIRE0_EL1 },
+       { SYS_DESC(SYS_PIR_EL1), NULL, reset_unknown, PIR_EL1 },
        { SYS_DESC(SYS_AMAIR_EL1), access_vm_reg, reset_amair_el1, AMAIR_EL1 },
 
        { SYS_DESC(SYS_LORSA_EL1), trap_loregion },
index 9c52718..13fd592 100644 (file)
@@ -241,15 +241,8 @@ static void clear_flush(struct mm_struct *mm,
        flush_tlb_range(&vma, saddr, addr);
 }
 
-static inline struct folio *hugetlb_swap_entry_to_folio(swp_entry_t entry)
-{
-       VM_BUG_ON(!is_migration_entry(entry) && !is_hwpoison_entry(entry));
-
-       return page_folio(pfn_to_page(swp_offset_pfn(entry)));
-}
-
 void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
-                           pte_t *ptep, pte_t pte)
+                           pte_t *ptep, pte_t pte, unsigned long sz)
 {
        size_t pgsize;
        int i;
@@ -257,13 +250,10 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
        unsigned long pfn, dpfn;
        pgprot_t hugeprot;
 
-       if (!pte_present(pte)) {
-               struct folio *folio;
-
-               folio = hugetlb_swap_entry_to_folio(pte_to_swp_entry(pte));
-               ncontig = num_contig_ptes(folio_size(folio), &pgsize);
+       ncontig = num_contig_ptes(sz, &pgsize);
 
-               for (i = 0; i < ncontig; i++, ptep++)
+       if (!pte_present(pte)) {
+               for (i = 0; i < ncontig; i++, ptep++, addr += pgsize)
                        set_pte_at(mm, addr, ptep, pte);
                return;
        }
@@ -273,7 +263,6 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
                return;
        }
 
-       ncontig = find_num_contig(mm, addr, ptep, &pgsize);
        pfn = pte_pfn(pte);
        dpfn = pgsize >> PAGE_SHIFT;
        hugeprot = pte_pgprot(pte);
@@ -571,5 +560,7 @@ pte_t huge_ptep_modify_prot_start(struct vm_area_struct *vma, unsigned long addr
 void huge_ptep_modify_prot_commit(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep,
                                  pte_t old_pte, pte_t pte)
 {
-       set_huge_pte_at(vma->vm_mm, addr, ptep, pte);
+       unsigned long psize = huge_page_size(hstate_vma(vma));
+
+       set_huge_pte_at(vma->vm_mm, addr, ptep, pte, psize);
 }
index c3f06fd..dea3dc8 100644 (file)
@@ -84,6 +84,7 @@ WORKAROUND_2077057
 WORKAROUND_2457168
 WORKAROUND_2645198
 WORKAROUND_2658417
+WORKAROUND_2966298
 WORKAROUND_AMPERE_AC03_CPU_38
 WORKAROUND_TRBE_OVERWRITE_FILL_MODE
 WORKAROUND_TSB_FLUSH_FAILURE
index 2517ef7..76ce150 100644 (file)
@@ -1347,7 +1347,11 @@ UnsignedEnum     51:48   RPRFM
        0b0000  NI
        0b0001  IMP
 EndEnum
-Res0   47:28
+Res0   47:32
+UnsignedEnum   31:28   CLRBHB
+       0b0000  NI
+       0b0001  IMP
+EndEnum
 UnsignedEnum   27:24   PAC_frac
        0b0000  NI
        0b0001  IMP
index 15f6cfd..41e8fe5 100644 (file)
@@ -907,3 +907,7 @@ EXPORT_SYMBOL(acpi_unregister_ioapic);
  * TBD when IA64 starts to support suspend...
  */
 int acpi_suspend_lowlevel(void) { return 0; }
+
+void acpi_proc_quirk_mwait_check(void)
+{
+}
index 5c9c03b..b24437e 100644 (file)
@@ -19,7 +19,7 @@
  */
 #ifndef __ASSEMBLY__
 #ifndef PHYS_OFFSET
-#define PHYS_OFFSET    _AC(0, UL)
+#define PHYS_OFFSET    _UL(0)
 #endif
 extern unsigned long vm_map_base;
 #endif /* __ASSEMBLY__ */
@@ -43,7 +43,7 @@ extern unsigned long vm_map_base;
  * Memory above this physical address will be considered highmem.
  */
 #ifndef HIGHMEM_START
-#define HIGHMEM_START          (_AC(1, UL) << _AC(DMW_PABITS, UL))
+#define HIGHMEM_START          (_UL(1) << _UL(DMW_PABITS))
 #endif
 
 #define TO_PHYS(x)             (               ((x) & TO_PHYS_MASK))
@@ -65,16 +65,16 @@ extern unsigned long vm_map_base;
 #define _ATYPE_
 #define _ATYPE32_
 #define _ATYPE64_
-#define _CONST64_(x)   x
 #else
 #define _ATYPE_                __PTRDIFF_TYPE__
 #define _ATYPE32_      int
 #define _ATYPE64_      __s64
+#endif
+
 #ifdef CONFIG_64BIT
-#define _CONST64_(x)   x ## UL
+#define _CONST64_(x)   _UL(x)
 #else
-#define _CONST64_(x)   x ## ULL
-#endif
+#define _CONST64_(x)   _ULL(x)
 #endif
 
 /*
index 7af0ceb..b9a4ab5 100644 (file)
 #define R_LARCH_TLS_GD_HI20                    98
 #define R_LARCH_32_PCREL                       99
 #define R_LARCH_RELAX                          100
+#define R_LARCH_DELETE                         101
+#define R_LARCH_ALIGN                          102
+#define R_LARCH_PCREL20_S2                     103
+#define R_LARCH_CFA                            104
+#define R_LARCH_ADD6                           105
+#define R_LARCH_SUB6                           106
+#define R_LARCH_ADD_ULEB128                    107
+#define R_LARCH_SUB_ULEB128                    108
+#define R_LARCH_64_PCREL                       109
 
 #ifndef ELF_ARCH
 
diff --git a/arch/loongarch/include/asm/exception.h b/arch/loongarch/include/asm/exception.h
new file mode 100644 (file)
index 0000000..af74a3f
--- /dev/null
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __ASM_EXCEPTION_H
+#define __ASM_EXCEPTION_H
+
+#include <asm/ptrace.h>
+#include <linux/kprobes.h>
+
+void show_registers(struct pt_regs *regs);
+
+asmlinkage void cache_parity_error(void);
+asmlinkage void noinstr do_ade(struct pt_regs *regs);
+asmlinkage void noinstr do_ale(struct pt_regs *regs);
+asmlinkage void noinstr do_bce(struct pt_regs *regs);
+asmlinkage void noinstr do_bp(struct pt_regs *regs);
+asmlinkage void noinstr do_ri(struct pt_regs *regs);
+asmlinkage void noinstr do_fpu(struct pt_regs *regs);
+asmlinkage void noinstr do_fpe(struct pt_regs *regs, unsigned long fcsr);
+asmlinkage void noinstr do_lsx(struct pt_regs *regs);
+asmlinkage void noinstr do_lasx(struct pt_regs *regs);
+asmlinkage void noinstr do_lbt(struct pt_regs *regs);
+asmlinkage void noinstr do_watch(struct pt_regs *regs);
+asmlinkage void noinstr do_syscall(struct pt_regs *regs);
+asmlinkage void noinstr do_reserved(struct pt_regs *regs);
+asmlinkage void noinstr do_vint(struct pt_regs *regs, unsigned long sp);
+asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
+                               unsigned long write, unsigned long address);
+
+asmlinkage void handle_ade(void);
+asmlinkage void handle_ale(void);
+asmlinkage void handle_bce(void);
+asmlinkage void handle_sys(void);
+asmlinkage void handle_bp(void);
+asmlinkage void handle_ri(void);
+asmlinkage void handle_fpu(void);
+asmlinkage void handle_fpe(void);
+asmlinkage void handle_lsx(void);
+asmlinkage void handle_lasx(void);
+asmlinkage void handle_lbt(void);
+asmlinkage void handle_watch(void);
+asmlinkage void handle_reserved(void);
+asmlinkage void handle_vint(void);
+asmlinkage void noinstr handle_loongarch_irq(struct pt_regs *regs);
+
+#endif /* __ASM_EXCEPTION_H */
index deeff81..cd6084f 100644 (file)
@@ -10,8 +10,6 @@
 #include <asm/io.h>
 #include <asm/pgtable.h>
 
-#define __HAVE_ARCH_SHADOW_MAP
-
 #define KASAN_SHADOW_SCALE_SHIFT 3
 #define KASAN_SHADOW_OFFSET    _AC(CONFIG_KASAN_SHADOW_OFFSET, UL)
 
 extern bool kasan_early_stage;
 extern unsigned char kasan_early_shadow_page[PAGE_SIZE];
 
+#define kasan_mem_to_shadow kasan_mem_to_shadow
+void *kasan_mem_to_shadow(const void *addr);
+
+#define kasan_shadow_to_mem kasan_shadow_to_mem
+const void *kasan_shadow_to_mem(const void *shadow_addr);
+
 #define kasan_arch_is_ready kasan_arch_is_ready
 static __always_inline bool kasan_arch_is_ready(void)
 {
        return !kasan_early_stage;
 }
 
-static inline void *kasan_mem_to_shadow(const void *addr)
-{
-       if (!kasan_arch_is_ready()) {
-               return (void *)(kasan_early_shadow_page);
-       } else {
-               unsigned long maddr = (unsigned long)addr;
-               unsigned long xrange = (maddr >> XRANGE_SHIFT) & 0xffff;
-               unsigned long offset = 0;
-
-               maddr &= XRANGE_SHADOW_MASK;
-               switch (xrange) {
-               case XKPRANGE_CC_SEG:
-                       offset = XKPRANGE_CC_SHADOW_OFFSET;
-                       break;
-               case XKPRANGE_UC_SEG:
-                       offset = XKPRANGE_UC_SHADOW_OFFSET;
-                       break;
-               case XKVRANGE_VC_SEG:
-                       offset = XKVRANGE_VC_SHADOW_OFFSET;
-                       break;
-               default:
-                       WARN_ON(1);
-                       return NULL;
-               }
-
-               return (void *)((maddr >> KASAN_SHADOW_SCALE_SHIFT) + offset);
-       }
-}
-
-static inline const void *kasan_shadow_to_mem(const void *shadow_addr)
+#define addr_has_metadata addr_has_metadata
+static __always_inline bool addr_has_metadata(const void *addr)
 {
-       unsigned long addr = (unsigned long)shadow_addr;
-
-       if (unlikely(addr > KASAN_SHADOW_END) ||
-               unlikely(addr < KASAN_SHADOW_START)) {
-               WARN_ON(1);
-               return NULL;
-       }
-
-       if (addr >= XKVRANGE_VC_SHADOW_OFFSET)
-               return (void *)(((addr - XKVRANGE_VC_SHADOW_OFFSET) << KASAN_SHADOW_SCALE_SHIFT) + XKVRANGE_VC_START);
-       else if (addr >= XKPRANGE_UC_SHADOW_OFFSET)
-               return (void *)(((addr - XKPRANGE_UC_SHADOW_OFFSET) << KASAN_SHADOW_SCALE_SHIFT) + XKPRANGE_UC_START);
-       else if (addr >= XKPRANGE_CC_SHADOW_OFFSET)
-               return (void *)(((addr - XKPRANGE_CC_SHADOW_OFFSET) << KASAN_SHADOW_SCALE_SHIFT) + XKPRANGE_CC_START);
-       else {
-               WARN_ON(1);
-               return NULL;
-       }
+       return (kasan_mem_to_shadow((void *)addr) != NULL);
 }
 
 void kasan_init(void);
index 66ecb48..f81e5f0 100644 (file)
@@ -70,6 +70,7 @@ struct secondary_data {
 extern struct secondary_data cpuboot_data;
 
 extern asmlinkage void smpboot_entry(void);
+extern asmlinkage void start_secondary(void);
 
 extern void calculate_cpu_foreign_map(void);
 
index c56ea0b..4fcc168 100644 (file)
@@ -19,6 +19,10 @@ obj-$(CONFIG_CPU_HAS_LBT)    += lbt.o
 
 obj-$(CONFIG_ARCH_STRICT_ALIGN)        += unaligned.o
 
+CFLAGS_module.o                += $(call cc-option,-Wno-override-init,)
+CFLAGS_syscall.o       += $(call cc-option,-Wno-override-init,)
+CFLAGS_perf_event.o    += $(call cc-option,-Wno-override-init,)
+
 ifdef CONFIG_FUNCTION_TRACER
   ifndef CONFIG_DYNAMIC_FTRACE
     obj-y += mcount.o ftrace.o
index 9450e09..8e00a75 100644 (file)
@@ -281,7 +281,6 @@ acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa)
        pr_info("SRAT: PXM %u -> CPU 0x%02x -> Node %u\n", pxm, pa->apic_id, node);
 }
 
-void __init acpi_numa_arch_fixup(void) {}
 #endif
 
 void __init arch_reserve_mem_area(acpi_physical_address addr, size_t size)
index 4a4107a..aed901c 100644 (file)
@@ -50,7 +50,6 @@ void __init memblock_init(void)
        }
 
        memblock_set_current_limit(PFN_PHYS(max_low_pfn));
-       memblock_set_node(0, PHYS_ADDR_MAX, &memblock.memory, 0);
 
        /* Reserve the first 2MB */
        memblock_reserve(PHYS_OFFSET, 0x200000);
@@ -58,4 +57,7 @@ void __init memblock_init(void)
        /* Reserve the kernel text/data/bss */
        memblock_reserve(__pa_symbol(&_text),
                         __pa_symbol(&_end) - __pa_symbol(&_text));
+
+       memblock_set_node(0, PHYS_ADDR_MAX, &memblock.memory, 0);
+       memblock_set_node(0, PHYS_ADDR_MAX, &memblock.reserved, 0);
 }
index d4dbcda..e2f30ff 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/elf.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/moduleloader.h>
 #include <linux/ftrace.h>
 
 Elf_Addr module_emit_got_entry(struct module *mod, Elf_Shdr *sechdrs, Elf_Addr val)
index b8b8608..b13b285 100644 (file)
@@ -367,6 +367,24 @@ static int apply_r_larch_got_pc(struct module *mod,
        return apply_r_larch_pcala(mod, location, got, rela_stack, rela_stack_top, type);
 }
 
+static int apply_r_larch_32_pcrel(struct module *mod, u32 *location, Elf_Addr v,
+                                 s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
+{
+       ptrdiff_t offset = (void *)v - (void *)location;
+
+       *(u32 *)location = offset;
+       return 0;
+}
+
+static int apply_r_larch_64_pcrel(struct module *mod, u32 *location, Elf_Addr v,
+                                 s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
+{
+       ptrdiff_t offset = (void *)v - (void *)location;
+
+       *(u64 *)location = offset;
+       return 0;
+}
+
 /*
  * reloc_handlers_rela() - Apply a particular relocation to a module
  * @mod: the module to apply the reloc to
@@ -382,7 +400,7 @@ typedef int (*reloc_rela_handler)(struct module *mod, u32 *location, Elf_Addr v,
 
 /* The handlers for known reloc types */
 static reloc_rela_handler reloc_rela_handlers[] = {
-       [R_LARCH_NONE ... R_LARCH_RELAX]                     = apply_r_larch_error,
+       [R_LARCH_NONE ... R_LARCH_64_PCREL]                  = apply_r_larch_error,
 
        [R_LARCH_NONE]                                       = apply_r_larch_none,
        [R_LARCH_32]                                         = apply_r_larch_32,
@@ -396,6 +414,8 @@ static reloc_rela_handler reloc_rela_handlers[] = {
        [R_LARCH_SOP_POP_32_S_10_5 ... R_LARCH_SOP_POP_32_U] = apply_r_larch_sop_imm_field,
        [R_LARCH_ADD32 ... R_LARCH_SUB64]                    = apply_r_larch_add_sub,
        [R_LARCH_PCALA_HI20...R_LARCH_PCALA64_HI12]          = apply_r_larch_pcala,
+       [R_LARCH_32_PCREL]                                   = apply_r_larch_32_pcrel,
+       [R_LARCH_64_PCREL]                                   = apply_r_larch_64_pcrel,
 };
 
 int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
index c7d33c4..6e65ff1 100644 (file)
@@ -436,7 +436,7 @@ void __init paging_init(void)
 
 void __init mem_init(void)
 {
-       high_memory = (void *) __va(get_num_physpages() << PAGE_SHIFT);
+       high_memory = (void *) __va(max_low_pfn << PAGE_SHIFT);
        memblock_free_all();
 }
 
index 3cb082e..767d94c 100644 (file)
@@ -37,6 +37,7 @@
 #include <asm/bootinfo.h>
 #include <asm/cpu.h>
 #include <asm/elf.h>
+#include <asm/exec.h>
 #include <asm/fpu.h>
 #include <asm/lbt.h>
 #include <asm/io.h>
index d132525..f49f6b0 100644 (file)
@@ -72,7 +72,6 @@ copy_word:
        LONG_ADDI       s5, s5, -1
        beqz            s5, process_entry
        b               copy_word
-       b               process_entry
 
 done:
        ibar            0
index 504fdfe..4a3686d 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/audit.h>
 #include <linux/cache.h>
 #include <linux/context_tracking.h>
+#include <linux/entry-common.h>
 #include <linux/irqflags.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
@@ -891,8 +892,8 @@ static unsigned long setup_extcontext(struct extctx_layout *extctx, unsigned lon
        return new_sp;
 }
 
-void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs,
-                         struct extctx_layout *extctx)
+static void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs,
+                                struct extctx_layout *extctx)
 {
        unsigned long sp;
 
@@ -922,7 +923,7 @@ void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs,
  * Atomically swap in the new signal mask, and wait for a signal.
  */
 
-asmlinkage long sys_rt_sigreturn(void)
+SYSCALL_DEFINE0(rt_sigreturn)
 {
        int sig;
        sigset_t set;
index 6667b0a..ef35c87 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/cpumask.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/profile.h>
 #include <linux/seq_file.h>
 #include <linux/smp.h>
 #include <linux/threads.h>
@@ -556,10 +557,12 @@ void smp_send_stop(void)
        smp_call_function(stop_this_cpu, NULL, 0);
 }
 
+#ifdef CONFIG_PROFILING
 int setup_profiling_timer(unsigned int multiplier)
 {
        return 0;
 }
+#endif
 
 static void flush_tlb_all_ipi(void *info)
 {
index 3fc4211..b4c5acd 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/unistd.h>
 
 #include <asm/asm.h>
+#include <asm/exception.h>
 #include <asm/signal.h>
 #include <asm/switch_to.h>
 #include <asm-generic/syscalls.h>
index c189e03..3064af9 100644 (file)
@@ -29,7 +29,7 @@ static void constant_event_handler(struct clock_event_device *dev)
 {
 }
 
-irqreturn_t constant_timer_interrupt(int irq, void *data)
+static irqreturn_t constant_timer_interrupt(int irq, void *data)
 {
        int cpu = smp_processor_id();
        struct clock_event_device *cd;
index caa7cd8..3fd1660 100644 (file)
@@ -1,4 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0
+#include <linux/acpi.h>
 #include <linux/cpu.h>
 #include <linux/cpumask.h>
 #include <linux/init.h>
@@ -7,6 +8,8 @@
 #include <linux/percpu.h>
 #include <asm/bootinfo.h>
 
+#include <acpi/processor.h>
+
 static DEFINE_PER_CPU(struct cpu, cpu_devices);
 
 #ifdef CONFIG_HOTPLUG_CPU
index 6521477..aebfc37 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/ptrace.h>
 #include <linux/kgdb.h>
 #include <linux/kdebug.h>
-#include <linux/kprobes.h>
 #include <linux/notifier.h>
 #include <linux/irq.h>
 #include <linux/perf_event.h>
@@ -35,6 +34,7 @@
 #include <asm/branch.h>
 #include <asm/break.h>
 #include <asm/cpu.h>
+#include <asm/exception.h>
 #include <asm/fpu.h>
 #include <asm/lbt.h>
 #include <asm/inst.h>
 
 #include "access-helper.h"
 
-extern asmlinkage void handle_ade(void);
-extern asmlinkage void handle_ale(void);
-extern asmlinkage void handle_bce(void);
-extern asmlinkage void handle_sys(void);
-extern asmlinkage void handle_bp(void);
-extern asmlinkage void handle_ri(void);
-extern asmlinkage void handle_fpu(void);
-extern asmlinkage void handle_fpe(void);
-extern asmlinkage void handle_lbt(void);
-extern asmlinkage void handle_lsx(void);
-extern asmlinkage void handle_lasx(void);
-extern asmlinkage void handle_reserved(void);
-extern asmlinkage void handle_watch(void);
-extern asmlinkage void handle_vint(void);
-
 static void show_backtrace(struct task_struct *task, const struct pt_regs *regs,
                           const char *loglvl, bool user)
 {
@@ -439,8 +424,8 @@ static inline void setup_vint_size(unsigned int size)
  * happen together with Overflow or Underflow, and `ptrace' can set
  * any bits.
  */
-void force_fcsr_sig(unsigned long fcsr, void __user *fault_addr,
-                    struct task_struct *tsk)
+static void force_fcsr_sig(unsigned long fcsr,
+                       void __user *fault_addr, struct task_struct *tsk)
 {
        int si_code = FPE_FLTUNK;
 
@@ -458,7 +443,7 @@ void force_fcsr_sig(unsigned long fcsr, void __user *fault_addr,
        force_sig_fault(SIGFPE, si_code, fault_addr);
 }
 
-int process_fpemu_return(int sig, void __user *fault_addr, unsigned long fcsr)
+static int process_fpemu_return(int sig, void __user *fault_addr, unsigned long fcsr)
 {
        int si_code;
 
@@ -824,7 +809,7 @@ out:
 asmlinkage void noinstr do_ri(struct pt_regs *regs)
 {
        int status = SIGILL;
-       unsigned int opcode = 0;
+       unsigned int __maybe_unused opcode;
        unsigned int __user *era = (unsigned int __user *)exception_era(regs);
        irqentry_state_t state = irqentry_enter(regs);
 
index b1686af..bb2ec86 100644 (file)
@@ -53,33 +53,6 @@ SECTIONS
        . = ALIGN(PECOFF_SEGMENT_ALIGN);
        _etext = .;
 
-       /*
-        * struct alt_inst entries. From the header (alternative.h):
-        * "Alternative instructions for different CPU types or capabilities"
-        * Think locking instructions on spinlocks.
-        */
-       . = ALIGN(4);
-       .altinstructions : AT(ADDR(.altinstructions) - LOAD_OFFSET) {
-               __alt_instructions = .;
-               *(.altinstructions)
-               __alt_instructions_end = .;
-       }
-
-#ifdef CONFIG_RELOCATABLE
-       . = ALIGN(8);
-       .la_abs : AT(ADDR(.la_abs) - LOAD_OFFSET) {
-               __la_abs_begin = .;
-               *(.la_abs)
-               __la_abs_end = .;
-       }
-#endif
-
-       .got : ALIGN(16) { *(.got) }
-       .plt : ALIGN(16) { *(.plt) }
-       .got.plt : ALIGN(16) { *(.got.plt) }
-
-       .data.rel : { *(.data.rel*) }
-
        . = ALIGN(PECOFF_SEGMENT_ALIGN);
        __init_begin = .;
        __inittext_begin = .;
@@ -94,6 +67,18 @@ SECTIONS
 
        __initdata_begin = .;
 
+       /*
+        * struct alt_inst entries. From the header (alternative.h):
+        * "Alternative instructions for different CPU types or capabilities"
+        * Think locking instructions on spinlocks.
+        */
+       . = ALIGN(4);
+       .altinstructions : AT(ADDR(.altinstructions) - LOAD_OFFSET) {
+               __alt_instructions = .;
+               *(.altinstructions)
+               __alt_instructions_end = .;
+       }
+
        INIT_DATA_SECTION(16)
        .exit.data : {
                EXIT_DATA
@@ -113,6 +98,11 @@ SECTIONS
 
        _sdata = .;
        RO_DATA(4096)
+
+       .got : ALIGN(16) { *(.got) }
+       .plt : ALIGN(16) { *(.plt) }
+       .got.plt : ALIGN(16) { *(.got.plt) }
+
        RW_DATA(1 << CONFIG_L1_CACHE_SHIFT, PAGE_SIZE, THREAD_SIZE)
 
        .rela.dyn : ALIGN(8) {
@@ -121,6 +111,17 @@ SECTIONS
                __rela_dyn_end = .;
        }
 
+       .data.rel : { *(.data.rel*) }
+
+#ifdef CONFIG_RELOCATABLE
+       . = ALIGN(8);
+       .la_abs : AT(ADDR(.la_abs) - LOAD_OFFSET) {
+               __la_abs_begin = .;
+               *(.la_abs)
+               __la_abs_end = .;
+       }
+#endif
+
        .sdata : {
                *(.sdata)
        }
index e6376e3..1fc2f68 100644 (file)
 #include <linux/mm.h>
 #include <linux/smp.h>
 #include <linux/kdebug.h>
-#include <linux/kprobes.h>
 #include <linux/perf_event.h>
 #include <linux/uaccess.h>
 #include <linux/kfence.h>
 
 #include <asm/branch.h>
+#include <asm/exception.h>
 #include <asm/mmu_context.h>
 #include <asm/ptrace.h>
 
index ba13811..1e76fcb 100644 (file)
@@ -50,18 +50,6 @@ pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr,
        return (pte_t *) pmd;
 }
 
-/*
- * This function checks for proper alignment of input addr and len parameters.
- */
-int is_aligned_hugepage_range(unsigned long addr, unsigned long len)
-{
-       if (len & ~HPAGE_MASK)
-               return -EINVAL;
-       if (addr & ~HPAGE_MASK)
-               return -EINVAL;
-       return 0;
-}
-
 int pmd_huge(pmd_t pmd)
 {
        return (pmd_val(pmd) & _PAGE_HUGE) != 0;
index 73b0980..70ca730 100644 (file)
@@ -4,6 +4,7 @@
  */
 
 #include <asm/io.h>
+#include <asm-generic/early_ioremap.h>
 
 void __init __iomem *early_ioremap(u64 phys_addr, unsigned long size)
 {
index da68bc1..cc3e81f 100644 (file)
@@ -35,6 +35,57 @@ static pgd_t kasan_pg_dir[PTRS_PER_PGD] __initdata __aligned(PAGE_SIZE);
 
 bool kasan_early_stage = true;
 
+void *kasan_mem_to_shadow(const void *addr)
+{
+       if (!kasan_arch_is_ready()) {
+               return (void *)(kasan_early_shadow_page);
+       } else {
+               unsigned long maddr = (unsigned long)addr;
+               unsigned long xrange = (maddr >> XRANGE_SHIFT) & 0xffff;
+               unsigned long offset = 0;
+
+               maddr &= XRANGE_SHADOW_MASK;
+               switch (xrange) {
+               case XKPRANGE_CC_SEG:
+                       offset = XKPRANGE_CC_SHADOW_OFFSET;
+                       break;
+               case XKPRANGE_UC_SEG:
+                       offset = XKPRANGE_UC_SHADOW_OFFSET;
+                       break;
+               case XKVRANGE_VC_SEG:
+                       offset = XKVRANGE_VC_SHADOW_OFFSET;
+                       break;
+               default:
+                       WARN_ON(1);
+                       return NULL;
+               }
+
+               return (void *)((maddr >> KASAN_SHADOW_SCALE_SHIFT) + offset);
+       }
+}
+
+const void *kasan_shadow_to_mem(const void *shadow_addr)
+{
+       unsigned long addr = (unsigned long)shadow_addr;
+
+       if (unlikely(addr > KASAN_SHADOW_END) ||
+               unlikely(addr < KASAN_SHADOW_START)) {
+               WARN_ON(1);
+               return NULL;
+       }
+
+       if (addr >= XKVRANGE_VC_SHADOW_OFFSET)
+               return (void *)(((addr - XKVRANGE_VC_SHADOW_OFFSET) << KASAN_SHADOW_SCALE_SHIFT) + XKVRANGE_VC_START);
+       else if (addr >= XKPRANGE_UC_SHADOW_OFFSET)
+               return (void *)(((addr - XKPRANGE_UC_SHADOW_OFFSET) << KASAN_SHADOW_SCALE_SHIFT) + XKPRANGE_UC_START);
+       else if (addr >= XKPRANGE_CC_SHADOW_OFFSET)
+               return (void *)(((addr - XKPRANGE_CC_SHADOW_OFFSET) << KASAN_SHADOW_SCALE_SHIFT) + XKPRANGE_CC_START);
+       else {
+               WARN_ON(1);
+               return NULL;
+       }
+}
+
 /*
  * Alloc memory for shadow memory page table.
  */
index eb8572e..2c0a411 100644 (file)
@@ -261,7 +261,7 @@ unsigned long pcpu_handlers[NR_CPUS];
 #endif
 extern long exception_handlers[VECSIZE * 128 / sizeof(long)];
 
-void setup_tlb_handler(int cpu)
+static void setup_tlb_handler(int cpu)
 {
        setup_ptwalker();
        local_flush_tlb_all();
index 012da04..7b9f91d 100644 (file)
@@ -164,6 +164,7 @@ static struct platform_device db1x00_audio_dev = {
 
 /******************************************************************************/
 
+#ifdef CONFIG_MMC_AU1X
 static irqreturn_t db1100_mmc_cd(int irq, void *ptr)
 {
        mmc_detect_change(ptr, msecs_to_jiffies(500));
@@ -369,6 +370,7 @@ static struct platform_device db1100_mmc1_dev = {
        .num_resources  = ARRAY_SIZE(au1100_mmc1_res),
        .resource       = au1100_mmc1_res,
 };
+#endif /* CONFIG_MMC_AU1X */
 
 /******************************************************************************/
 
@@ -440,8 +442,10 @@ static struct platform_device *db1x00_devs[] = {
 
 static struct platform_device *db1100_devs[] = {
        &au1100_lcd_device,
+#ifdef CONFIG_MMC_AU1X
        &db1100_mmc0_dev,
        &db1100_mmc1_dev,
+#endif
 };
 
 int __init db1000_dev_setup(void)
index 76080c7..f521874 100644 (file)
@@ -326,6 +326,7 @@ static struct platform_device db1200_ide_dev = {
 
 /**********************************************************************/
 
+#ifdef CONFIG_MMC_AU1X
 /* SD carddetects:  they're supposed to be edge-triggered, but ack
  * doesn't seem to work (CPLD Rev 2).  Instead, the screaming one
  * is disabled and its counterpart enabled.  The 200ms timeout is
@@ -584,6 +585,7 @@ static struct platform_device pb1200_mmc1_dev = {
        .num_resources  = ARRAY_SIZE(au1200_mmc1_res),
        .resource       = au1200_mmc1_res,
 };
+#endif /* CONFIG_MMC_AU1X */
 
 /**********************************************************************/
 
@@ -751,7 +753,9 @@ static struct platform_device db1200_audiodma_dev = {
 static struct platform_device *db1200_devs[] __initdata = {
        NULL,           /* PSC0, selected by S6.8 */
        &db1200_ide_dev,
+#ifdef CONFIG_MMC_AU1X
        &db1200_mmc0_dev,
+#endif
        &au1200_lcd_dev,
        &db1200_eth_dev,
        &db1200_nand_dev,
@@ -762,7 +766,9 @@ static struct platform_device *db1200_devs[] __initdata = {
 };
 
 static struct platform_device *pb1200_devs[] __initdata = {
+#ifdef CONFIG_MMC_AU1X
        &pb1200_mmc1_dev,
+#endif
 };
 
 /* Some peripheral base addresses differ on the PB1200 */
index ff61901..d377e04 100644 (file)
@@ -450,6 +450,7 @@ static struct platform_device db1300_ide_dev = {
 
 /**********************************************************************/
 
+#ifdef CONFIG_MMC_AU1X
 static irqreturn_t db1300_mmc_cd(int irq, void *ptr)
 {
        disable_irq_nosync(irq);
@@ -632,6 +633,7 @@ static struct platform_device db1300_sd0_dev = {
        .resource       = au1300_sd0_res,
        .num_resources  = ARRAY_SIZE(au1300_sd0_res),
 };
+#endif /* CONFIG_MMC_AU1X */
 
 /**********************************************************************/
 
@@ -767,8 +769,10 @@ static struct platform_device *db1300_dev[] __initdata = {
        &db1300_5waysw_dev,
        &db1300_nand_dev,
        &db1300_ide_dev,
+#ifdef CONFIG_MMC_AU1X
        &db1300_sd0_dev,
        &db1300_sd1_dev,
+#endif
        &db1300_lcd_dev,
        &db1300_ac97_dev,
        &db1300_i2s_dev,
index 7b2ac13..467ee6b 100644 (file)
@@ -592,7 +592,7 @@ static int kvm_mips_map_page(struct kvm_vcpu *vcpu, unsigned long gpa,
        gfn_t gfn = gpa >> PAGE_SHIFT;
        int srcu_idx, err;
        kvm_pfn_t pfn;
-       pte_t *ptep, entry, old_pte;
+       pte_t *ptep, entry;
        bool writeable;
        unsigned long prot_bits;
        unsigned long mmu_seq;
@@ -664,7 +664,6 @@ retry:
        entry = pfn_pte(pfn, __pgprot(prot_bits));
 
        /* Write the PTE */
-       old_pte = *ptep;
        set_pte(ptep, entry);
 
        err = 0;
index f7f078c..72daacc 100644 (file)
@@ -6,7 +6,7 @@
 
 #define __HAVE_ARCH_HUGE_SET_HUGE_PTE_AT
 void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
-                    pte_t *ptep, pte_t pte);
+                    pte_t *ptep, pte_t pte, unsigned long sz);
 
 #define __HAVE_ARCH_HUGE_PTEP_GET_AND_CLEAR
 pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
index 6d28b55..ee9e071 100644 (file)
@@ -2,39 +2,42 @@
 #ifndef __PARISC_LDCW_H
 #define __PARISC_LDCW_H
 
-#ifndef CONFIG_PA20
 /* Because kmalloc only guarantees 8-byte alignment for kmalloc'd data,
    and GCC only guarantees 8-byte alignment for stack locals, we can't
    be assured of 16-byte alignment for atomic lock data even if we
    specify "__attribute ((aligned(16)))" in the type declaration.  So,
    we use a struct containing an array of four ints for the atomic lock
    type and dynamically select the 16-byte aligned int from the array
-   for the semaphore.  */
+   for the semaphore. */
+
+/* From: "Jim Hull" <jim.hull of hp.com>
+   I've attached a summary of the change, but basically, for PA 2.0, as
+   long as the ",CO" (coherent operation) completer is implemented, then the
+   16-byte alignment requirement for ldcw and ldcd is relaxed, and instead
+   they only require "natural" alignment (4-byte for ldcw, 8-byte for
+   ldcd).
+
+   Although the cache control hint is accepted by all PA 2.0 processors,
+   it is only implemented on PA8800/PA8900 CPUs. Prior PA8X00 CPUs still
+   require 16-byte alignment. If the address is unaligned, the operation
+   of the instruction is undefined. The ldcw instruction does not generate
+   unaligned data reference traps so misaligned accesses are not detected.
+   This hid the problem for years. So, restore the 16-byte alignment dropped
+   by Kyle McMartin in "Remove __ldcw_align for PA-RISC 2.0 processors". */
 
 #define __PA_LDCW_ALIGNMENT    16
-#define __PA_LDCW_ALIGN_ORDER  4
 #define __ldcw_align(a) ({                                     \
        unsigned long __ret = (unsigned long) &(a)->lock[0];    \
        __ret = (__ret + __PA_LDCW_ALIGNMENT - 1)               \
                & ~(__PA_LDCW_ALIGNMENT - 1);                   \
        (volatile unsigned int *) __ret;                        \
 })
-#define __LDCW "ldcw"
 
-#else /*CONFIG_PA20*/
-/* From: "Jim Hull" <jim.hull of hp.com>
-   I've attached a summary of the change, but basically, for PA 2.0, as
-   long as the ",CO" (coherent operation) completer is specified, then the
-   16-byte alignment requirement for ldcw and ldcd is relaxed, and instead
-   they only require "natural" alignment (4-byte for ldcw, 8-byte for
-   ldcd). */
-
-#define __PA_LDCW_ALIGNMENT    4
-#define __PA_LDCW_ALIGN_ORDER  2
-#define __ldcw_align(a) (&(a)->slock)
+#ifdef CONFIG_PA20
 #define __LDCW "ldcw,co"
-
-#endif /*!CONFIG_PA20*/
+#else
+#define __LDCW "ldcw"
+#endif
 
 /* LDCW, the only atomic read-write operation PA-RISC has. *sigh*.
    We don't explicitly expose that "*a" may be written as reload
index efd06a8..7b986b0 100644 (file)
@@ -9,15 +9,10 @@
 #ifndef __ASSEMBLY__
 
 typedef struct {
-#ifdef CONFIG_PA20
-       volatile unsigned int slock;
-# define __ARCH_SPIN_LOCK_UNLOCKED { __ARCH_SPIN_LOCK_UNLOCKED_VAL }
-#else
        volatile unsigned int lock[4];
 # define __ARCH_SPIN_LOCK_UNLOCKED     \
        { { __ARCH_SPIN_LOCK_UNLOCKED_VAL, __ARCH_SPIN_LOCK_UNLOCKED_VAL, \
            __ARCH_SPIN_LOCK_UNLOCKED_VAL, __ARCH_SPIN_LOCK_UNLOCKED_VAL } }
-#endif
 } arch_spinlock_t;
 
 
index 4098f9a..2019c1f 100644 (file)
@@ -440,7 +440,9 @@ int __cpu_up(unsigned int cpu, struct task_struct *tidle)
        if (cpu_online(cpu))
                return 0;
 
-       if (num_online_cpus() < setup_max_cpus && smp_boot_one_cpu(cpu, tidle))
+       if (num_online_cpus() < nr_cpu_ids &&
+               num_online_cpus() < setup_max_cpus &&
+               smp_boot_one_cpu(cpu, tidle))
                return -EIO;
 
        return cpu_online(cpu) ? 0 : -EIO;
index a8a1a7c..a9f7e21 100644 (file)
@@ -140,7 +140,7 @@ static void __set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
 }
 
 void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
-                    pte_t *ptep, pte_t entry)
+                    pte_t *ptep, pte_t entry, unsigned long sz)
 {
        __set_huge_pte_at(mm, addr, ptep, entry);
 }
index 54b9387..3aaadfd 100644 (file)
@@ -255,7 +255,7 @@ config PPC
        select HAVE_KPROBES
        select HAVE_KPROBES_ON_FTRACE
        select HAVE_KRETPROBES
-       select HAVE_LD_DEAD_CODE_DATA_ELIMINATION if HAVE_OBJTOOL_MCOUNT
+       select HAVE_LD_DEAD_CODE_DATA_ELIMINATION if HAVE_OBJTOOL_MCOUNT && (!ARCH_USING_PATCHABLE_FUNCTION_ENTRY || (!CC_IS_GCC || GCC_VERSION >= 110100))
        select HAVE_LIVEPATCH                   if HAVE_DYNAMIC_FTRACE_WITH_REGS
        select HAVE_MOD_ARCH_SPECIFIC
        select HAVE_NMI                         if PERF_EVENTS || (PPC64 && PPC_BOOK3S)
index de092b0..92df40c 100644 (file)
@@ -46,7 +46,8 @@ static inline int check_and_get_huge_psize(int shift)
 }
 
 #define __HAVE_ARCH_HUGE_SET_HUGE_PTE_AT
-void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte);
+void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep,
+                    pte_t pte, unsigned long sz);
 
 #define __HAVE_ARCH_HUGE_PTE_CLEAR
 static inline void huge_pte_clear(struct mm_struct *mm, unsigned long addr,
index b8513dc..a1318ce 100644 (file)
@@ -230,13 +230,15 @@ void thread_change_pc(struct task_struct *tsk, struct pt_regs *regs)
        struct arch_hw_breakpoint *info;
        int i;
 
+       preempt_disable();
+
        for (i = 0; i < nr_wp_slots(); i++) {
                struct perf_event *bp = __this_cpu_read(bp_per_reg[i]);
 
                if (unlikely(bp && counter_arch_bp(bp)->perf_single_step))
                        goto reset;
        }
-       return;
+       goto out;
 
 reset:
        regs_set_return_msr(regs, regs->msr & ~MSR_SE);
@@ -245,6 +247,9 @@ reset:
                __set_breakpoint(i, info);
                info->perf_single_step = false;
        }
+
+out:
+       preempt_enable();
 }
 
 static bool is_larx_stcx_instr(int type)
@@ -363,6 +368,11 @@ static void handle_p10dd1_spurious_exception(struct perf_event **bp,
        }
 }
 
+/*
+ * Handle a DABR or DAWR exception.
+ *
+ * Called in atomic context.
+ */
 int hw_breakpoint_handler(struct die_args *args)
 {
        bool err = false;
@@ -490,6 +500,8 @@ NOKPROBE_SYMBOL(hw_breakpoint_handler);
 
 /*
  * Handle single-step exceptions following a DABR hit.
+ *
+ * Called in atomic context.
  */
 static int single_step_dabr_instruction(struct die_args *args)
 {
@@ -541,6 +553,8 @@ NOKPROBE_SYMBOL(single_step_dabr_instruction);
 
 /*
  * Handle debug exception notifications.
+ *
+ * Called in atomic context.
  */
 int hw_breakpoint_exceptions_notify(
                struct notifier_block *unused, unsigned long val, void *data)
index a746230..9e51801 100644 (file)
@@ -131,8 +131,13 @@ void wp_get_instr_detail(struct pt_regs *regs, ppc_inst_t *instr,
                         int *type, int *size, unsigned long *ea)
 {
        struct instruction_op op;
+       int err;
 
-       if (__get_user_instr(*instr, (void __user *)regs->nip))
+       pagefault_disable();
+       err = __get_user_instr(*instr, (void __user *)regs->nip);
+       pagefault_enable();
+
+       if (err)
                return;
 
        analyse_instr(&op, regs, *instr);
index b15f15d..e6a958a 100644 (file)
@@ -73,29 +73,12 @@ int __no_sanitize_address arch_stack_walk_reliable(stack_trace_consume_fn consum
        bool firstframe;
 
        stack_end = stack_page + THREAD_SIZE;
-       if (!is_idle_task(task)) {
-               /*
-                * For user tasks, this is the SP value loaded on
-                * kernel entry, see "PACAKSAVE(r13)" in _switch() and
-                * system_call_common().
-                *
-                * Likewise for non-swapper kernel threads,
-                * this also happens to be the top of the stack
-                * as setup by copy_thread().
-                *
-                * Note that stack backlinks are not properly setup by
-                * copy_thread() and thus, a forked task() will have
-                * an unreliable stack trace until it's been
-                * _switch()'ed to for the first time.
-                */
-               stack_end -= STACK_USER_INT_FRAME_SIZE;
-       } else {
-               /*
-                * idle tasks have a custom stack layout,
-                * c.f. cpu_idle_thread_init().
-                */
+
+       // See copy_thread() for details.
+       if (task->flags & PF_KTHREAD)
                stack_end -= STACK_FRAME_MIN_SIZE;
-       }
+       else
+               stack_end -= STACK_USER_INT_FRAME_SIZE;
 
        if (task == current)
                sp = current_stack_frame();
index eeff136..64ff377 100644 (file)
@@ -1512,23 +1512,11 @@ static void do_program_check(struct pt_regs *regs)
                        return;
                }
 
-               if (cpu_has_feature(CPU_FTR_DEXCR_NPHIE) && user_mode(regs)) {
-                       ppc_inst_t insn;
-
-                       if (get_user_instr(insn, (void __user *)regs->nip)) {
-                               _exception(SIGSEGV, regs, SEGV_MAPERR, regs->nip);
-                               return;
-                       }
-
-                       if (ppc_inst_primary_opcode(insn) == 31 &&
-                           get_xop(ppc_inst_val(insn)) == OP_31_XOP_HASHCHK) {
-                               _exception(SIGILL, regs, ILL_ILLOPN, regs->nip);
-                               return;
-                       }
+               /* User mode considers other cases after enabling IRQs */
+               if (!user_mode(regs)) {
+                       _exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip);
+                       return;
                }
-
-               _exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip);
-               return;
        }
 #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
        if (reason & REASON_TM) {
@@ -1561,16 +1549,44 @@ static void do_program_check(struct pt_regs *regs)
 
        /*
         * If we took the program check in the kernel skip down to sending a
-        * SIGILL. The subsequent cases all relate to emulating instructions
-        * which we should only do for userspace. We also do not want to enable
-        * interrupts for kernel faults because that might lead to further
-        * faults, and loose the context of the original exception.
+        * SIGILL. The subsequent cases all relate to user space, such as
+        * emulating instructions which we should only do for user space. We
+        * also do not want to enable interrupts for kernel faults because that
+        * might lead to further faults, and loose the context of the original
+        * exception.
         */
        if (!user_mode(regs))
                goto sigill;
 
        interrupt_cond_local_irq_enable(regs);
 
+       /*
+        * (reason & REASON_TRAP) is mostly handled before enabling IRQs,
+        * except get_user_instr() can sleep so we cannot reliably inspect the
+        * current instruction in that context. Now that we know we are
+        * handling a user space trap and can sleep, we can check if the trap
+        * was a hashchk failure.
+        */
+       if (reason & REASON_TRAP) {
+               if (cpu_has_feature(CPU_FTR_DEXCR_NPHIE)) {
+                       ppc_inst_t insn;
+
+                       if (get_user_instr(insn, (void __user *)regs->nip)) {
+                               _exception(SIGSEGV, regs, SEGV_MAPERR, regs->nip);
+                               return;
+                       }
+
+                       if (ppc_inst_primary_opcode(insn) == 31 &&
+                           get_xop(ppc_inst_val(insn)) == OP_31_XOP_HASHCHK) {
+                               _exception(SIGILL, regs, ILL_ILLOPN, regs->nip);
+                               return;
+                       }
+               }
+
+               _exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip);
+               return;
+       }
+
        /* (reason & REASON_ILLEGAL) would be the obvious thing here,
         * but there seems to be a hardware bug on the 405GP (RevD)
         * that means ESR is sometimes set incorrectly - either to
index 3bc0eb2..5a2e512 100644 (file)
@@ -143,11 +143,14 @@ pte_t huge_ptep_modify_prot_start(struct vm_area_struct *vma,
 void huge_ptep_modify_prot_commit(struct vm_area_struct *vma, unsigned long addr,
                                  pte_t *ptep, pte_t old_pte, pte_t pte)
 {
+       unsigned long psize;
 
        if (radix_enabled())
                return radix__huge_ptep_modify_prot_commit(vma, addr, ptep,
                                                           old_pte, pte);
-       set_huge_pte_at(vma->vm_mm, addr, ptep, pte);
+
+       psize = huge_page_size(hstate_vma(vma));
+       set_huge_pte_at(vma->vm_mm, addr, ptep, pte, psize);
 }
 
 void __init hugetlbpage_init_defaultsize(void)
index 17075c7..35fd2a9 100644 (file)
@@ -47,6 +47,7 @@ void radix__huge_ptep_modify_prot_commit(struct vm_area_struct *vma,
                                         pte_t old_pte, pte_t pte)
 {
        struct mm_struct *mm = vma->vm_mm;
+       unsigned long psize = huge_page_size(hstate_vma(vma));
 
        /*
         * POWER9 NMMU must flush the TLB after clearing the PTE before
@@ -58,5 +59,5 @@ void radix__huge_ptep_modify_prot_commit(struct vm_area_struct *vma,
            atomic_read(&mm->context.copros) > 0)
                radix__flush_hugetlb_page(vma, addr);
 
-       set_huge_pte_at(vma->vm_mm, addr, ptep, pte);
+       set_huge_pte_at(vma->vm_mm, addr, ptep, pte, psize);
 }
index dbbfe89..a642a79 100644 (file)
@@ -91,7 +91,8 @@ static int __ref __early_map_kernel_hugepage(unsigned long va, phys_addr_t pa,
        if (new && WARN_ON(pte_present(*ptep) && pgprot_val(prot)))
                return -EINVAL;
 
-       set_huge_pte_at(&init_mm, va, ptep, pte_mkhuge(pfn_pte(pa >> PAGE_SHIFT, prot)));
+       set_huge_pte_at(&init_mm, va, ptep,
+                       pte_mkhuge(pfn_pte(pa >> PAGE_SHIFT, prot)), psize);
 
        return 0;
 }
index 3f86fd2..3ba9fe4 100644 (file)
@@ -288,7 +288,8 @@ int huge_ptep_set_access_flags(struct vm_area_struct *vma,
 }
 
 #if defined(CONFIG_PPC_8xx)
-void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte)
+void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep,
+                    pte_t pte, unsigned long sz)
 {
        pmd_t *pmd = pmd_off(mm, addr);
        pte_basic_t val;
index 3171757..3449be7 100644 (file)
@@ -1418,7 +1418,7 @@ static int h_24x7_event_init(struct perf_event *event)
        }
 
        domain = event_get_domain(event);
-       if (domain >= HV_PERF_DOMAIN_MAX) {
+       if (domain  == 0 || domain >= HV_PERF_DOMAIN_MAX) {
                pr_devel("invalid domain %d\n", domain);
                return -EINVAL;
        }
index d9f1a2a..1824536 100644 (file)
@@ -2,6 +2,7 @@
 menuconfig PPC_82xx
        bool "82xx-based boards (PQ II)"
        depends on PPC_BOOK3S_32
+       select FSL_SOC
 
 if PPC_82xx
 
@@ -9,7 +10,6 @@ config EP8248E
        bool "Embedded Planet EP8248E (a.k.a. CWH-PPC-8248N-VE)"
        select CPM2
        select PPC_INDIRECT_PCI if PCI
-       select FSL_SOC
        select PHYLIB if NETDEVICES
        select MDIO_BITBANG if PHYLIB
        help
@@ -22,7 +22,6 @@ config MGCOGE
        bool "Keymile MGCOGE"
        select CPM2
        select PPC_INDIRECT_PCI if PCI
-       select FSL_SOC
        help
          This enables support for the Keymile MGCOGE board.
 
index d79f944..12ebe97 100644 (file)
                                reg = <0x100000 0x400000>;
                        };
                        reserved-data@600000 {
-                               reg = <0x600000 0x1000000>;
+                               reg = <0x600000 0xa00000>;
                        };
                };
        };
                };
        };
 
-       uart0_pins: uart0-0 {
-               tx-pins {
-                       pinmux = <GPIOMUX(5, GPOUT_SYS_UART0_TX,
-                                            GPOEN_ENABLE,
-                                            GPI_NONE)>;
-                       bias-disable;
-                       drive-strength = <12>;
-                       input-disable;
-                       input-schmitt-disable;
-                       slew-rate = <0>;
-               };
-
-               rx-pins {
-                       pinmux = <GPIOMUX(6, GPOUT_LOW,
-                                            GPOEN_DISABLE,
-                                            GPI_SYS_UART0_RX)>;
-                       bias-disable; /* external pull-up */
-                       drive-strength = <2>;
-                       input-enable;
-                       input-schmitt-enable;
-                       slew-rate = <0>;
-               };
-       };
-
        tdm_pins: tdm-0 {
                tx-pins {
                        pinmux = <GPIOMUX(44, GPOUT_SYS_TDM_TXD,
                        input-enable;
                };
        };
+
+       uart0_pins: uart0-0 {
+               tx-pins {
+                       pinmux = <GPIOMUX(5, GPOUT_SYS_UART0_TX,
+                                            GPOEN_ENABLE,
+                                            GPI_NONE)>;
+                       bias-disable;
+                       drive-strength = <12>;
+                       input-disable;
+                       input-schmitt-disable;
+                       slew-rate = <0>;
+               };
+
+               rx-pins {
+                       pinmux = <GPIOMUX(6, GPOUT_LOW,
+                                            GPOEN_DISABLE,
+                                            GPI_SYS_UART0_RX)>;
+                       bias-disable; /* external pull-up */
+                       drive-strength = <2>;
+                       input-enable;
+                       input-schmitt-enable;
+                       slew-rate = <0>;
+               };
+       };
 };
 
 &tdm {
 
 &usb0 {
        dr_mode = "peripheral";
+       status = "okay";
 };
 
 &U74_1 {
index 34e24f0..4c5b0e9 100644 (file)
@@ -18,7 +18,8 @@ void huge_pte_clear(struct mm_struct *mm, unsigned long addr,
 
 #define __HAVE_ARCH_HUGE_SET_HUGE_PTE_AT
 void set_huge_pte_at(struct mm_struct *mm,
-                    unsigned long addr, pte_t *ptep, pte_t pte);
+                    unsigned long addr, pte_t *ptep, pte_t pte,
+                    unsigned long sz);
 
 #define __HAVE_ARCH_HUGE_PTEP_GET_AND_CLEAR
 pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
index 96225a8..e4a2ace 100644 (file)
@@ -180,7 +180,8 @@ pte_t arch_make_huge_pte(pte_t entry, unsigned int shift, vm_flags_t flags)
 void set_huge_pte_at(struct mm_struct *mm,
                     unsigned long addr,
                     pte_t *ptep,
-                    pte_t pte)
+                    pte_t pte,
+                    unsigned long sz)
 {
        int i, pte_num;
 
index af2fbe4..438cd92 100644 (file)
@@ -40,23 +40,25 @@ CONFIG_SCHED_AUTOGROUP=y
 CONFIG_EXPERT=y
 # CONFIG_SYSFS_SYSCALL is not set
 CONFIG_PROFILING=y
+CONFIG_KEXEC_FILE=y
+CONFIG_KEXEC_SIG=y
+CONFIG_CRASH_DUMP=y
 CONFIG_LIVEPATCH=y
 CONFIG_MARCH_ZEC12=y
 CONFIG_TUNE_ZEC12=y
 CONFIG_NR_CPUS=512
 CONFIG_NUMA=y
 CONFIG_HZ_100=y
-CONFIG_KEXEC_FILE=y
-CONFIG_KEXEC_SIG=y
+CONFIG_CERT_STORE=y
 CONFIG_EXPOLINE=y
 CONFIG_EXPOLINE_AUTO=y
 CONFIG_CHSC_SCH=y
 CONFIG_VFIO_CCW=m
 CONFIG_VFIO_AP=m
-CONFIG_CRASH_DUMP=y
 CONFIG_PROTECTED_VIRTUALIZATION_GUEST=y
 CONFIG_CMM=m
 CONFIG_APPLDATA_BASE=y
+CONFIG_S390_HYPFS_FS=y
 CONFIG_KVM=m
 CONFIG_S390_UNWIND_SELFTEST=m
 CONFIG_S390_KPROBES_SANITY_TEST=m
@@ -434,6 +436,7 @@ CONFIG_SCSI_DH_EMC=m
 CONFIG_SCSI_DH_ALUA=m
 CONFIG_MD=y
 CONFIG_BLK_DEV_MD=y
+# CONFIG_MD_BITMAP_FILE is not set
 CONFIG_MD_LINEAR=m
 CONFIG_MD_MULTIPATH=m
 CONFIG_MD_FAULTY=m
@@ -577,6 +580,7 @@ CONFIG_SOFT_WATCHDOG=m
 CONFIG_DIAG288_WATCHDOG=m
 # CONFIG_DRM_DEBUG_MODESET_LOCK is not set
 CONFIG_FB=y
+# CONFIG_FB_DEVICE is not set
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
 # CONFIG_HID_SUPPORT is not set
@@ -647,6 +651,7 @@ CONFIG_PROC_KCORE=y
 CONFIG_TMPFS=y
 CONFIG_TMPFS_POSIX_ACL=y
 CONFIG_TMPFS_INODE64=y
+CONFIG_TMPFS_QUOTA=y
 CONFIG_HUGETLBFS=y
 CONFIG_ECRYPT_FS=m
 CONFIG_CRAMFS=m
@@ -703,6 +708,7 @@ CONFIG_IMA_WRITE_POLICY=y
 CONFIG_IMA_APPRAISE=y
 CONFIG_LSM="yama,loadpin,safesetid,integrity,selinux,smack,tomoyo,apparmor"
 CONFIG_INIT_STACK_NONE=y
+CONFIG_BUG_ON_DATA_CORRUPTION=y
 CONFIG_CRYPTO_USER=m
 # CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set
 CONFIG_CRYPTO_PCRYPT=m
@@ -825,9 +831,9 @@ CONFIG_LOCK_STAT=y
 CONFIG_DEBUG_ATOMIC_SLEEP=y
 CONFIG_DEBUG_LOCKING_API_SELFTESTS=y
 CONFIG_DEBUG_IRQFLAGS=y
+CONFIG_DEBUG_LIST=y
 CONFIG_DEBUG_SG=y
 CONFIG_DEBUG_NOTIFIERS=y
-CONFIG_BUG_ON_DATA_CORRUPTION=y
 CONFIG_DEBUG_CREDENTIALS=y
 CONFIG_RCU_TORTURE_TEST=m
 CONFIG_RCU_REF_SCALE_TEST=m
index 3f263b7..1b8150e 100644 (file)
@@ -38,23 +38,25 @@ CONFIG_SCHED_AUTOGROUP=y
 CONFIG_EXPERT=y
 # CONFIG_SYSFS_SYSCALL is not set
 CONFIG_PROFILING=y
+CONFIG_KEXEC_FILE=y
+CONFIG_KEXEC_SIG=y
+CONFIG_CRASH_DUMP=y
 CONFIG_LIVEPATCH=y
 CONFIG_MARCH_ZEC12=y
 CONFIG_TUNE_ZEC12=y
 CONFIG_NR_CPUS=512
 CONFIG_NUMA=y
 CONFIG_HZ_100=y
-CONFIG_KEXEC_FILE=y
-CONFIG_KEXEC_SIG=y
+CONFIG_CERT_STORE=y
 CONFIG_EXPOLINE=y
 CONFIG_EXPOLINE_AUTO=y
 CONFIG_CHSC_SCH=y
 CONFIG_VFIO_CCW=m
 CONFIG_VFIO_AP=m
-CONFIG_CRASH_DUMP=y
 CONFIG_PROTECTED_VIRTUALIZATION_GUEST=y
 CONFIG_CMM=m
 CONFIG_APPLDATA_BASE=y
+CONFIG_S390_HYPFS_FS=y
 CONFIG_KVM=m
 CONFIG_S390_UNWIND_SELFTEST=m
 CONFIG_S390_KPROBES_SANITY_TEST=m
@@ -424,6 +426,7 @@ CONFIG_SCSI_DH_EMC=m
 CONFIG_SCSI_DH_ALUA=m
 CONFIG_MD=y
 CONFIG_BLK_DEV_MD=y
+# CONFIG_MD_BITMAP_FILE is not set
 CONFIG_MD_LINEAR=m
 CONFIG_MD_MULTIPATH=m
 CONFIG_MD_FAULTY=m
@@ -566,6 +569,7 @@ CONFIG_WATCHDOG_NOWAYOUT=y
 CONFIG_SOFT_WATCHDOG=m
 CONFIG_DIAG288_WATCHDOG=m
 CONFIG_FB=y
+# CONFIG_FB_DEVICE is not set
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
 # CONFIG_HID_SUPPORT is not set
@@ -632,6 +636,7 @@ CONFIG_PROC_KCORE=y
 CONFIG_TMPFS=y
 CONFIG_TMPFS_POSIX_ACL=y
 CONFIG_TMPFS_INODE64=y
+CONFIG_TMPFS_QUOTA=y
 CONFIG_HUGETLBFS=y
 CONFIG_CONFIGFS_FS=m
 CONFIG_ECRYPT_FS=m
@@ -687,6 +692,7 @@ CONFIG_IMA_WRITE_POLICY=y
 CONFIG_IMA_APPRAISE=y
 CONFIG_LSM="yama,loadpin,safesetid,integrity,selinux,smack,tomoyo,apparmor"
 CONFIG_INIT_STACK_NONE=y
+CONFIG_BUG_ON_DATA_CORRUPTION=y
 CONFIG_CRYPTO_FIPS=y
 CONFIG_CRYPTO_USER=m
 # CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set
@@ -781,7 +787,6 @@ CONFIG_PTDUMP_DEBUGFS=y
 CONFIG_DEBUG_MEMORY_INIT=y
 CONFIG_PANIC_ON_OOPS=y
 CONFIG_TEST_LOCKUP=m
-CONFIG_BUG_ON_DATA_CORRUPTION=y
 CONFIG_RCU_TORTURE_TEST=m
 CONFIG_RCU_REF_SCALE_TEST=m
 CONFIG_RCU_CPU_STALL_TIMEOUT=60
index e62fb20..b831083 100644 (file)
@@ -8,6 +8,7 @@ CONFIG_BPF_SYSCALL=y
 # CONFIG_NET_NS is not set
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_CRASH_DUMP=y
 CONFIG_MARCH_ZEC12=y
 CONFIG_TUNE_ZEC12=y
 # CONFIG_COMPAT is not set
@@ -15,9 +16,8 @@ CONFIG_NR_CPUS=2
 CONFIG_HZ_100=y
 # CONFIG_CHSC_SCH is not set
 # CONFIG_SCM_BUS is not set
-CONFIG_CRASH_DUMP=y
 # CONFIG_PFAULT is not set
-# CONFIG_S390_HYPFS_FS is not set
+# CONFIG_S390_HYPFS is not set
 # CONFIG_VIRTUALIZATION is not set
 # CONFIG_S390_GUEST is not set
 # CONFIG_SECCOMP is not set
index f072678..deb198a 100644 (file)
@@ -16,6 +16,8 @@
 #define hugepages_supported()                  (MACHINE_HAS_EDAT1)
 
 void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
+                    pte_t *ptep, pte_t pte, unsigned long sz);
+void __set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
                     pte_t *ptep, pte_t pte);
 pte_t huge_ptep_get(pte_t *ptep);
 pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
@@ -65,7 +67,7 @@ static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma,
        int changed = !pte_same(huge_ptep_get(ptep), pte);
        if (changed) {
                huge_ptep_get_and_clear(vma->vm_mm, addr, ptep);
-               set_huge_pte_at(vma->vm_mm, addr, ptep, pte);
+               __set_huge_pte_at(vma->vm_mm, addr, ptep, pte);
        }
        return changed;
 }
@@ -74,7 +76,7 @@ static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
                                           unsigned long addr, pte_t *ptep)
 {
        pte_t pte = huge_ptep_get_and_clear(mm, addr, ptep);
-       set_huge_pte_at(mm, addr, ptep, pte_wrprotect(pte));
+       __set_huge_pte_at(mm, addr, ptep, pte_wrprotect(pte));
 }
 
 static inline pte_t mk_huge_pte(struct page *page, pgprot_t pgprot)
index 3986a04..5544477 100644 (file)
@@ -432,15 +432,16 @@ static char *get_key_description(struct vcssb *vcssb, const struct vce *vce)
        char *desc;
 
        cs_token = vcssb->cs_token;
-       /* Description string contains "%64s:%04u:%08u\0". */
+       /* Description string contains "%64s:%05u:%010u\0". */
        name_len = sizeof(vce->vce_hdr.vc_name);
-       len = name_len + 1 + 4 + 1 + 8 + 1;
+       len = name_len + 1 + 5 + 1 + 10 + 1;
        desc = kmalloc(len, GFP_KERNEL);
        if (!desc)
                return NULL;
 
        memcpy(desc, vce->vce_hdr.vc_name, name_len);
-       sprintf(desc + name_len, ":%04u:%08u", vce->vce_hdr.vc_index, cs_token);
+       snprintf(desc + name_len, len - name_len, ":%05u:%010u",
+                vce->vce_hdr.vc_index, cs_token);
 
        return desc;
 }
index c1b47d6..efaebba 100644 (file)
@@ -303,11 +303,6 @@ static inline u8 gisa_get_ipm_or_restore_iam(struct kvm_s390_gisa_interrupt *gi)
        return 0;
 }
 
-static inline int gisa_in_alert_list(struct kvm_s390_gisa *gisa)
-{
-       return READ_ONCE(gisa->next_alert) != (u32)virt_to_phys(gisa);
-}
-
 static inline void gisa_set_ipm_gisc(struct kvm_s390_gisa *gisa, u32 gisc)
 {
        set_bit_inv(IPM_BIT_OFFSET + gisc, (unsigned long *) gisa);
@@ -3216,11 +3211,12 @@ void kvm_s390_gisa_destroy(struct kvm *kvm)
 
        if (!gi->origin)
                return;
-       if (gi->alert.mask)
-               KVM_EVENT(3, "vm 0x%pK has unexpected iam 0x%02x",
-                         kvm, gi->alert.mask);
-       while (gisa_in_alert_list(gi->origin))
-               cpu_relax();
+       WARN(gi->alert.mask != 0x00,
+            "unexpected non zero alert.mask 0x%02x",
+            gi->alert.mask);
+       gi->alert.mask = 0x00;
+       if (gisa_set_iam(gi->origin, gi->alert.mask))
+               process_gib_alert_list();
        hrtimer_cancel(&gi->timer);
        gi->origin = NULL;
        VM_EVENT(kvm, 3, "gisa 0x%pK destroyed", gisa);
index c718f2a..297a6d8 100644 (file)
@@ -142,7 +142,7 @@ static void clear_huge_pte_skeys(struct mm_struct *mm, unsigned long rste)
                __storage_key_init_range(paddr, paddr + size - 1);
 }
 
-void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
+void __set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
                     pte_t *ptep, pte_t pte)
 {
        unsigned long rste;
@@ -163,6 +163,12 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
        set_pte(ptep, __pte(rste));
 }
 
+void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
+                    pte_t *ptep, pte_t pte, unsigned long sz)
+{
+       __set_huge_pte_at(mm, addr, ptep, pte);
+}
+
 pte_t huge_ptep_get(pte_t *ptep)
 {
        return __rste_to_pte(pte_val(*ptep));
index de2fb12..2861e33 100644 (file)
@@ -2513,7 +2513,7 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image,
                        return -E2BIG;
        }
 
-       return ret;
+       return tjit.common.prg;
 }
 
 bool bpf_jit_supports_subprog_tailcalls(void)
index c33b3da..33d20f3 100644 (file)
@@ -72,8 +72,8 @@ __ioremap_29bit(phys_addr_t offset, unsigned long size, pgprot_t prot)
 #define __ioremap_29bit(offset, size, prot)            NULL
 #endif /* CONFIG_29BIT */
 
-void __iomem *ioremap_prot(phys_addr_t phys_addr, size_t size,
-                          unsigned long prot)
+void __iomem __ref *ioremap_prot(phys_addr_t phys_addr, size_t size,
+                                unsigned long prot)
 {
        void __iomem *mapped;
        pgprot_t pgprot = __pgprot(prot);
index 0a26cca..c714ca6 100644 (file)
@@ -14,6 +14,8 @@ extern struct pud_huge_patch_entry __pud_huge_patch, __pud_huge_patch_end;
 
 #define __HAVE_ARCH_HUGE_SET_HUGE_PTE_AT
 void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
+                    pte_t *ptep, pte_t pte, unsigned long sz);
+void __set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
                     pte_t *ptep, pte_t pte);
 
 #define __HAVE_ARCH_HUGE_PTEP_GET_AND_CLEAR
@@ -32,7 +34,7 @@ static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
                                           unsigned long addr, pte_t *ptep)
 {
        pte_t old_pte = *ptep;
-       set_huge_pte_at(mm, addr, ptep, pte_wrprotect(old_pte));
+       __set_huge_pte_at(mm, addr, ptep, pte_wrprotect(old_pte));
 }
 
 #define __HAVE_ARCH_HUGE_PTEP_SET_ACCESS_FLAGS
@@ -42,7 +44,7 @@ static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma,
 {
        int changed = !pte_same(*ptep, pte);
        if (changed) {
-               set_huge_pte_at(vma->vm_mm, addr, ptep, pte);
+               __set_huge_pte_at(vma->vm_mm, addr, ptep, pte);
                flush_tlb_page(vma, addr);
        }
        return changed;
index d701882..b432500 100644 (file)
@@ -328,7 +328,7 @@ pte_t *huge_pte_offset(struct mm_struct *mm,
        return pte_offset_huge(pmd, addr);
 }
 
-void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
+void __set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
                     pte_t *ptep, pte_t entry)
 {
        unsigned int nptes, orig_shift, shift;
@@ -364,6 +364,12 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
                                    orig_shift);
 }
 
+void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
+                    pte_t *ptep, pte_t entry, unsigned long sz)
+{
+       __set_huge_pte_at(mm, addr, ptep, entry);
+}
+
 pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
                              pte_t *ptep)
 {
index 6c28264..93c60c0 100644 (file)
@@ -294,7 +294,7 @@ static void __xen_pv_evtchn_do_upcall(struct pt_regs *regs)
 
        inc_irq_stat(irq_hv_callback_count);
 
-       xen_hvm_evtchn_do_upcall();
+       xen_evtchn_do_upcall();
 
        set_irq_regs(old_regs);
 }
index abadd5f..e249765 100644 (file)
@@ -534,8 +534,12 @@ static void amd_pmu_cpu_reset(int cpu)
        /* Clear enable bits i.e. PerfCntrGlobalCtl.PerfCntrEn */
        wrmsrl(MSR_AMD64_PERF_CNTR_GLOBAL_CTL, 0);
 
-       /* Clear overflow bits i.e. PerfCntrGLobalStatus.PerfCntrOvfl */
-       wrmsrl(MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_CLR, amd_pmu_global_cntr_mask);
+       /*
+        * Clear freeze and overflow bits i.e. PerfCntrGLobalStatus.LbrFreeze
+        * and PerfCntrGLobalStatus.PerfCntrOvfl
+        */
+       wrmsrl(MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_CLR,
+              GLOBAL_STATUS_LBRS_FROZEN | amd_pmu_global_cntr_mask);
 }
 
 static int amd_pmu_cpu_prepare(int cpu)
@@ -570,6 +574,7 @@ static void amd_pmu_cpu_starting(int cpu)
        int i, nb_id;
 
        cpuc->perf_ctr_virt_mask = AMD64_EVENTSEL_HOSTONLY;
+       amd_pmu_cpu_reset(cpu);
 
        if (!x86_pmu.amd_nb_constraints)
                return;
@@ -591,8 +596,6 @@ static void amd_pmu_cpu_starting(int cpu)
 
        cpuc->amd_nb->nb_id = nb_id;
        cpuc->amd_nb->refcnt++;
-
-       amd_pmu_cpu_reset(cpu);
 }
 
 static void amd_pmu_cpu_dead(int cpu)
@@ -601,6 +604,7 @@ static void amd_pmu_cpu_dead(int cpu)
 
        kfree(cpuhw->lbr_sel);
        cpuhw->lbr_sel = NULL;
+       amd_pmu_cpu_reset(cpu);
 
        if (!x86_pmu.amd_nb_constraints)
                return;
@@ -613,8 +617,6 @@ static void amd_pmu_cpu_dead(int cpu)
 
                cpuhw->amd_nb = NULL;
        }
-
-       amd_pmu_cpu_reset(cpu);
 }
 
 static inline void amd_pmu_set_global_ctl(u64 ctl)
@@ -884,7 +886,7 @@ static int amd_pmu_v2_handle_irq(struct pt_regs *regs)
        struct hw_perf_event *hwc;
        struct perf_event *event;
        int handled = 0, idx;
-       u64 status, mask;
+       u64 reserved, status, mask;
        bool pmu_enabled;
 
        /*
@@ -909,6 +911,14 @@ static int amd_pmu_v2_handle_irq(struct pt_regs *regs)
                status &= ~GLOBAL_STATUS_LBRS_FROZEN;
        }
 
+       reserved = status & ~amd_pmu_global_cntr_mask;
+       if (reserved)
+               pr_warn_once("Reserved PerfCntrGlobalStatus bits are set (0x%llx), please consider updating microcode\n",
+                            reserved);
+
+       /* Clear any reserved bits set by buggy microcode */
+       status &= amd_pmu_global_cntr_mask;
+
        for (idx = 0; idx < x86_pmu.num_counters; idx++) {
                if (!test_bit(idx, cpuc->active_mask))
                        continue;
index 783ed33..21556ad 100644 (file)
@@ -7,6 +7,8 @@
  * Author : K. Y. Srinivasan <kys@microsoft.com>
  */
 
+#define pr_fmt(fmt)  "Hyper-V: " fmt
+
 #include <linux/efi.h>
 #include <linux/types.h>
 #include <linux/bitfield.h>
@@ -191,7 +193,7 @@ void set_hv_tscchange_cb(void (*cb)(void))
        struct hv_tsc_emulation_control emu_ctrl = {.enabled = 1};
 
        if (!hv_reenlightenment_available()) {
-               pr_warn("Hyper-V: reenlightenment support is unavailable\n");
+               pr_warn("reenlightenment support is unavailable\n");
                return;
        }
 
@@ -394,6 +396,7 @@ static void __init hv_get_partition_id(void)
        local_irq_restore(flags);
 }
 
+#if IS_ENABLED(CONFIG_HYPERV_VTL_MODE)
 static u8 __init get_vtl(void)
 {
        u64 control = HV_HYPERCALL_REP_COMP_1 | HVCALL_GET_VP_REGISTERS;
@@ -416,13 +419,16 @@ static u8 __init get_vtl(void)
        if (hv_result_success(ret)) {
                ret = output->as64.low & HV_X64_VTL_MASK;
        } else {
-               pr_err("Failed to get VTL(%lld) and set VTL to zero by default.\n", ret);
-               ret = 0;
+               pr_err("Failed to get VTL(error: %lld) exiting...\n", ret);
+               BUG();
        }
 
        local_irq_restore(flags);
        return ret;
 }
+#else
+static inline u8 get_vtl(void) { return 0; }
+#endif
 
 /*
  * This function is to be invoked early in the boot sequence after the
@@ -564,7 +570,7 @@ skip_hypercall_pg_init:
        if (cpu_feature_enabled(X86_FEATURE_IBT) &&
            *(u32 *)hv_hypercall_pg != gen_endbr()) {
                setup_clear_cpu_cap(X86_FEATURE_IBT);
-               pr_warn("Hyper-V: Disabling IBT because of Hyper-V bug\n");
+               pr_warn("Disabling IBT because of Hyper-V bug\n");
        }
 #endif
 
@@ -604,8 +610,10 @@ skip_hypercall_pg_init:
        hv_query_ext_cap(0);
 
        /* Find the VTL */
-       if (!ms_hyperv.paravisor_present && hv_isolation_type_snp())
-               ms_hyperv.vtl = get_vtl();
+       ms_hyperv.vtl = get_vtl();
+
+       if (ms_hyperv.vtl > 0) /* non default VTL */
+               hv_vtl_early_init();
 
        return;
 
index 36a5622..999f5ac 100644 (file)
@@ -215,7 +215,7 @@ static int hv_vtl_wakeup_secondary_cpu(int apicid, unsigned long start_eip)
        return hv_vtl_bringup_vcpu(vp_id, start_eip);
 }
 
-static int __init hv_vtl_early_init(void)
+int __init hv_vtl_early_init(void)
 {
        /*
         * `boot_cpu_has` returns the runtime feature support,
@@ -230,4 +230,3 @@ static int __init hv_vtl_early_init(void)
 
        return 0;
 }
-early_initcall(hv_vtl_early_init);
index 31089b8..a2be3ae 100644 (file)
@@ -157,7 +157,8 @@ static inline void fpu_update_guest_xfd(struct fpu_guest *guest_fpu, u64 xfd) {
 static inline void fpu_sync_guest_vmexit_xfd_state(void) { }
 #endif
 
-extern void fpu_copy_guest_fpstate_to_uabi(struct fpu_guest *gfpu, void *buf, unsigned int size, u32 pkru);
+extern void fpu_copy_guest_fpstate_to_uabi(struct fpu_guest *gfpu, void *buf,
+                                          unsigned int size, u64 xfeatures, u32 pkru);
 extern int fpu_copy_uabi_to_guest_fpstate(struct fpu_guest *gfpu, const void *buf, u64 xcr0, u32 *vpkru);
 
 static inline void fpstate_set_confidential(struct fpu_guest *gfpu)
index 5ff49fd..571fe4d 100644 (file)
        CFI_POST_PADDING                                        \
        SYM_FUNC_END(__cfi_##name)
 
+/* UML needs to be able to override memcpy() and friends for KASAN. */
+#ifdef CONFIG_UML
+# define SYM_FUNC_ALIAS_MEMFUNC        SYM_FUNC_ALIAS_WEAK
+#else
+# define SYM_FUNC_ALIAS_MEMFUNC        SYM_FUNC_ALIAS
+#endif
+
 /* SYM_TYPED_FUNC_START -- use for indirectly called globals, w/ CFI type */
 #define SYM_TYPED_FUNC_START(name)                             \
        SYM_TYPED_START(name, SYM_L_GLOBAL, SYM_F_ALIGN)        \
index 416901d..8dac45a 100644 (file)
@@ -186,8 +186,7 @@ do {                                                \
 #else
 #define deactivate_mm(tsk, mm)                 \
 do {                                           \
-       if (!tsk->vfork_done)                   \
-               shstk_free(tsk);                \
+       shstk_free(tsk);                        \
        load_gs_index(0);                       \
        loadsegment(fs, 0);                     \
 } while (0)
index 033b53f..896445e 100644 (file)
@@ -340,8 +340,10 @@ static inline u64 hv_get_non_nested_register(unsigned int reg) { return 0; }
 
 #ifdef CONFIG_HYPERV_VTL_MODE
 void __init hv_vtl_init_platform(void);
+int __init hv_vtl_early_init(void);
 #else
 static inline void __init hv_vtl_init_platform(void) {}
+static inline int __init hv_vtl_early_init(void) { return 0; }
 #endif
 
 #include <asm-generic/mshyperv.h>
index 4acbcdd..772d034 100644 (file)
@@ -9,13 +9,6 @@ struct paravirt_patch_site {
        u8 type;                /* type of this instruction */
        u8 len;                 /* length of original instruction */
 };
-
-/* Lazy mode for batching updates / context switch */
-enum paravirt_lazy_mode {
-       PARAVIRT_LAZY_NONE,
-       PARAVIRT_LAZY_MMU,
-       PARAVIRT_LAZY_CPU,
-};
 #endif
 
 #ifdef CONFIG_PARAVIRT
@@ -549,14 +542,6 @@ int paravirt_disable_iospace(void);
        __PVOP_VCALL(op, PVOP_CALL_ARG1(arg1), PVOP_CALL_ARG2(arg2),    \
                     PVOP_CALL_ARG3(arg3), PVOP_CALL_ARG4(arg4))
 
-enum paravirt_lazy_mode paravirt_get_lazy_mode(void);
-void paravirt_start_context_switch(struct task_struct *prev);
-void paravirt_end_context_switch(struct task_struct *next);
-
-void paravirt_enter_lazy_mmu(void);
-void paravirt_leave_lazy_mmu(void);
-void paravirt_flush_lazy_mmu(void);
-
 void _paravirt_nop(void);
 void paravirt_BUG(void);
 unsigned long paravirt_ret0(void);
index d6ad98c..e02b179 100644 (file)
@@ -955,6 +955,14 @@ static inline int pte_same(pte_t a, pte_t b)
        return a.pte == b.pte;
 }
 
+static inline pte_t pte_next_pfn(pte_t pte)
+{
+       if (__pte_needs_invert(pte_val(pte)))
+               return __pte(pte_val(pte) - (1UL << PFN_PTE_SHIFT));
+       return __pte(pte_val(pte) + (1UL << PFN_PTE_SHIFT));
+}
+#define pte_next_pfn   pte_next_pfn
+
 static inline int pte_present(pte_t a)
 {
        return pte_flags(a) & (_PAGE_PRESENT | _PAGE_PROTNONE);
index 0086920..a3669a7 100644 (file)
@@ -683,13 +683,11 @@ extern u16 get_llc_id(unsigned int cpu);
 #ifdef CONFIG_CPU_SUP_AMD
 extern u32 amd_get_nodes_per_socket(void);
 extern u32 amd_get_highest_perf(void);
-extern bool cpu_has_ibpb_brtype_microcode(void);
 extern void amd_clear_divider(void);
 extern void amd_check_microcode(void);
 #else
 static inline u32 amd_get_nodes_per_socket(void)       { return 0; }
 static inline u32 amd_get_highest_perf(void)           { return 0; }
-static inline bool cpu_has_ibpb_brtype_microcode(void) { return false; }
 static inline void amd_clear_divider(void)             { }
 static inline void amd_check_microcode(void)           { }
 #endif
index 19bf955..3ac0ffc 100644 (file)
@@ -268,6 +268,7 @@ enum avic_ipi_failure_cause {
        AVIC_IPI_FAILURE_TARGET_NOT_RUNNING,
        AVIC_IPI_FAILURE_INVALID_TARGET,
        AVIC_IPI_FAILURE_INVALID_BACKING_PAGE,
+       AVIC_IPI_FAILURE_INVALID_IPI_VECTOR,
 };
 
 #define AVIC_PHYSICAL_MAX_INDEX_MASK   GENMASK_ULL(8, 0)
index 5fc35f8..7048dfa 100644 (file)
@@ -36,6 +36,7 @@
 extern struct shared_info *HYPERVISOR_shared_info;
 extern struct start_info *xen_start_info;
 
+#include <asm/bug.h>
 #include <asm/processor.h>
 
 #define XEN_SIGNATURE "XenVMMXenVMM"
@@ -63,4 +64,40 @@ void __init xen_pvh_init(struct boot_params *boot_params);
 void __init mem_map_via_hcall(struct boot_params *boot_params_p);
 #endif
 
+/* Lazy mode for batching updates / context switch */
+enum xen_lazy_mode {
+       XEN_LAZY_NONE,
+       XEN_LAZY_MMU,
+       XEN_LAZY_CPU,
+};
+
+DECLARE_PER_CPU(enum xen_lazy_mode, xen_lazy_mode);
+DECLARE_PER_CPU(unsigned int, xen_lazy_nesting);
+
+static inline void enter_lazy(enum xen_lazy_mode mode)
+{
+       enum xen_lazy_mode old_mode = this_cpu_read(xen_lazy_mode);
+
+       if (mode == old_mode) {
+               this_cpu_inc(xen_lazy_nesting);
+               return;
+       }
+
+       BUG_ON(old_mode != XEN_LAZY_NONE);
+
+       this_cpu_write(xen_lazy_mode, mode);
+}
+
+static inline void leave_lazy(enum xen_lazy_mode mode)
+{
+       BUG_ON(this_cpu_read(xen_lazy_mode) != mode);
+
+       if (this_cpu_read(xen_lazy_nesting) == 0)
+               this_cpu_write(xen_lazy_mode, XEN_LAZY_NONE);
+       else
+               this_cpu_dec(xen_lazy_nesting);
+}
+
+enum xen_lazy_mode xen_get_lazy_mode(void);
+
 #endif /* _ASM_X86_XEN_HYPERVISOR_H */
index a5ead6a..517ee01 100644 (file)
@@ -720,13 +720,8 @@ void __init_or_module noinline apply_returns(s32 *start, s32 *end)
 {
        s32 *s;
 
-       /*
-        * Do not patch out the default return thunks if those needed are the
-        * ones generated by the compiler.
-        */
-       if (cpu_feature_enabled(X86_FEATURE_RETHUNK) &&
-           (x86_return_thunk == __x86_return_thunk))
-               return;
+       if (cpu_feature_enabled(X86_FEATURE_RETHUNK))
+               static_call_force_reinit();
 
        for (s = start; s < end; s++) {
                void *dest = NULL, *addr = (void *)s + *s;
index c06bfc0..faa9f22 100644 (file)
@@ -272,7 +272,6 @@ void __init callthunks_patch_builtin_calls(void)
        pr_info("Setting up call depth tracking\n");
        mutex_lock(&text_mutex);
        callthunks_setup(&cs, &builtin_coretext);
-       static_call_force_reinit();
        thunks_initialized = true;
        mutex_unlock(&text_mutex);
 }
index dd8379d..03ef962 100644 (file)
@@ -766,6 +766,15 @@ static void early_init_amd(struct cpuinfo_x86 *c)
 
        if (cpu_has(c, X86_FEATURE_TOPOEXT))
                smp_num_siblings = ((cpuid_ebx(0x8000001e) >> 8) & 0xff) + 1;
+
+       if (!cpu_has(c, X86_FEATURE_HYPERVISOR) && !cpu_has(c, X86_FEATURE_IBPB_BRTYPE)) {
+               if (c->x86 == 0x17 && boot_cpu_has(X86_FEATURE_AMD_IBPB))
+                       setup_force_cpu_cap(X86_FEATURE_IBPB_BRTYPE);
+               else if (c->x86 >= 0x19 && !wrmsrl_safe(MSR_IA32_PRED_CMD, PRED_CMD_SBPB)) {
+                       setup_force_cpu_cap(X86_FEATURE_IBPB_BRTYPE);
+                       setup_force_cpu_cap(X86_FEATURE_SBPB);
+               }
+       }
 }
 
 static void init_amd_k8(struct cpuinfo_x86 *c)
@@ -1301,25 +1310,6 @@ void amd_check_microcode(void)
        on_each_cpu(zenbleed_check_cpu, NULL, 1);
 }
 
-bool cpu_has_ibpb_brtype_microcode(void)
-{
-       switch (boot_cpu_data.x86) {
-       /* Zen1/2 IBPB flushes branch type predictions too. */
-       case 0x17:
-               return boot_cpu_has(X86_FEATURE_AMD_IBPB);
-       case 0x19:
-               /* Poke the MSR bit on Zen3/4 to check its presence. */
-               if (!wrmsrl_safe(MSR_IA32_PRED_CMD, PRED_CMD_SBPB)) {
-                       setup_force_cpu_cap(X86_FEATURE_SBPB);
-                       return true;
-               } else {
-                       return false;
-               }
-       default:
-               return false;
-       }
-}
-
 /*
  * Issue a DIV 0/1 insn to clear any division data from previous DIV
  * operations.
index f081d26..10499bc 100644 (file)
@@ -2404,27 +2404,16 @@ early_param("spec_rstack_overflow", srso_parse_cmdline);
 
 static void __init srso_select_mitigation(void)
 {
-       bool has_microcode;
+       bool has_microcode = boot_cpu_has(X86_FEATURE_IBPB_BRTYPE);
 
        if (!boot_cpu_has_bug(X86_BUG_SRSO) || cpu_mitigations_off())
                goto pred_cmd;
 
-       /*
-        * The first check is for the kernel running as a guest in order
-        * for guests to verify whether IBPB is a viable mitigation.
-        */
-       has_microcode = boot_cpu_has(X86_FEATURE_IBPB_BRTYPE) || cpu_has_ibpb_brtype_microcode();
        if (!has_microcode) {
                pr_warn("IBPB-extending microcode not applied!\n");
                pr_warn(SRSO_NOTICE);
        } else {
                /*
-                * Enable the synthetic (even if in a real CPUID leaf)
-                * flags for guests.
-                */
-               setup_force_cpu_cap(X86_FEATURE_IBPB_BRTYPE);
-
-               /*
                 * Zen1/2 with SMT off aren't vulnerable after the right
                 * IBPB microcode has been applied.
                 */
@@ -2444,7 +2433,7 @@ static void __init srso_select_mitigation(void)
 
        switch (srso_cmd) {
        case SRSO_CMD_OFF:
-               return;
+               goto pred_cmd;
 
        case SRSO_CMD_MICROCODE:
                if (has_microcode) {
@@ -2717,7 +2706,7 @@ static ssize_t srso_show_state(char *buf)
 
        return sysfs_emit(buf, "%s%s\n",
                          srso_strings[srso_mitigation],
-                         (cpu_has_ibpb_brtype_microcode() ? "" : ", no microcode"));
+                         boot_cpu_has(X86_FEATURE_IBPB_BRTYPE) ? "" : ", no microcode");
 }
 
 static ssize_t gds_show_state(char *buf)
index 382d4e6..4e5ffc8 100644 (file)
@@ -1303,7 +1303,7 @@ static const struct x86_cpu_id cpu_vuln_blacklist[] __initconst = {
        VULNBL_AMD(0x15, RETBLEED),
        VULNBL_AMD(0x16, RETBLEED),
        VULNBL_AMD(0x17, RETBLEED | SMT_RSB | SRSO),
-       VULNBL_HYGON(0x18, RETBLEED | SMT_RSB),
+       VULNBL_HYGON(0x18, RETBLEED | SMT_RSB | SRSO),
        VULNBL_AMD(0x19, SRSO),
        {}
 };
index 91fa70e..279148e 100644 (file)
@@ -235,6 +235,21 @@ static struct sgx_epc_page *sgx_encl_eldu(struct sgx_encl_page *encl_page,
        return epc_page;
 }
 
+/*
+ * Ensure the SECS page is not swapped out.  Must be called with encl->lock
+ * to protect the enclave states including SECS and ensure the SECS page is
+ * not swapped out again while being used.
+ */
+static struct sgx_epc_page *sgx_encl_load_secs(struct sgx_encl *encl)
+{
+       struct sgx_epc_page *epc_page = encl->secs.epc_page;
+
+       if (!epc_page)
+               epc_page = sgx_encl_eldu(&encl->secs, NULL);
+
+       return epc_page;
+}
+
 static struct sgx_encl_page *__sgx_encl_load_page(struct sgx_encl *encl,
                                                  struct sgx_encl_page *entry)
 {
@@ -248,11 +263,9 @@ static struct sgx_encl_page *__sgx_encl_load_page(struct sgx_encl *encl,
                return entry;
        }
 
-       if (!(encl->secs.epc_page)) {
-               epc_page = sgx_encl_eldu(&encl->secs, NULL);
-               if (IS_ERR(epc_page))
-                       return ERR_CAST(epc_page);
-       }
+       epc_page = sgx_encl_load_secs(encl);
+       if (IS_ERR(epc_page))
+               return ERR_CAST(epc_page);
 
        epc_page = sgx_encl_eldu(entry, encl->secs.epc_page);
        if (IS_ERR(epc_page))
@@ -339,6 +352,13 @@ static vm_fault_t sgx_encl_eaug_page(struct vm_area_struct *vma,
 
        mutex_lock(&encl->lock);
 
+       epc_page = sgx_encl_load_secs(encl);
+       if (IS_ERR(epc_page)) {
+               if (PTR_ERR(epc_page) == -EBUSY)
+                       vmret = VM_FAULT_NOPAGE;
+               goto err_out_unlock;
+       }
+
        epc_page = sgx_alloc_epc_page(encl_page, false);
        if (IS_ERR(epc_page)) {
                if (PTR_ERR(epc_page) == -EBUSY)
index a86d370..a21a4d0 100644 (file)
@@ -369,14 +369,15 @@ int fpu_swap_kvm_fpstate(struct fpu_guest *guest_fpu, bool enter_guest)
 EXPORT_SYMBOL_GPL(fpu_swap_kvm_fpstate);
 
 void fpu_copy_guest_fpstate_to_uabi(struct fpu_guest *gfpu, void *buf,
-                                   unsigned int size, u32 pkru)
+                                   unsigned int size, u64 xfeatures, u32 pkru)
 {
        struct fpstate *kstate = gfpu->fpstate;
        union fpregs_state *ustate = buf;
        struct membuf mb = { .p = buf, .left = size };
 
        if (cpu_feature_enabled(X86_FEATURE_XSAVE)) {
-               __copy_xstate_to_uabi_buf(mb, kstate, pkru, XSTATE_COPY_XSAVE);
+               __copy_xstate_to_uabi_buf(mb, kstate, xfeatures, pkru,
+                                         XSTATE_COPY_XSAVE);
        } else {
                memcpy(&ustate->fxsave, &kstate->regs.fxsave,
                       sizeof(ustate->fxsave));
index cadf687..ef69061 100644 (file)
@@ -1049,6 +1049,7 @@ static void copy_feature(bool from_xstate, struct membuf *to, void *xstate,
  * __copy_xstate_to_uabi_buf - Copy kernel saved xstate to a UABI buffer
  * @to:                membuf descriptor
  * @fpstate:   The fpstate buffer from which to copy
+ * @xfeatures: The mask of xfeatures to save (XSAVE mode only)
  * @pkru_val:  The PKRU value to store in the PKRU component
  * @copy_mode: The requested copy mode
  *
@@ -1059,7 +1060,8 @@ static void copy_feature(bool from_xstate, struct membuf *to, void *xstate,
  * It supports partial copy but @to.pos always starts from zero.
  */
 void __copy_xstate_to_uabi_buf(struct membuf to, struct fpstate *fpstate,
-                              u32 pkru_val, enum xstate_copy_mode copy_mode)
+                              u64 xfeatures, u32 pkru_val,
+                              enum xstate_copy_mode copy_mode)
 {
        const unsigned int off_mxcsr = offsetof(struct fxregs_state, mxcsr);
        struct xregs_state *xinit = &init_fpstate.regs.xsave;
@@ -1083,7 +1085,7 @@ void __copy_xstate_to_uabi_buf(struct membuf to, struct fpstate *fpstate,
                break;
 
        case XSTATE_COPY_XSAVE:
-               header.xfeatures &= fpstate->user_xfeatures;
+               header.xfeatures &= fpstate->user_xfeatures & xfeatures;
                break;
        }
 
@@ -1185,6 +1187,7 @@ void copy_xstate_to_uabi_buf(struct membuf to, struct task_struct *tsk,
                             enum xstate_copy_mode copy_mode)
 {
        __copy_xstate_to_uabi_buf(to, tsk->thread.fpu.fpstate,
+                                 tsk->thread.fpu.fpstate->user_xfeatures,
                                  tsk->thread.pkru, copy_mode);
 }
 
@@ -1536,10 +1539,7 @@ static int fpstate_realloc(u64 xfeatures, unsigned int ksize,
                fpregs_restore_userregs();
 
        newfps->xfeatures = curfps->xfeatures | xfeatures;
-
-       if (!guest_fpu)
-               newfps->user_xfeatures = curfps->user_xfeatures | xfeatures;
-
+       newfps->user_xfeatures = curfps->user_xfeatures | xfeatures;
        newfps->xfd = curfps->xfd & ~xfeatures;
 
        /* Do the final updates within the locked region */
index a4ecb04..3518fb2 100644 (file)
@@ -43,7 +43,8 @@ enum xstate_copy_mode {
 
 struct membuf;
 extern void __copy_xstate_to_uabi_buf(struct membuf to, struct fpstate *fpstate,
-                                     u32 pkru_val, enum xstate_copy_mode copy_mode);
+                                     u64 xfeatures, u32 pkru_val,
+                                     enum xstate_copy_mode copy_mode);
 extern void copy_xstate_to_uabi_buf(struct membuf to, struct task_struct *tsk,
                                    enum xstate_copy_mode mode);
 extern int copy_uabi_from_kernel_to_xstate(struct fpstate *fpstate, const void *kbuf, u32 *pkru);
index 3a43a2d..9c9faa1 100644 (file)
@@ -695,7 +695,6 @@ void kgdb_arch_exit(void)
 }
 
 /**
- *
  *     kgdb_skipexception - Bail out of KGDB when we've been triggered.
  *     @exception: Exception vector number
  *     @regs: Current &struct pt_regs.
index 975f98d..97f1436 100644 (file)
@@ -143,66 +143,7 @@ int paravirt_disable_iospace(void)
        return request_resource(&ioport_resource, &reserve_ioports);
 }
 
-static DEFINE_PER_CPU(enum paravirt_lazy_mode, paravirt_lazy_mode) = PARAVIRT_LAZY_NONE;
-
-static inline void enter_lazy(enum paravirt_lazy_mode mode)
-{
-       BUG_ON(this_cpu_read(paravirt_lazy_mode) != PARAVIRT_LAZY_NONE);
-
-       this_cpu_write(paravirt_lazy_mode, mode);
-}
-
-static void leave_lazy(enum paravirt_lazy_mode mode)
-{
-       BUG_ON(this_cpu_read(paravirt_lazy_mode) != mode);
-
-       this_cpu_write(paravirt_lazy_mode, PARAVIRT_LAZY_NONE);
-}
-
-void paravirt_enter_lazy_mmu(void)
-{
-       enter_lazy(PARAVIRT_LAZY_MMU);
-}
-
-void paravirt_leave_lazy_mmu(void)
-{
-       leave_lazy(PARAVIRT_LAZY_MMU);
-}
-
-void paravirt_flush_lazy_mmu(void)
-{
-       preempt_disable();
-
-       if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU) {
-               arch_leave_lazy_mmu_mode();
-               arch_enter_lazy_mmu_mode();
-       }
-
-       preempt_enable();
-}
-
 #ifdef CONFIG_PARAVIRT_XXL
-void paravirt_start_context_switch(struct task_struct *prev)
-{
-       BUG_ON(preemptible());
-
-       if (this_cpu_read(paravirt_lazy_mode) == PARAVIRT_LAZY_MMU) {
-               arch_leave_lazy_mmu_mode();
-               set_ti_thread_flag(task_thread_info(prev), TIF_LAZY_MMU_UPDATES);
-       }
-       enter_lazy(PARAVIRT_LAZY_CPU);
-}
-
-void paravirt_end_context_switch(struct task_struct *next)
-{
-       BUG_ON(preemptible());
-
-       leave_lazy(PARAVIRT_LAZY_CPU);
-
-       if (test_and_clear_ti_thread_flag(task_thread_info(next), TIF_LAZY_MMU_UPDATES))
-               arch_enter_lazy_mmu_mode();
-}
-
 static noinstr void pv_native_write_cr2(unsigned long val)
 {
        native_write_cr2(val);
@@ -229,14 +170,6 @@ static noinstr void pv_native_safe_halt(void)
 }
 #endif
 
-enum paravirt_lazy_mode paravirt_get_lazy_mode(void)
-{
-       if (in_interrupt())
-               return PARAVIRT_LAZY_NONE;
-
-       return this_cpu_read(paravirt_lazy_mode);
-}
-
 struct pv_info pv_info = {
        .name = "bare hardware",
 #ifdef CONFIG_PARAVIRT_XXL
index 9f09091..b6f4e83 100644 (file)
@@ -257,13 +257,6 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
        if (!ret && unlikely(test_tsk_thread_flag(current, TIF_IO_BITMAP)))
                io_bitmap_share(p);
 
-       /*
-        * If copy_thread() if failing, don't leak the shadow stack possibly
-        * allocated in shstk_alloc_thread_stack() above.
-        */
-       if (ret)
-               shstk_free(p);
-
        return ret;
 }
 
index b9145a6..b098b1f 100644 (file)
@@ -358,15 +358,11 @@ static void __init add_early_ima_buffer(u64 phys_addr)
 #if defined(CONFIG_HAVE_IMA_KEXEC) && !defined(CONFIG_OF_FLATTREE)
 int __init ima_free_kexec_buffer(void)
 {
-       int rc;
-
        if (!ima_kexec_buffer_size)
                return -ENOENT;
 
-       rc = memblock_phys_free(ima_kexec_buffer_phys,
-                               ima_kexec_buffer_size);
-       if (rc)
-               return rc;
+       memblock_free_late(ima_kexec_buffer_phys,
+                          ima_kexec_buffer_size);
 
        ima_kexec_buffer_phys = 0;
        ima_kexec_buffer_size = 0;
index 2eabccd..dcf325b 100644 (file)
@@ -256,7 +256,7 @@ static int __sev_cpuid_hv(u32 fn, int reg_idx, u32 *reg)
        return 0;
 }
 
-static int sev_cpuid_hv(struct cpuid_leaf *leaf)
+static int __sev_cpuid_hv_msr(struct cpuid_leaf *leaf)
 {
        int ret;
 
@@ -279,6 +279,45 @@ static int sev_cpuid_hv(struct cpuid_leaf *leaf)
        return ret;
 }
 
+static int __sev_cpuid_hv_ghcb(struct ghcb *ghcb, struct es_em_ctxt *ctxt, struct cpuid_leaf *leaf)
+{
+       u32 cr4 = native_read_cr4();
+       int ret;
+
+       ghcb_set_rax(ghcb, leaf->fn);
+       ghcb_set_rcx(ghcb, leaf->subfn);
+
+       if (cr4 & X86_CR4_OSXSAVE)
+               /* Safe to read xcr0 */
+               ghcb_set_xcr0(ghcb, xgetbv(XCR_XFEATURE_ENABLED_MASK));
+       else
+               /* xgetbv will cause #UD - use reset value for xcr0 */
+               ghcb_set_xcr0(ghcb, 1);
+
+       ret = sev_es_ghcb_hv_call(ghcb, ctxt, SVM_EXIT_CPUID, 0, 0);
+       if (ret != ES_OK)
+               return ret;
+
+       if (!(ghcb_rax_is_valid(ghcb) &&
+             ghcb_rbx_is_valid(ghcb) &&
+             ghcb_rcx_is_valid(ghcb) &&
+             ghcb_rdx_is_valid(ghcb)))
+               return ES_VMM_ERROR;
+
+       leaf->eax = ghcb->save.rax;
+       leaf->ebx = ghcb->save.rbx;
+       leaf->ecx = ghcb->save.rcx;
+       leaf->edx = ghcb->save.rdx;
+
+       return ES_OK;
+}
+
+static int sev_cpuid_hv(struct ghcb *ghcb, struct es_em_ctxt *ctxt, struct cpuid_leaf *leaf)
+{
+       return ghcb ? __sev_cpuid_hv_ghcb(ghcb, ctxt, leaf)
+                   : __sev_cpuid_hv_msr(leaf);
+}
+
 /*
  * This may be called early while still running on the initial identity
  * mapping. Use RIP-relative addressing to obtain the correct address
@@ -388,19 +427,20 @@ snp_cpuid_get_validated_func(struct cpuid_leaf *leaf)
        return false;
 }
 
-static void snp_cpuid_hv(struct cpuid_leaf *leaf)
+static void snp_cpuid_hv(struct ghcb *ghcb, struct es_em_ctxt *ctxt, struct cpuid_leaf *leaf)
 {
-       if (sev_cpuid_hv(leaf))
+       if (sev_cpuid_hv(ghcb, ctxt, leaf))
                sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_CPUID_HV);
 }
 
-static int snp_cpuid_postprocess(struct cpuid_leaf *leaf)
+static int snp_cpuid_postprocess(struct ghcb *ghcb, struct es_em_ctxt *ctxt,
+                                struct cpuid_leaf *leaf)
 {
        struct cpuid_leaf leaf_hv = *leaf;
 
        switch (leaf->fn) {
        case 0x1:
-               snp_cpuid_hv(&leaf_hv);
+               snp_cpuid_hv(ghcb, ctxt, &leaf_hv);
 
                /* initial APIC ID */
                leaf->ebx = (leaf_hv.ebx & GENMASK(31, 24)) | (leaf->ebx & GENMASK(23, 0));
@@ -419,7 +459,7 @@ static int snp_cpuid_postprocess(struct cpuid_leaf *leaf)
                break;
        case 0xB:
                leaf_hv.subfn = 0;
-               snp_cpuid_hv(&leaf_hv);
+               snp_cpuid_hv(ghcb, ctxt, &leaf_hv);
 
                /* extended APIC ID */
                leaf->edx = leaf_hv.edx;
@@ -467,7 +507,7 @@ static int snp_cpuid_postprocess(struct cpuid_leaf *leaf)
                }
                break;
        case 0x8000001E:
-               snp_cpuid_hv(&leaf_hv);
+               snp_cpuid_hv(ghcb, ctxt, &leaf_hv);
 
                /* extended APIC ID */
                leaf->eax = leaf_hv.eax;
@@ -488,7 +528,7 @@ static int snp_cpuid_postprocess(struct cpuid_leaf *leaf)
  * Returns -EOPNOTSUPP if feature not enabled. Any other non-zero return value
  * should be treated as fatal by caller.
  */
-static int snp_cpuid(struct cpuid_leaf *leaf)
+static int snp_cpuid(struct ghcb *ghcb, struct es_em_ctxt *ctxt, struct cpuid_leaf *leaf)
 {
        const struct snp_cpuid_table *cpuid_table = snp_cpuid_get_table();
 
@@ -522,7 +562,7 @@ static int snp_cpuid(struct cpuid_leaf *leaf)
                        return 0;
        }
 
-       return snp_cpuid_postprocess(leaf);
+       return snp_cpuid_postprocess(ghcb, ctxt, leaf);
 }
 
 /*
@@ -544,14 +584,14 @@ void __init do_vc_no_ghcb(struct pt_regs *regs, unsigned long exit_code)
        leaf.fn = fn;
        leaf.subfn = subfn;
 
-       ret = snp_cpuid(&leaf);
+       ret = snp_cpuid(NULL, NULL, &leaf);
        if (!ret)
                goto cpuid_done;
 
        if (ret != -EOPNOTSUPP)
                goto fail;
 
-       if (sev_cpuid_hv(&leaf))
+       if (__sev_cpuid_hv_msr(&leaf))
                goto fail;
 
 cpuid_done:
@@ -848,14 +888,15 @@ static enum es_result vc_handle_ioio(struct ghcb *ghcb, struct es_em_ctxt *ctxt)
        return ret;
 }
 
-static int vc_handle_cpuid_snp(struct pt_regs *regs)
+static int vc_handle_cpuid_snp(struct ghcb *ghcb, struct es_em_ctxt *ctxt)
 {
+       struct pt_regs *regs = ctxt->regs;
        struct cpuid_leaf leaf;
        int ret;
 
        leaf.fn = regs->ax;
        leaf.subfn = regs->cx;
-       ret = snp_cpuid(&leaf);
+       ret = snp_cpuid(ghcb, ctxt, &leaf);
        if (!ret) {
                regs->ax = leaf.eax;
                regs->bx = leaf.ebx;
@@ -874,7 +915,7 @@ static enum es_result vc_handle_cpuid(struct ghcb *ghcb,
        enum es_result ret;
        int snp_cpuid_ret;
 
-       snp_cpuid_ret = vc_handle_cpuid_snp(regs);
+       snp_cpuid_ret = vc_handle_cpuid_snp(ghcb, ctxt);
        if (!snp_cpuid_ret)
                return ES_OK;
        if (snp_cpuid_ret != -EOPNOTSUPP)
index 2787826..d8c1e3b 100644 (file)
@@ -868,8 +868,7 @@ void snp_set_memory_private(unsigned long vaddr, unsigned long npages)
 
 void snp_accept_memory(phys_addr_t start, phys_addr_t end)
 {
-       unsigned long vaddr;
-       unsigned int npages;
+       unsigned long vaddr, npages;
 
        if (!cc_platform_has(CC_ATTR_GUEST_SEV_SNP))
                return;
index fd68992..59e15dd 100644 (file)
@@ -205,10 +205,21 @@ unsigned long shstk_alloc_thread_stack(struct task_struct *tsk, unsigned long cl
                return 0;
 
        /*
-        * For CLONE_VM, except vfork, the child needs a separate shadow
+        * For CLONE_VFORK the child will share the parents shadow stack.
+        * Make sure to clear the internal tracking of the thread shadow
+        * stack so the freeing logic run for child knows to leave it alone.
+        */
+       if (clone_flags & CLONE_VFORK) {
+               shstk->base = 0;
+               shstk->size = 0;
+               return 0;
+       }
+
+       /*
+        * For !CLONE_VM the child will use a copy of the parents shadow
         * stack.
         */
-       if ((clone_flags & (CLONE_VFORK | CLONE_VM)) != CLONE_VM)
+       if (!(clone_flags & CLONE_VM))
                return 0;
 
        size = adjust_shstk_size(stack_size);
@@ -408,7 +419,25 @@ void shstk_free(struct task_struct *tsk)
        if (!tsk->mm || tsk->mm != current->mm)
                return;
 
+       /*
+        * If shstk->base is NULL, then this task is not managing its
+        * own shadow stack (CLONE_VFORK). So skip freeing it.
+        */
+       if (!shstk->base)
+               return;
+
+       /*
+        * shstk->base is NULL for CLONE_VFORK child tasks, and so is
+        * normal. But size = 0 on a shstk->base is not normal and
+        * indicated an attempt to free the thread shadow stack twice.
+        * Warn about it.
+        */
+       if (WARN_ON(!shstk->size))
+               return;
+
        unmap_shadow_stack(shstk->base, shstk->size);
+
+       shstk->size = 0;
 }
 
 static int wrss_control(bool enable)
index 0544e30..773132c 100644 (file)
@@ -360,14 +360,6 @@ static void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
        vcpu->arch.guest_supported_xcr0 =
                cpuid_get_supported_xcr0(vcpu->arch.cpuid_entries, vcpu->arch.cpuid_nent);
 
-       /*
-        * FP+SSE can always be saved/restored via KVM_{G,S}ET_XSAVE, even if
-        * XSAVE/XCRO are not exposed to the guest, and even if XSAVE isn't
-        * supported by the host.
-        */
-       vcpu->arch.guest_fpu.fpstate->user_xfeatures = vcpu->arch.guest_supported_xcr0 |
-                                                      XFEATURE_MASK_FPSSE;
-
        kvm_update_pv_runtime(vcpu);
 
        vcpu->arch.maxphyaddr = cpuid_query_maxphyaddr(vcpu);
index 2092db8..4b74ea9 100644 (file)
@@ -529,8 +529,11 @@ int avic_incomplete_ipi_interception(struct kvm_vcpu *vcpu)
        case AVIC_IPI_FAILURE_INVALID_BACKING_PAGE:
                WARN_ONCE(1, "Invalid backing page\n");
                break;
+       case AVIC_IPI_FAILURE_INVALID_IPI_VECTOR:
+               /* Invalid IPI with vector < 16 */
+               break;
        default:
-               pr_err("Unknown IPI interception\n");
+               vcpu_unimpl(vcpu, "Unknown avic incomplete IPI interception\n");
        }
 
        return 1;
index dd496c9..3fea8c4 100644 (file)
@@ -1253,6 +1253,9 @@ void svm_leave_nested(struct kvm_vcpu *vcpu)
 
                nested_svm_uninit_mmu_context(vcpu);
                vmcb_mark_all_dirty(svm->vmcb);
+
+               if (kvm_apicv_activated(vcpu->kvm))
+                       kvm_make_request(KVM_REQ_APICV_UPDATE, vcpu);
        }
 
        kvm_clear_request(KVM_REQ_GET_NESTED_STATE_PAGES, vcpu);
index 9507df9..beea99c 100644 (file)
@@ -691,7 +691,7 @@ static int svm_hardware_enable(void)
         */
        if (boot_cpu_has(X86_FEATURE_V_TSC_AUX)) {
                struct sev_es_save_area *hostsa;
-               u32 msr_hi;
+               u32 __maybe_unused msr_hi;
 
                hostsa = (struct sev_es_save_area *)(page_address(sd->save_area) + 0x400);
 
@@ -913,8 +913,7 @@ void svm_set_x2apic_msr_interception(struct vcpu_svm *svm, bool intercept)
        if (intercept == svm->x2avic_msrs_intercepted)
                return;
 
-       if (!x2avic_enabled ||
-           !apic_x2apic_mode(svm->vcpu.arch.apic))
+       if (!x2avic_enabled)
                return;
 
        for (i = 0; i < MAX_DIRECT_ACCESS_MSRS; i++) {
index 42a4e8f..41cce50 100644 (file)
@@ -5382,26 +5382,37 @@ static int kvm_vcpu_ioctl_x86_set_debugregs(struct kvm_vcpu *vcpu,
        return 0;
 }
 
-static void kvm_vcpu_ioctl_x86_get_xsave(struct kvm_vcpu *vcpu,
-                                        struct kvm_xsave *guest_xsave)
-{
-       if (fpstate_is_confidential(&vcpu->arch.guest_fpu))
-               return;
-
-       fpu_copy_guest_fpstate_to_uabi(&vcpu->arch.guest_fpu,
-                                      guest_xsave->region,
-                                      sizeof(guest_xsave->region),
-                                      vcpu->arch.pkru);
-}
 
 static void kvm_vcpu_ioctl_x86_get_xsave2(struct kvm_vcpu *vcpu,
                                          u8 *state, unsigned int size)
 {
+       /*
+        * Only copy state for features that are enabled for the guest.  The
+        * state itself isn't problematic, but setting bits in the header for
+        * features that are supported in *this* host but not exposed to the
+        * guest can result in KVM_SET_XSAVE failing when live migrating to a
+        * compatible host without the features that are NOT exposed to the
+        * guest.
+        *
+        * FP+SSE can always be saved/restored via KVM_{G,S}ET_XSAVE, even if
+        * XSAVE/XCRO are not exposed to the guest, and even if XSAVE isn't
+        * supported by the host.
+        */
+       u64 supported_xcr0 = vcpu->arch.guest_supported_xcr0 |
+                            XFEATURE_MASK_FPSSE;
+
        if (fpstate_is_confidential(&vcpu->arch.guest_fpu))
                return;
 
-       fpu_copy_guest_fpstate_to_uabi(&vcpu->arch.guest_fpu,
-                                      state, size, vcpu->arch.pkru);
+       fpu_copy_guest_fpstate_to_uabi(&vcpu->arch.guest_fpu, state, size,
+                                      supported_xcr0, vcpu->arch.pkru);
+}
+
+static void kvm_vcpu_ioctl_x86_get_xsave(struct kvm_vcpu *vcpu,
+                                        struct kvm_xsave *guest_xsave)
+{
+       return kvm_vcpu_ioctl_x86_get_xsave2(vcpu, (void *)guest_xsave->region,
+                                            sizeof(guest_xsave->region));
 }
 
 static int kvm_vcpu_ioctl_x86_set_xsave(struct kvm_vcpu *vcpu,
index 8f95fb2..76697df 100644 (file)
@@ -40,7 +40,7 @@ SYM_TYPED_FUNC_START(__memcpy)
 SYM_FUNC_END(__memcpy)
 EXPORT_SYMBOL(__memcpy)
 
-SYM_FUNC_ALIAS(memcpy, __memcpy)
+SYM_FUNC_ALIAS_MEMFUNC(memcpy, __memcpy)
 EXPORT_SYMBOL(memcpy)
 
 SYM_FUNC_START_LOCAL(memcpy_orig)
index 0559b20..ccdf3a5 100644 (file)
@@ -212,5 +212,5 @@ SYM_FUNC_START(__memmove)
 SYM_FUNC_END(__memmove)
 EXPORT_SYMBOL(__memmove)
 
-SYM_FUNC_ALIAS(memmove, __memmove)
+SYM_FUNC_ALIAS_MEMFUNC(memmove, __memmove)
 EXPORT_SYMBOL(memmove)
index 7c59a70..3d818b8 100644 (file)
@@ -40,7 +40,7 @@ SYM_FUNC_START(__memset)
 SYM_FUNC_END(__memset)
 EXPORT_SYMBOL(__memset)
 
-SYM_FUNC_ALIAS(memset, __memset)
+SYM_FUNC_ALIAS_MEMFUNC(memset, __memset)
 EXPORT_SYMBOL(memset)
 
 SYM_FUNC_START_LOCAL(memset_orig)
index 863d0d6..7250d0e 100644 (file)
@@ -138,7 +138,7 @@ void __init xen_efi_init(struct boot_params *boot_params)
        if (efi_systab_xen == NULL)
                return;
 
-       strncpy((char *)&boot_params->efi_info.efi_loader_signature, "Xen",
+       strscpy((char *)&boot_params->efi_info.efi_loader_signature, "Xen",
                        sizeof(boot_params->efi_info.efi_loader_signature));
        boot_params->efi_info.efi_systab = (__u32)__pa(efi_systab_xen);
        boot_params->efi_info.efi_systab_hi = (__u32)(__pa(efi_systab_xen) >> 32);
index b8db214..0337392 100644 (file)
@@ -32,7 +32,7 @@ EXPORT_SYMBOL_GPL(hypercall_page);
  * &HYPERVISOR_shared_info->vcpu_info[cpu]. See xen_hvm_init_shared_info
  * and xen_vcpu_setup for details. By default it points to share_info->vcpu_info
  * but during boot it is switched to point to xen_vcpu_info.
- * The pointer is used in __xen_evtchn_do_upcall to acknowledge pending events.
+ * The pointer is used in xen_evtchn_do_upcall to acknowledge pending events.
  */
 DEFINE_PER_CPU(struct vcpu_info *, xen_vcpu);
 DEFINE_PER_CPU(struct vcpu_info, xen_vcpu_info);
index 9a192f5..3f8c347 100644 (file)
@@ -136,7 +136,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_xen_hvm_callback)
 
        inc_irq_stat(irq_hv_callback_count);
 
-       xen_hvm_evtchn_do_upcall();
+       xen_evtchn_do_upcall();
 
        set_irq_regs(old_regs);
 }
index 49352fa..bbbfdd4 100644 (file)
@@ -101,6 +101,17 @@ struct tls_descs {
        struct desc_struct desc[3];
 };
 
+DEFINE_PER_CPU(enum xen_lazy_mode, xen_lazy_mode) = XEN_LAZY_NONE;
+DEFINE_PER_CPU(unsigned int, xen_lazy_nesting);
+
+enum xen_lazy_mode xen_get_lazy_mode(void)
+{
+       if (in_interrupt())
+               return XEN_LAZY_NONE;
+
+       return this_cpu_read(xen_lazy_mode);
+}
+
 /*
  * Updating the 3 TLS descriptors in the GDT on every task switch is
  * surprisingly expensive so we avoid updating them if they haven't
@@ -362,10 +373,25 @@ static noinstr unsigned long xen_get_debugreg(int reg)
        return HYPERVISOR_get_debugreg(reg);
 }
 
+static void xen_start_context_switch(struct task_struct *prev)
+{
+       BUG_ON(preemptible());
+
+       if (this_cpu_read(xen_lazy_mode) == XEN_LAZY_MMU) {
+               arch_leave_lazy_mmu_mode();
+               set_ti_thread_flag(task_thread_info(prev), TIF_LAZY_MMU_UPDATES);
+       }
+       enter_lazy(XEN_LAZY_CPU);
+}
+
 static void xen_end_context_switch(struct task_struct *next)
 {
+       BUG_ON(preemptible());
+
        xen_mc_flush();
-       paravirt_end_context_switch(next);
+       leave_lazy(XEN_LAZY_CPU);
+       if (test_and_clear_ti_thread_flag(task_thread_info(next), TIF_LAZY_MMU_UPDATES))
+               arch_enter_lazy_mmu_mode();
 }
 
 static unsigned long xen_store_tr(void)
@@ -472,7 +498,7 @@ static void xen_set_ldt(const void *addr, unsigned entries)
 
        MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF);
 
-       xen_mc_issue(PARAVIRT_LAZY_CPU);
+       xen_mc_issue(XEN_LAZY_CPU);
 }
 
 static void xen_load_gdt(const struct desc_ptr *dtr)
@@ -568,7 +594,7 @@ static void xen_load_tls(struct thread_struct *t, unsigned int cpu)
         * exception between the new %fs descriptor being loaded and
         * %fs being effectively cleared at __switch_to().
         */
-       if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_CPU)
+       if (xen_get_lazy_mode() == XEN_LAZY_CPU)
                loadsegment(fs, 0);
 
        xen_mc_batch();
@@ -577,7 +603,7 @@ static void xen_load_tls(struct thread_struct *t, unsigned int cpu)
        load_TLS_descriptor(t, cpu, 1);
        load_TLS_descriptor(t, cpu, 2);
 
-       xen_mc_issue(PARAVIRT_LAZY_CPU);
+       xen_mc_issue(XEN_LAZY_CPU);
 }
 
 static void xen_load_gs_index(unsigned int idx)
@@ -909,7 +935,7 @@ static void xen_load_sp0(unsigned long sp0)
 
        mcs = xen_mc_entry(0);
        MULTI_stack_switch(mcs.mc, __KERNEL_DS, sp0);
-       xen_mc_issue(PARAVIRT_LAZY_CPU);
+       xen_mc_issue(XEN_LAZY_CPU);
        this_cpu_write(cpu_tss_rw.x86_tss.sp0, sp0);
 }
 
@@ -973,7 +999,7 @@ static void xen_write_cr0(unsigned long cr0)
 
        MULTI_fpu_taskswitch(mcs.mc, (cr0 & X86_CR0_TS) != 0);
 
-       xen_mc_issue(PARAVIRT_LAZY_CPU);
+       xen_mc_issue(XEN_LAZY_CPU);
 }
 
 static void xen_write_cr4(unsigned long cr4)
@@ -1156,7 +1182,7 @@ static const typeof(pv_ops) xen_cpu_ops __initconst = {
 #endif
                .io_delay = xen_io_delay,
 
-               .start_context_switch = paravirt_start_context_switch,
+               .start_context_switch = xen_start_context_switch,
                .end_context_switch = xen_end_context_switch,
        },
 };
index 1652c39..b683055 100644 (file)
@@ -236,7 +236,7 @@ static void xen_set_pmd_hyper(pmd_t *ptr, pmd_t val)
        u.val = pmd_val_ma(val);
        xen_extend_mmu_update(&u);
 
-       xen_mc_issue(PARAVIRT_LAZY_MMU);
+       xen_mc_issue(XEN_LAZY_MMU);
 
        preempt_enable();
 }
@@ -270,7 +270,7 @@ static bool xen_batched_set_pte(pte_t *ptep, pte_t pteval)
 {
        struct mmu_update u;
 
-       if (paravirt_get_lazy_mode() != PARAVIRT_LAZY_MMU)
+       if (xen_get_lazy_mode() != XEN_LAZY_MMU)
                return false;
 
        xen_mc_batch();
@@ -279,7 +279,7 @@ static bool xen_batched_set_pte(pte_t *ptep, pte_t pteval)
        u.val = pte_val_ma(pteval);
        xen_extend_mmu_update(&u);
 
-       xen_mc_issue(PARAVIRT_LAZY_MMU);
+       xen_mc_issue(XEN_LAZY_MMU);
 
        return true;
 }
@@ -325,7 +325,7 @@ void xen_ptep_modify_prot_commit(struct vm_area_struct *vma, unsigned long addr,
        u.val = pte_val_ma(pte);
        xen_extend_mmu_update(&u);
 
-       xen_mc_issue(PARAVIRT_LAZY_MMU);
+       xen_mc_issue(XEN_LAZY_MMU);
 }
 
 /* Assume pteval_t is equivalent to all the other *val_t types. */
@@ -419,7 +419,7 @@ static void xen_set_pud_hyper(pud_t *ptr, pud_t val)
        u.val = pud_val_ma(val);
        xen_extend_mmu_update(&u);
 
-       xen_mc_issue(PARAVIRT_LAZY_MMU);
+       xen_mc_issue(XEN_LAZY_MMU);
 
        preempt_enable();
 }
@@ -499,7 +499,7 @@ static void __init xen_set_p4d_hyper(p4d_t *ptr, p4d_t val)
 
        __xen_set_p4d_hyper(ptr, val);
 
-       xen_mc_issue(PARAVIRT_LAZY_MMU);
+       xen_mc_issue(XEN_LAZY_MMU);
 
        preempt_enable();
 }
@@ -531,7 +531,7 @@ static void xen_set_p4d(p4d_t *ptr, p4d_t val)
        if (user_ptr)
                __xen_set_p4d_hyper((p4d_t *)user_ptr, val);
 
-       xen_mc_issue(PARAVIRT_LAZY_MMU);
+       xen_mc_issue(XEN_LAZY_MMU);
 }
 
 #if CONFIG_PGTABLE_LEVELS >= 5
@@ -1245,7 +1245,7 @@ static noinline void xen_flush_tlb(void)
        op->cmd = MMUEXT_TLB_FLUSH_LOCAL;
        MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF);
 
-       xen_mc_issue(PARAVIRT_LAZY_MMU);
+       xen_mc_issue(XEN_LAZY_MMU);
 
        preempt_enable();
 }
@@ -1265,7 +1265,7 @@ static void xen_flush_tlb_one_user(unsigned long addr)
        op->arg1.linear_addr = addr & PAGE_MASK;
        MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF);
 
-       xen_mc_issue(PARAVIRT_LAZY_MMU);
+       xen_mc_issue(XEN_LAZY_MMU);
 
        preempt_enable();
 }
@@ -1302,7 +1302,7 @@ static void xen_flush_tlb_multi(const struct cpumask *cpus,
 
        MULTI_mmuext_op(mcs.mc, &args->op, 1, NULL, DOMID_SELF);
 
-       xen_mc_issue(PARAVIRT_LAZY_MMU);
+       xen_mc_issue(XEN_LAZY_MMU);
 }
 
 static unsigned long xen_read_cr3(void)
@@ -1361,7 +1361,7 @@ static void xen_write_cr3(unsigned long cr3)
        else
                __xen_write_cr3(false, 0);
 
-       xen_mc_issue(PARAVIRT_LAZY_CPU);  /* interrupts restored */
+       xen_mc_issue(XEN_LAZY_CPU);  /* interrupts restored */
 }
 
 /*
@@ -1396,7 +1396,7 @@ static void __init xen_write_cr3_init(unsigned long cr3)
 
        __xen_write_cr3(true, cr3);
 
-       xen_mc_issue(PARAVIRT_LAZY_CPU);  /* interrupts restored */
+       xen_mc_issue(XEN_LAZY_CPU);  /* interrupts restored */
 }
 
 static int xen_pgd_alloc(struct mm_struct *mm)
@@ -1557,7 +1557,7 @@ static inline void xen_alloc_ptpage(struct mm_struct *mm, unsigned long pfn,
                if (level == PT_PTE && USE_SPLIT_PTE_PTLOCKS && !pinned)
                        __pin_pagetable_pfn(MMUEXT_PIN_L1_TABLE, pfn);
 
-               xen_mc_issue(PARAVIRT_LAZY_MMU);
+               xen_mc_issue(XEN_LAZY_MMU);
        }
 }
 
@@ -1587,7 +1587,7 @@ static inline void xen_release_ptpage(unsigned long pfn, unsigned level)
 
                __set_pfn_prot(pfn, PAGE_KERNEL);
 
-               xen_mc_issue(PARAVIRT_LAZY_MMU);
+               xen_mc_issue(XEN_LAZY_MMU);
 
                ClearPagePinned(page);
        }
@@ -1804,7 +1804,7 @@ void __init xen_setup_kernel_pagetable(pgd_t *pgd, unsigned long max_pfn)
         */
        xen_mc_batch();
        __xen_write_cr3(true, __pa(init_top_pgt));
-       xen_mc_issue(PARAVIRT_LAZY_CPU);
+       xen_mc_issue(XEN_LAZY_CPU);
 
        /* We can't that easily rip out L3 and L2, as the Xen pagetables are
         * set out this way: [L4], [L1], [L2], [L3], [L1], [L1] ...  for
@@ -2083,6 +2083,23 @@ static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot)
 #endif
 }
 
+static void xen_enter_lazy_mmu(void)
+{
+       enter_lazy(XEN_LAZY_MMU);
+}
+
+static void xen_flush_lazy_mmu(void)
+{
+       preempt_disable();
+
+       if (xen_get_lazy_mode() == XEN_LAZY_MMU) {
+               arch_leave_lazy_mmu_mode();
+               arch_enter_lazy_mmu_mode();
+       }
+
+       preempt_enable();
+}
+
 static void __init xen_post_allocator_init(void)
 {
        pv_ops.mmu.set_pte = xen_set_pte;
@@ -2107,7 +2124,7 @@ static void xen_leave_lazy_mmu(void)
 {
        preempt_disable();
        xen_mc_flush();
-       paravirt_leave_lazy_mmu();
+       leave_lazy(XEN_LAZY_MMU);
        preempt_enable();
 }
 
@@ -2166,9 +2183,9 @@ static const typeof(pv_ops) xen_mmu_ops __initconst = {
                .exit_mmap = xen_exit_mmap,
 
                .lazy_mode = {
-                       .enter = paravirt_enter_lazy_mmu,
+                       .enter = xen_enter_lazy_mmu,
                        .leave = xen_leave_lazy_mmu,
-                       .flush = paravirt_flush_lazy_mmu,
+                       .flush = xen_flush_lazy_mmu,
                },
 
                .set_fixmap = xen_set_fixmap,
@@ -2385,7 +2402,7 @@ static noinline void xen_flush_tlb_all(void)
        op->cmd = MMUEXT_TLB_FLUSH_ALL;
        MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF);
 
-       xen_mc_issue(PARAVIRT_LAZY_MMU);
+       xen_mc_issue(XEN_LAZY_MMU);
 
        preempt_enable();
 }
index 1c51b2c..c3867b5 100644 (file)
@@ -26,7 +26,7 @@ static inline void xen_mc_batch(void)
 
        /* need to disable interrupts until this entry is complete */
        local_irq_save(flags);
-       trace_xen_mc_batch(paravirt_get_lazy_mode());
+       trace_xen_mc_batch(xen_get_lazy_mode());
        __this_cpu_write(xen_mc_irq_flags, flags);
 }
 
@@ -44,7 +44,7 @@ static inline void xen_mc_issue(unsigned mode)
 {
        trace_xen_mc_issue(mode);
 
-       if ((paravirt_get_lazy_mode() & mode) == 0)
+       if ((xen_get_lazy_mode() & mode) == 0)
                xen_mc_flush();
 
        /* restore flags saved in xen_mc_batch */
index a65b7a9..d8b0fad 100644 (file)
@@ -9,8 +9,7 @@
 
 
 # KBUILD_CFLAGS used when building rest of boot (takes effect recursively)
-KBUILD_CFLAGS  += -fno-builtin -Iarch/$(ARCH)/boot/include
-HOSTFLAGS      += -Iarch/$(ARCH)/boot/include
+KBUILD_CFLAGS  += -fno-builtin
 
 subdir-y       := lib
 targets                += vmlinux.bin vmlinux.bin.gz
index e3ecd74..b891893 100644 (file)
@@ -4,13 +4,14 @@
 /* bits taken from ppc */
 
 extern void *avail_ram, *end_avail;
+void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp);
 
-void exit (void)
+static void exit(void)
 {
   for (;;);
 }
 
-void *zalloc(unsigned size)
+static void *zalloc(unsigned int size)
 {
         void *p = avail_ram;
 
index 3f5ffae..6f02f6f 100644 (file)
@@ -6,6 +6,10 @@
 
 #include <variant/core.h>
 
+#ifndef XCHAL_HAVE_DIV32
+#define XCHAL_HAVE_DIV32 0
+#endif
+
 #ifndef XCHAL_HAVE_EXCLUSIVE
 #define XCHAL_HAVE_EXCLUSIVE 0
 #endif
index 9f119c1..9ec86f4 100644 (file)
@@ -48,6 +48,7 @@ void arch_uninstall_hw_breakpoint(struct perf_event *bp);
 void hw_breakpoint_pmu_read(struct perf_event *bp);
 int check_hw_breakpoint(struct pt_regs *regs);
 void clear_ptrace_hw_breakpoint(struct task_struct *tsk);
+void restore_dbreak(void);
 
 #else
 
index a6d09fe..d008a15 100644 (file)
@@ -14,6 +14,8 @@
 
 #include <linux/compiler.h>
 #include <linux/stringify.h>
+
+#include <asm/bootparam.h>
 #include <asm/ptrace.h>
 #include <asm/types.h>
 #include <asm/regs.h>
@@ -217,6 +219,9 @@ struct mm_struct;
 
 extern unsigned long __get_wchan(struct task_struct *p);
 
+void init_arch(bp_tag_t *bp_start);
+void do_notify_resume(struct pt_regs *regs);
+
 #define KSTK_EIP(tsk)          (task_pt_regs(tsk)->pc)
 #define KSTK_ESP(tsk)          (task_pt_regs(tsk)->areg[1])
 
index 308f209..a270467 100644 (file)
@@ -106,6 +106,9 @@ static inline unsigned long regs_return_value(struct pt_regs *regs)
        return regs->areg[2];
 }
 
+int do_syscall_trace_enter(struct pt_regs *regs);
+void do_syscall_trace_leave(struct pt_regs *regs);
+
 #else  /* __ASSEMBLY__ */
 
 # include <asm/asm-offsets.h>
index 5dc5bf8..e446e6f 100644 (file)
@@ -23,6 +23,7 @@ struct cpumask;
 void arch_send_call_function_ipi_mask(const struct cpumask *mask);
 void arch_send_call_function_single_ipi(int cpu);
 
+void secondary_start_kernel(void);
 void smp_init_cpus(void);
 void secondary_init_irq(void);
 void ipi_init(void);
index 5088993..8c3ceb4 100644 (file)
@@ -18,4 +18,6 @@
 
 #define __pte_free_tlb(tlb, pte, address)      pte_free((tlb)->mm, pte)
 
+void check_tlb_sanity(void);
+
 #endif /* _XTENSA_TLB_H */
index 285fb29..1eeecd5 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/percpu.h>
 #include <linux/perf_event.h>
 #include <asm/core.h>
+#include <asm/hw_breakpoint.h>
 
 /* Breakpoint currently in use for each IBREAKA. */
 static DEFINE_PER_CPU(struct perf_event *, bp_on_reg[XCHAL_NUM_IBREAK]);
index 42f1060..b1e410f 100644 (file)
@@ -28,6 +28,7 @@
 #include <asm/mxregs.h>
 #include <linux/uaccess.h>
 #include <asm/platform.h>
+#include <asm/traps.h>
 
 DECLARE_PER_CPU(unsigned long, nmi_count);
 
index f294771..9056cd1 100644 (file)
@@ -541,7 +541,6 @@ long arch_ptrace(struct task_struct *child, long request,
        return ret;
 }
 
-void do_syscall_trace_leave(struct pt_regs *regs);
 int do_syscall_trace_enter(struct pt_regs *regs)
 {
        if (regs->syscall == NO_SYSCALL)
index 5c01d7e..81f0b10 100644 (file)
@@ -26,6 +26,8 @@
 #include <linux/uaccess.h>
 #include <asm/cacheflush.h>
 #include <asm/coprocessor.h>
+#include <asm/processor.h>
+#include <asm/syscall.h>
 #include <asm/unistd.h>
 
 extern struct task_struct *coproc_owners[];
index 07dd6ba..94a23f1 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/irq.h>
 #include <linux/kdebug.h>
 #include <linux/module.h>
+#include <linux/profile.h>
 #include <linux/sched/mm.h>
 #include <linux/sched/hotplug.h>
 #include <linux/sched/task_stack.h>
index f643ea5..831ffb6 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/sched.h>
 #include <linux/stacktrace.h>
 
+#include <asm/ftrace.h>
 #include <asm/stacktrace.h>
 #include <asm/traps.h>
 #include <linux/uaccess.h>
index 427c125..38092d2 100644 (file)
@@ -23,6 +23,7 @@
  * for more details.
  */
 
+#include <linux/cpu.h>
 #include <linux/kernel.h>
 #include <linux/sched/signal.h>
 #include <linux/sched/debug.h>
index 8c7a94a..5da501b 100644 (file)
@@ -3,7 +3,9 @@
 #include <asm/asmmacro.h>
 #include <asm/core.h>
 
-#if !XCHAL_HAVE_MUL16 && !XCHAL_HAVE_MUL32 && !XCHAL_HAVE_MAC16
+#if XCHAL_HAVE_MUL16 || XCHAL_HAVE_MUL32 || XCHAL_HAVE_MAC16
+#define XCHAL_NO_MUL 0
+#else
 #define XCHAL_NO_MUL 1
 #endif
 
index d1eb8d6..16e11b6 100644 (file)
@@ -20,6 +20,7 @@
 #include <asm/mmu_context.h>
 #include <asm/cacheflush.h>
 #include <asm/hardirq.h>
+#include <asm/traps.h>
 
 void bad_page_fault(struct pt_regs*, unsigned long, int);
 
index 0a11fc5..4f974b7 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/mm.h>
 #include <asm/processor.h>
 #include <asm/mmu_context.h>
+#include <asm/tlb.h>
 #include <asm/tlbflush.h>
 #include <asm/cacheflush.h>
 
index 85c82cd..e89f27f 100644 (file)
@@ -201,7 +201,7 @@ static int tuntap_write(struct iss_net_private *lp, struct sk_buff **skb)
        return simc_write(lp->tp.info.tuntap.fd, (*skb)->data, (*skb)->len);
 }
 
-unsigned short tuntap_protocol(struct sk_buff *skb)
+static unsigned short tuntap_protocol(struct sk_buff *skb)
 {
        return eth_type_trans(skb, skb->dev);
 }
@@ -441,7 +441,7 @@ static int iss_net_change_mtu(struct net_device *dev, int new_mtu)
        return -EINVAL;
 }
 
-void iss_net_user_timer_expire(struct timer_list *unused)
+static void iss_net_user_timer_expire(struct timer_list *unused)
 {
 }
 
index 167be74..dd7310c 100644 (file)
@@ -270,7 +270,7 @@ void rq_qos_wait(struct rq_wait *rqw, void *private_data,
                        finish_wait(&rqw->wait, &data.wq);
 
                        /*
-                        * We raced with wbt_wake_function() getting a token,
+                        * We raced with rq_qos_wake_function() getting a token,
                         * which means we now have two. Put our local token
                         * and wake anyone else potentially waiting for one.
                         */
index 422db82..13c3372 100644 (file)
@@ -290,7 +290,6 @@ EXPORT_SYMBOL(disk_check_media_change);
 /**
  * disk_force_media_change - force a media change event
  * @disk: the disk which will raise the event
- * @events: the events to raise
  *
  * Should be called when the media changes for @disk.  Generates a uevent
  * and attempts to free all dentries and inodes and invalidates all block
index 285b3cb..5ab120d 100644 (file)
@@ -278,10 +278,14 @@ int sm2_compute_z_digest(struct shash_desc *desc,
        if (!ec)
                return -ENOMEM;
 
-       err = __sm2_set_pub_key(ec, key, keylen);
+       err = sm2_ec_ctx_init(ec);
        if (err)
                goto out_free_ec;
 
+       err = __sm2_set_pub_key(ec, key, keylen);
+       if (err)
+               goto out_deinit_ec;
+
        bits_len = SM2_DEFAULT_USERID_LEN * 8;
        entl[0] = bits_len >> 8;
        entl[1] = bits_len & 0xff;
index ba79f39..467a602 100644 (file)
@@ -327,7 +327,7 @@ static int ivpu_wait_for_ready(struct ivpu_device *vdev)
        }
 
        if (!ret)
-               ivpu_info(vdev, "VPU ready message received successfully\n");
+               ivpu_dbg(vdev, PM, "VPU ready message received successfully\n");
        else
                ivpu_hw_diagnose_failure(vdev);
 
@@ -634,6 +634,7 @@ static void ivpu_dev_fini(struct ivpu_device *vdev)
 
 static struct pci_device_id ivpu_pci_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_MTL) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_ARL) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_LNL) },
        { }
 };
index 9e8c075..03b3d65 100644 (file)
@@ -23,6 +23,7 @@
 #define DRIVER_DATE "20230117"
 
 #define PCI_DEVICE_ID_MTL   0x7d1d
+#define PCI_DEVICE_ID_ARL   0xad1d
 #define PCI_DEVICE_ID_LNL   0x643e
 
 #define IVPU_HW_37XX   37
@@ -165,6 +166,7 @@ static inline int ivpu_hw_gen(struct ivpu_device *vdev)
 {
        switch (ivpu_device_id(vdev)) {
        case PCI_DEVICE_ID_MTL:
+       case PCI_DEVICE_ID_ARL:
                return IVPU_HW_37XX;
        case PCI_DEVICE_ID_LNL:
                return IVPU_HW_40XX;
index 9827ea4..0191cf8 100644 (file)
@@ -220,7 +220,8 @@ static int ivpu_fw_mem_init(struct ivpu_device *vdev)
        if (ret)
                return ret;
 
-       fw->mem = ivpu_bo_alloc_internal(vdev, fw->runtime_addr, fw->runtime_size, DRM_IVPU_BO_WC);
+       fw->mem = ivpu_bo_alloc_internal(vdev, fw->runtime_addr, fw->runtime_size,
+                                        DRM_IVPU_BO_CACHED | DRM_IVPU_BO_NOSNOOP);
        if (!fw->mem) {
                ivpu_err(vdev, "Failed to allocate firmware runtime memory\n");
                return -ENOMEM;
@@ -330,7 +331,7 @@ int ivpu_fw_load(struct ivpu_device *vdev)
                memset(start, 0, size);
        }
 
-       wmb(); /* Flush WC buffers after writing fw->mem */
+       clflush_cache_range(fw->mem->kvaddr, fw->mem->base.size);
 
        return 0;
 }
@@ -432,6 +433,7 @@ void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params
        if (!ivpu_fw_is_cold_boot(vdev)) {
                boot_params->save_restore_ret_address = 0;
                vdev->pm->is_warmboot = true;
+               clflush_cache_range(vdev->fw->mem->kvaddr, SZ_4K);
                return;
        }
 
@@ -493,7 +495,7 @@ void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params
        boot_params->punit_telemetry_sram_size = ivpu_hw_reg_telemetry_size_get(vdev);
        boot_params->vpu_telemetry_enable = ivpu_hw_reg_telemetry_enable_get(vdev);
 
-       wmb(); /* Flush WC buffers after writing bootparams */
+       clflush_cache_range(vdev->fw->mem->kvaddr, SZ_4K);
 
        ivpu_fw_boot_params_print(vdev, boot_params);
 }
index 6b0ceda..f413058 100644 (file)
@@ -8,6 +8,8 @@
 #include <drm/drm_gem.h>
 #include <drm/drm_mm.h>
 
+#define DRM_IVPU_BO_NOSNOOP       0x10000000
+
 struct dma_buf;
 struct ivpu_bo_ops;
 struct ivpu_file_priv;
@@ -83,6 +85,9 @@ static inline u32 ivpu_bo_cache_mode(struct ivpu_bo *bo)
 
 static inline bool ivpu_bo_is_snooped(struct ivpu_bo *bo)
 {
+       if (bo->flags & DRM_IVPU_BO_NOSNOOP)
+               return false;
+
        return ivpu_bo_cache_mode(bo) == DRM_IVPU_BO_CACHED;
 }
 
index 34626d6..8bdb59a 100644 (file)
@@ -57,8 +57,7 @@
 
 #define ICB_0_1_IRQ_MASK ((((u64)ICB_1_IRQ_MASK) << 32) | ICB_0_IRQ_MASK)
 
-#define BUTTRESS_IRQ_MASK ((REG_FLD(VPU_40XX_BUTTRESS_INTERRUPT_STAT, FREQ_CHANGE)) | \
-                          (REG_FLD(VPU_40XX_BUTTRESS_INTERRUPT_STAT, ATS_ERR)) | \
+#define BUTTRESS_IRQ_MASK ((REG_FLD(VPU_40XX_BUTTRESS_INTERRUPT_STAT, ATS_ERR)) | \
                           (REG_FLD(VPU_40XX_BUTTRESS_INTERRUPT_STAT, CFI0_ERR)) | \
                           (REG_FLD(VPU_40XX_BUTTRESS_INTERRUPT_STAT, CFI1_ERR)) | \
                           (REG_FLD(VPU_40XX_BUTTRESS_INTERRUPT_STAT, IMR0_ERR)) | \
@@ -196,6 +195,14 @@ static int ivpu_pll_wait_for_status_ready(struct ivpu_device *vdev)
        return REGB_POLL_FLD(VPU_40XX_BUTTRESS_VPU_STATUS, READY, 1, PLL_TIMEOUT_US);
 }
 
+static int ivpu_wait_for_clock_own_resource_ack(struct ivpu_device *vdev)
+{
+       if (ivpu_is_simics(vdev))
+               return 0;
+
+       return REGB_POLL_FLD(VPU_40XX_BUTTRESS_VPU_STATUS, CLOCK_RESOURCE_OWN_ACK, 1, TIMEOUT_US);
+}
+
 static void ivpu_pll_init_frequency_ratios(struct ivpu_device *vdev)
 {
        struct ivpu_hw_info *hw = vdev->hw;
@@ -556,6 +563,12 @@ static int ivpu_boot_pwr_domain_enable(struct ivpu_device *vdev)
 {
        int ret;
 
+       ret = ivpu_wait_for_clock_own_resource_ack(vdev);
+       if (ret) {
+               ivpu_err(vdev, "Timed out waiting for clock own resource ACK\n");
+               return ret;
+       }
+
        ivpu_boot_pwr_island_trickle_drive(vdev, true);
        ivpu_boot_pwr_island_drive(vdev, true);
 
@@ -1046,8 +1059,6 @@ static irqreturn_t ivpu_hw_40xx_irqb_handler(struct ivpu_device *vdev, int irq)
        if (status == 0)
                return IRQ_NONE;
 
-       REGB_WR32(VPU_40XX_BUTTRESS_INTERRUPT_STAT, status);
-
        if (REG_TEST_FLD(VPU_40XX_BUTTRESS_INTERRUPT_STAT, FREQ_CHANGE, status))
                ivpu_dbg(vdev, IRQ, "FREQ_CHANGE");
 
@@ -1092,6 +1103,9 @@ static irqreturn_t ivpu_hw_40xx_irqb_handler(struct ivpu_device *vdev, int irq)
                schedule_recovery = true;
        }
 
+       /* This must be done after interrupts are cleared at the source. */
+       REGB_WR32(VPU_40XX_BUTTRESS_INTERRUPT_STAT, status);
+
        if (schedule_recovery)
                ivpu_pm_schedule_recovery(vdev);
 
@@ -1103,9 +1117,14 @@ static irqreturn_t ivpu_hw_40xx_irq_handler(int irq, void *ptr)
        struct ivpu_device *vdev = ptr;
        irqreturn_t ret = IRQ_NONE;
 
+       REGB_WR32(VPU_40XX_BUTTRESS_GLOBAL_INT_MASK, 0x1);
+
        ret |= ivpu_hw_40xx_irqv_handler(vdev, irq);
        ret |= ivpu_hw_40xx_irqb_handler(vdev, irq);
 
+       /* Re-enable global interrupts to re-trigger MSI for pending interrupts */
+       REGB_WR32(VPU_40XX_BUTTRESS_GLOBAL_INT_MASK, 0x0);
+
        if (ret & IRQ_WAKE_THREAD)
                return IRQ_WAKE_THREAD;
 
index 5139cfe..ff4a5d4 100644 (file)
@@ -70,6 +70,8 @@
 #define VPU_40XX_BUTTRESS_VPU_STATUS_READY_MASK                                BIT_MASK(0)
 #define VPU_40XX_BUTTRESS_VPU_STATUS_IDLE_MASK                         BIT_MASK(1)
 #define VPU_40XX_BUTTRESS_VPU_STATUS_DUP_IDLE_MASK                     BIT_MASK(2)
+#define VPU_40XX_BUTTRESS_VPU_STATUS_CLOCK_RESOURCE_OWN_ACK_MASK       BIT_MASK(6)
+#define VPU_40XX_BUTTRESS_VPU_STATUS_POWER_RESOURCE_OWN_ACK_MASK       BIT_MASK(7)
 #define VPU_40XX_BUTTRESS_VPU_STATUS_PERF_CLK_MASK                     BIT_MASK(11)
 #define VPU_40XX_BUTTRESS_VPU_STATUS_DISABLE_CLK_RELINQUISH_MASK        BIT_MASK(12)
 
index fa0af59..295c0d7 100644 (file)
@@ -209,10 +209,10 @@ int ivpu_ipc_receive(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons,
        struct ivpu_ipc_rx_msg *rx_msg;
        int wait_ret, ret = 0;
 
-       wait_ret = wait_event_interruptible_timeout(cons->rx_msg_wq,
-                                                   (IS_KTHREAD() && kthread_should_stop()) ||
-                                                   !list_empty(&cons->rx_msg_list),
-                                                   msecs_to_jiffies(timeout_ms));
+       wait_ret = wait_event_timeout(cons->rx_msg_wq,
+                                     (IS_KTHREAD() && kthread_should_stop()) ||
+                                     !list_empty(&cons->rx_msg_list),
+                                     msecs_to_jiffies(timeout_ms));
 
        if (IS_KTHREAD() && kthread_should_stop())
                return -EINTR;
@@ -220,9 +220,6 @@ int ivpu_ipc_receive(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons,
        if (wait_ret == 0)
                return -ETIMEDOUT;
 
-       if (wait_ret < 0)
-               return -ERESTARTSYS;
-
        spin_lock_irq(&cons->rx_msg_lock);
        rx_msg = list_first_entry_or_null(&cons->rx_msg_list, struct ivpu_ipc_rx_msg, link);
        if (!rx_msg) {
index 948e31f..b411948 100644 (file)
@@ -2057,7 +2057,9 @@ static int acpi_video_bus_add(struct acpi_device *device)
            !auto_detect)
                acpi_video_bus_register_backlight(video);
 
-       acpi_video_bus_add_notify_handler(video);
+       error = acpi_video_bus_add_notify_handler(video);
+       if (error)
+               goto err_del;
 
        error = acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY,
                                                acpi_video_bus_notify);
@@ -2067,10 +2069,11 @@ static int acpi_video_bus_add(struct acpi_device *device)
        return 0;
 
 err_remove:
+       acpi_video_bus_remove_notify_handler(video);
+err_del:
        mutex_lock(&video_list_lock);
        list_del(&video->entry);
        mutex_unlock(&video_list_lock);
-       acpi_video_bus_remove_notify_handler(video);
        acpi_video_bus_unregister_backlight(video);
 err_put_video:
        acpi_video_bus_put_devices(video);
index f0e6738..f96bf32 100644 (file)
@@ -855,7 +855,7 @@ static size_t sizeof_idt(struct acpi_nfit_interleave *idt)
 {
        if (idt->header.length < sizeof(*idt))
                return 0;
-       return sizeof(*idt) + sizeof(u32) * (idt->line_count - 1);
+       return sizeof(*idt) + sizeof(u32) * idt->line_count;
 }
 
 static bool add_idt(struct acpi_nfit_desc *acpi_desc,
index dc615ef..3a34a8c 100644 (file)
@@ -1217,8 +1217,7 @@ static int acpi_processor_setup_lpi_states(struct acpi_processor *pr)
                strscpy(state->desc, lpi->desc, CPUIDLE_DESC_LEN);
                state->exit_latency = lpi->wake_latency;
                state->target_residency = lpi->min_residency;
-               if (lpi->arch_flags)
-                       state->flags |= CPUIDLE_FLAG_TIMER_STOP;
+               state->flags |= arch_get_idle_state_flags(lpi->arch_flags);
                if (i != 0 && lpi->entry_method == ACPI_CSTATE_FFH)
                        state->flags |= CPUIDLE_FLAG_RCU_IDLE;
                state->enter = acpi_idle_lpi_enter;
index 1a8591e..994091b 100644 (file)
@@ -19,6 +19,7 @@ static void acpi_set_pdc_bits(u32 *buf)
 {
        buf[0] = ACPI_PDC_REVISION_ID;
        buf[1] = 1;
+       buf[2] = 0;
 
        /* Twiddle arch-specific bits needed for _PDC */
        arch_acpi_set_proc_cap_bits(&buf[2]);
index 0072e0f..d8cc1e2 100644 (file)
@@ -1973,6 +1973,96 @@ retry:
 }
 
 /**
+ *     ata_dev_power_set_standby - Set a device power mode to standby
+ *     @dev: target device
+ *
+ *     Issue a STANDBY IMMEDIATE command to set a device power mode to standby.
+ *     For an HDD device, this spins down the disks.
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep).
+ */
+void ata_dev_power_set_standby(struct ata_device *dev)
+{
+       unsigned long ap_flags = dev->link->ap->flags;
+       struct ata_taskfile tf;
+       unsigned int err_mask;
+
+       /* Issue STANDBY IMMEDIATE command only if supported by the device */
+       if (dev->class != ATA_DEV_ATA && dev->class != ATA_DEV_ZAC)
+               return;
+
+       /*
+        * Some odd clown BIOSes issue spindown on power off (ACPI S4 or S5)
+        * causing some drives to spin up and down again. For these, do nothing
+        * if we are being called on shutdown.
+        */
+       if ((ap_flags & ATA_FLAG_NO_POWEROFF_SPINDOWN) &&
+           system_state == SYSTEM_POWER_OFF)
+               return;
+
+       if ((ap_flags & ATA_FLAG_NO_HIBERNATE_SPINDOWN) &&
+           system_entering_hibernation())
+               return;
+
+       ata_tf_init(dev, &tf);
+       tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
+       tf.protocol = ATA_PROT_NODATA;
+       tf.command = ATA_CMD_STANDBYNOW1;
+
+       ata_dev_notice(dev, "Entering standby power mode\n");
+
+       err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
+       if (err_mask)
+               ata_dev_err(dev, "STANDBY IMMEDIATE failed (err_mask=0x%x)\n",
+                           err_mask);
+}
+
+/**
+ *     ata_dev_power_set_active -  Set a device power mode to active
+ *     @dev: target device
+ *
+ *     Issue a VERIFY command to enter to ensure that the device is in the
+ *     active power mode. For a spun-down HDD (standby or idle power mode),
+ *     the VERIFY command will complete after the disk spins up.
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep).
+ */
+void ata_dev_power_set_active(struct ata_device *dev)
+{
+       struct ata_taskfile tf;
+       unsigned int err_mask;
+
+       /*
+        * Issue READ VERIFY SECTORS command for 1 sector at lba=0 only
+        * if supported by the device.
+        */
+       if (dev->class != ATA_DEV_ATA && dev->class != ATA_DEV_ZAC)
+               return;
+
+       ata_tf_init(dev, &tf);
+       tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
+       tf.protocol = ATA_PROT_NODATA;
+       tf.command = ATA_CMD_VERIFY;
+       tf.nsect = 1;
+       if (dev->flags & ATA_DFLAG_LBA) {
+               tf.flags |= ATA_TFLAG_LBA;
+               tf.device |= ATA_LBA;
+       } else {
+               /* CHS */
+               tf.lbal = 0x1; /* sect */
+       }
+
+       ata_dev_notice(dev, "Entering active power mode\n");
+
+       err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
+       if (err_mask)
+               ata_dev_err(dev, "VERIFY failed (err_mask=0x%x)\n",
+                           err_mask);
+}
+
+/**
  *     ata_read_log_page - read a specific log page
  *     @dev: target device
  *     @log: log to read
@@ -2529,7 +2619,7 @@ static int ata_dev_config_lba(struct ata_device *dev)
 {
        const u16 *id = dev->id;
        const char *lba_desc;
-       char ncq_desc[24];
+       char ncq_desc[32];
        int ret;
 
        dev->flags |= ATA_DFLAG_LBA;
@@ -5037,17 +5127,19 @@ static void ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
        struct ata_link *link;
        unsigned long flags;
 
-       /* Previous resume operation might still be in
-        * progress.  Wait for PM_PENDING to clear.
+       spin_lock_irqsave(ap->lock, flags);
+
+       /*
+        * A previous PM operation might still be in progress. Wait for
+        * ATA_PFLAG_PM_PENDING to clear.
         */
        if (ap->pflags & ATA_PFLAG_PM_PENDING) {
+               spin_unlock_irqrestore(ap->lock, flags);
                ata_port_wait_eh(ap);
-               WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
+               spin_lock_irqsave(ap->lock, flags);
        }
 
-       /* request PM ops to EH */
-       spin_lock_irqsave(ap->lock, flags);
-
+       /* Request PM operation to EH */
        ap->pm_mesg = mesg;
        ap->pflags |= ATA_PFLAG_PM_PENDING;
        ata_for_each_link(link, ap, HOST_FIRST) {
@@ -5059,10 +5151,8 @@ static void ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
 
        spin_unlock_irqrestore(ap->lock, flags);
 
-       if (!async) {
+       if (!async)
                ata_port_wait_eh(ap);
-               WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
-       }
 }
 
 /*
@@ -5078,11 +5168,27 @@ static const unsigned int ata_port_suspend_ehi = ATA_EHI_QUIET
 
 static void ata_port_suspend(struct ata_port *ap, pm_message_t mesg)
 {
+       /*
+        * We are about to suspend the port, so we do not care about
+        * scsi_rescan_device() calls scheduled by previous resume operations.
+        * The next resume will schedule the rescan again. So cancel any rescan
+        * that is not done yet.
+        */
+       cancel_delayed_work_sync(&ap->scsi_rescan_task);
+
        ata_port_request_pm(ap, mesg, 0, ata_port_suspend_ehi, false);
 }
 
 static void ata_port_suspend_async(struct ata_port *ap, pm_message_t mesg)
 {
+       /*
+        * We are about to suspend the port, so we do not care about
+        * scsi_rescan_device() calls scheduled by previous resume operations.
+        * The next resume will schedule the rescan again. So cancel any rescan
+        * that is not done yet.
+        */
+       cancel_delayed_work_sync(&ap->scsi_rescan_task);
+
        ata_port_request_pm(ap, mesg, 0, ata_port_suspend_ehi, true);
 }
 
@@ -5229,7 +5335,7 @@ EXPORT_SYMBOL_GPL(ata_host_resume);
 #endif
 
 const struct device_type ata_port_type = {
-       .name = "ata_port",
+       .name = ATA_PORT_TYPE_NAME,
 #ifdef CONFIG_PM
        .pm = &ata_port_pm_ops,
 #endif
@@ -5948,11 +6054,30 @@ static void ata_port_detach(struct ata_port *ap)
        struct ata_link *link;
        struct ata_device *dev;
 
-       /* tell EH we're leaving & flush EH */
+       /* Wait for any ongoing EH */
+       ata_port_wait_eh(ap);
+
+       mutex_lock(&ap->scsi_scan_mutex);
        spin_lock_irqsave(ap->lock, flags);
+
+       /* Remove scsi devices */
+       ata_for_each_link(link, ap, HOST_FIRST) {
+               ata_for_each_dev(dev, link, ALL) {
+                       if (dev->sdev) {
+                               spin_unlock_irqrestore(ap->lock, flags);
+                               scsi_remove_device(dev->sdev);
+                               spin_lock_irqsave(ap->lock, flags);
+                               dev->sdev = NULL;
+                       }
+               }
+       }
+
+       /* Tell EH to disable all devices */
        ap->pflags |= ATA_PFLAG_UNLOADING;
        ata_port_schedule_eh(ap);
+
        spin_unlock_irqrestore(ap->lock, flags);
+       mutex_unlock(&ap->scsi_scan_mutex);
 
        /* wait till EH commits suicide */
        ata_port_wait_eh(ap);
index 4cf4f57..5686353 100644 (file)
@@ -147,6 +147,8 @@ ata_eh_cmd_timeout_table[ATA_EH_CMD_TIMEOUT_TABLE_SIZE] = {
          .timeouts = ata_eh_other_timeouts, },
        { .commands = CMDS(ATA_CMD_FLUSH, ATA_CMD_FLUSH_EXT),
          .timeouts = ata_eh_flush_timeouts },
+       { .commands = CMDS(ATA_CMD_VERIFY),
+         .timeouts = ata_eh_reset_timeouts },
 };
 #undef CMDS
 
@@ -498,7 +500,19 @@ static void ata_eh_unload(struct ata_port *ap)
        struct ata_device *dev;
        unsigned long flags;
 
-       /* Restore SControl IPM and SPD for the next driver and
+       /*
+        * Unless we are restarting, transition all enabled devices to
+        * standby power mode.
+        */
+       if (system_state != SYSTEM_RESTART) {
+               ata_for_each_link(link, ap, PMP_FIRST) {
+                       ata_for_each_dev(dev, link, ENABLED)
+                               ata_dev_power_set_standby(dev);
+               }
+       }
+
+       /*
+        * Restore SControl IPM and SPD for the next driver and
         * disable attached devices.
         */
        ata_for_each_link(link, ap, PMP_FIRST) {
@@ -684,6 +698,10 @@ void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap)
                        ehc->saved_xfer_mode[devno] = dev->xfer_mode;
                        if (ata_ncq_enabled(dev))
                                ehc->saved_ncq_enabled |= 1 << devno;
+
+                       /* If we are resuming, wake up the device */
+                       if (ap->pflags & ATA_PFLAG_RESUMING)
+                               ehc->i.dev_action[devno] |= ATA_EH_SET_ACTIVE;
                }
        }
 
@@ -743,6 +761,8 @@ void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap)
        /* clean up */
        spin_lock_irqsave(ap->lock, flags);
 
+       ap->pflags &= ~ATA_PFLAG_RESUMING;
+
        if (ap->pflags & ATA_PFLAG_LOADING)
                ap->pflags &= ~ATA_PFLAG_LOADING;
        else if ((ap->pflags & ATA_PFLAG_SCSI_HOTPLUG) &&
@@ -1218,6 +1238,13 @@ void ata_eh_detach_dev(struct ata_device *dev)
        struct ata_eh_context *ehc = &link->eh_context;
        unsigned long flags;
 
+       /*
+        * If the device is still enabled, transition it to standby power mode
+        * (i.e. spin down HDDs).
+        */
+       if (ata_dev_enabled(dev))
+               ata_dev_power_set_standby(dev);
+
        ata_dev_disable(dev);
 
        spin_lock_irqsave(ap->lock, flags);
@@ -2305,7 +2332,7 @@ static void ata_eh_link_report(struct ata_link *link)
        struct ata_eh_context *ehc = &link->eh_context;
        struct ata_queued_cmd *qc;
        const char *frozen, *desc;
-       char tries_buf[6] = "";
+       char tries_buf[16] = "";
        int tag, nr_failed = 0;
 
        if (ehc->i.flags & ATA_EHI_QUIET)
@@ -3016,6 +3043,15 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link,
                if (ehc->i.flags & ATA_EHI_DID_RESET)
                        readid_flags |= ATA_READID_POSTRESET;
 
+               /*
+                * When resuming, before executing any command, make sure to
+                * transition the device to the active power mode.
+                */
+               if ((action & ATA_EH_SET_ACTIVE) && ata_dev_enabled(dev)) {
+                       ata_dev_power_set_active(dev);
+                       ata_eh_done(link, dev, ATA_EH_SET_ACTIVE);
+               }
+
                if ((action & ATA_EH_REVALIDATE) && ata_dev_enabled(dev)) {
                        WARN_ON(dev->class == ATA_DEV_PMP);
 
@@ -3989,6 +4025,7 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap)
        unsigned long flags;
        int rc = 0;
        struct ata_device *dev;
+       struct ata_link *link;
 
        /* are we suspending? */
        spin_lock_irqsave(ap->lock, flags);
@@ -4001,6 +4038,12 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap)
 
        WARN_ON(ap->pflags & ATA_PFLAG_SUSPENDED);
 
+       /* Set all devices attached to the port in standby mode */
+       ata_for_each_link(link, ap, HOST_FIRST) {
+               ata_for_each_dev(dev, link, ENABLED)
+                       ata_dev_power_set_standby(dev);
+       }
+
        /*
         * If we have a ZPODD attached, check its zero
         * power ready status before the port is frozen.
@@ -4083,6 +4126,7 @@ static void ata_eh_handle_port_resume(struct ata_port *ap)
        /* update the flags */
        spin_lock_irqsave(ap->lock, flags);
        ap->pflags &= ~(ATA_PFLAG_PM_PENDING | ATA_PFLAG_SUSPENDED);
+       ap->pflags |= ATA_PFLAG_RESUMING;
        spin_unlock_irqrestore(ap->lock, flags);
 }
 #endif /* CONFIG_PM */
index d3f28b8..a371b49 100644 (file)
@@ -1050,14 +1050,13 @@ int ata_scsi_dev_config(struct scsi_device *sdev, struct ata_device *dev)
                }
        } else {
                sdev->sector_size = ata_id_logical_sector_size(dev->id);
+
                /*
-                * Stop the drive on suspend but do not issue START STOP UNIT
-                * on resume as this is not necessary and may fail: the device
-                * will be woken up by ata_port_pm_resume() with a port reset
-                * and device revalidation.
+                * Ask the sd driver to issue START STOP UNIT on runtime suspend
+                * and resume only. For system level suspend/resume, devices
+                * power state is handled directly by libata EH.
                 */
-               sdev->manage_start_stop = 1;
-               sdev->no_start_on_resume = 1;
+               sdev->manage_runtime_start_stop = true;
        }
 
        /*
@@ -1090,6 +1089,42 @@ int ata_scsi_dev_config(struct scsi_device *sdev, struct ata_device *dev)
 }
 
 /**
+ *     ata_scsi_slave_alloc - Early setup of SCSI device
+ *     @sdev: SCSI device to examine
+ *
+ *     This is called from scsi_alloc_sdev() when the scsi device
+ *     associated with an ATA device is scanned on a port.
+ *
+ *     LOCKING:
+ *     Defined by SCSI layer.  We don't really care.
+ */
+
+int ata_scsi_slave_alloc(struct scsi_device *sdev)
+{
+       struct ata_port *ap = ata_shost_to_port(sdev->host);
+       struct device_link *link;
+
+       ata_scsi_sdev_config(sdev);
+
+       /*
+        * Create a link from the ata_port device to the scsi device to ensure
+        * that PM does suspend/resume in the correct order: the scsi device is
+        * consumer (child) and the ata port the supplier (parent).
+        */
+       link = device_link_add(&sdev->sdev_gendev, &ap->tdev,
+                              DL_FLAG_STATELESS |
+                              DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE);
+       if (!link) {
+               ata_port_err(ap, "Failed to create link to scsi device %s\n",
+                            dev_name(&sdev->sdev_gendev));
+               return -ENODEV;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ata_scsi_slave_alloc);
+
+/**
  *     ata_scsi_slave_config - Set SCSI device attributes
  *     @sdev: SCSI device to examine
  *
@@ -1105,14 +1140,11 @@ int ata_scsi_slave_config(struct scsi_device *sdev)
 {
        struct ata_port *ap = ata_shost_to_port(sdev->host);
        struct ata_device *dev = __ata_scsi_find_dev(ap, sdev);
-       int rc = 0;
-
-       ata_scsi_sdev_config(sdev);
 
        if (dev)
-               rc = ata_scsi_dev_config(sdev, dev);
+               return ata_scsi_dev_config(sdev, dev);
 
-       return rc;
+       return 0;
 }
 EXPORT_SYMBOL_GPL(ata_scsi_slave_config);
 
@@ -1136,6 +1168,8 @@ void ata_scsi_slave_destroy(struct scsi_device *sdev)
        unsigned long flags;
        struct ata_device *dev;
 
+       device_link_remove(&sdev->sdev_gendev, &ap->tdev);
+
        spin_lock_irqsave(ap->lock, flags);
        dev = __ata_scsi_find_dev(ap, sdev);
        if (dev && dev->sdev) {
@@ -1195,7 +1229,7 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc)
        }
 
        if (cdb[4] & 0x1) {
-               tf->nsect = 1;  /* 1 sector, lba=0 */
+               tf->nsect = 1;  /* 1 sector, lba=0 */
 
                if (qc->dev->flags & ATA_DFLAG_LBA) {
                        tf->flags |= ATA_TFLAG_LBA;
@@ -1211,7 +1245,7 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc)
                        tf->lbah = 0x0; /* cyl high */
                }
 
-               tf->command = ATA_CMD_VERIFY;   /* READ VERIFY */
+               tf->command = ATA_CMD_VERIFY;   /* READ VERIFY */
        } else {
                /* Some odd clown BIOSen issue spindown on power off (ACPI S4
                 * or S5) causing some drives to spin up and down again.
@@ -1221,7 +1255,7 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc)
                        goto skip;
 
                if ((qc->ap->flags & ATA_FLAG_NO_HIBERNATE_SPINDOWN) &&
-                    system_entering_hibernation())
+                   system_entering_hibernation())
                        goto skip;
 
                /* Issue ATA STANDBY IMMEDIATE command */
@@ -1835,6 +1869,9 @@ static unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf)
                hdr[2] = 0x7; /* claim SPC-5 version compatibility */
        }
 
+       if (args->dev->flags & ATA_DFLAG_CDL)
+               hdr[2] = 0xd; /* claim SPC-6 version compatibility */
+
        memcpy(rbuf, hdr, sizeof(hdr));
        memcpy(&rbuf[8], "ATA     ", 8);
        ata_id_string(args->id, &rbuf[16], ATA_ID_PROD, 16);
@@ -4312,7 +4349,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd)
                break;
 
        case MAINTENANCE_IN:
-               if (scsicmd[1] == MI_REPORT_SUPPORTED_OPERATION_CODES)
+               if ((scsicmd[1] & 0x1f) == MI_REPORT_SUPPORTED_OPERATION_CODES)
                        ata_scsi_rbuf_fill(&args, ata_scsiop_maint_in);
                else
                        ata_scsi_set_invalid_field(dev, cmd, 1, 0xff);
@@ -4722,7 +4759,7 @@ void ata_scsi_dev_rescan(struct work_struct *work)
        struct ata_link *link;
        struct ata_device *dev;
        unsigned long flags;
-       bool delay_rescan = false;
+       int ret = 0;
 
        mutex_lock(&ap->scsi_scan_mutex);
        spin_lock_irqsave(ap->lock, flags);
@@ -4731,37 +4768,34 @@ void ata_scsi_dev_rescan(struct work_struct *work)
                ata_for_each_dev(dev, link, ENABLED) {
                        struct scsi_device *sdev = dev->sdev;
 
+                       /*
+                        * If the port was suspended before this was scheduled,
+                        * bail out.
+                        */
+                       if (ap->pflags & ATA_PFLAG_SUSPENDED)
+                               goto unlock;
+
                        if (!sdev)
                                continue;
                        if (scsi_device_get(sdev))
                                continue;
 
-                       /*
-                        * If the rescan work was scheduled because of a resume
-                        * event, the port is already fully resumed, but the
-                        * SCSI device may not yet be fully resumed. In such
-                        * case, executing scsi_rescan_device() may cause a
-                        * deadlock with the PM code on device_lock(). Prevent
-                        * this by giving up and retrying rescan after a short
-                        * delay.
-                        */
-                       delay_rescan = sdev->sdev_gendev.power.is_suspended;
-                       if (delay_rescan) {
-                               scsi_device_put(sdev);
-                               break;
-                       }
-
                        spin_unlock_irqrestore(ap->lock, flags);
-                       scsi_rescan_device(sdev);
+                       ret = scsi_rescan_device(sdev);
                        scsi_device_put(sdev);
                        spin_lock_irqsave(ap->lock, flags);
+
+                       if (ret)
+                               goto unlock;
                }
        }
 
+unlock:
        spin_unlock_irqrestore(ap->lock, flags);
        mutex_unlock(&ap->scsi_scan_mutex);
 
-       if (delay_rescan)
+       /* Reschedule with a delay if scsi_rescan_device() returned an error */
+       if (ret)
                schedule_delayed_work(&ap->scsi_rescan_task,
                                      msecs_to_jiffies(5));
 }
index e4fb9d1..3e49a87 100644 (file)
@@ -266,6 +266,10 @@ void ata_tport_delete(struct ata_port *ap)
        put_device(dev);
 }
 
+static const struct device_type ata_port_sas_type = {
+       .name = ATA_PORT_TYPE_NAME,
+};
+
 /** ata_tport_add - initialize a transport ATA port structure
  *
  * @parent:    parent device
@@ -283,7 +287,10 @@ int ata_tport_add(struct device *parent,
        struct device *dev = &ap->tdev;
 
        device_initialize(dev);
-       dev->type = &ata_port_type;
+       if (ap->flags & ATA_FLAG_SAS_HOST)
+               dev->type = &ata_port_sas_type;
+       else
+               dev->type = &ata_port_type;
 
        dev->parent = parent;
        ata_host_get(ap->host);
index 6e7d352..05ac80d 100644 (file)
@@ -30,6 +30,8 @@ enum {
        ATA_DNXFER_QUIET        = (1 << 31),
 };
 
+#define ATA_PORT_TYPE_NAME     "ata_port"
+
 extern atomic_t ata_print_id;
 extern int atapi_passthru16;
 extern int libata_fua;
@@ -60,6 +62,8 @@ extern int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags);
 extern int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class,
                              unsigned int readid_flags);
 extern int ata_dev_configure(struct ata_device *dev);
+extern void ata_dev_power_set_standby(struct ata_device *dev);
+extern void ata_dev_power_set_active(struct ata_device *dev);
 extern int sata_down_spd_limit(struct ata_link *link, u32 spd_limit);
 extern int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel);
 extern unsigned int ata_dev_set_feature(struct ata_device *dev,
index bad7aa9..d2b81cf 100644 (file)
@@ -9,11 +9,6 @@
  *
  * The TD-2000 and certain older devices use a different protocol.
  * Try the fit2 protocol module with them.
- *
- * NB:  The FIT adapters do not appear to support the control
- * registers.  So, we map ALT_STATUS to STATUS and NO-OP writes
- * to the device control register - this means that IDE reset
- * will not work on these devices.
  */
 
 #include <linux/module.h>
@@ -37,8 +32,7 @@
 
 static void fit3_write_regr(struct pi_adapter *pi, int cont, int regr, int val)
 {
-       if (cont == 1)
-               return;
+       regr += cont << 3;
 
        switch (pi->mode) {
        case 0:
@@ -59,11 +53,7 @@ static int fit3_read_regr(struct pi_adapter *pi, int cont, int regr)
 {
        int  a, b;
 
-       if (cont) {
-               if (regr != 6)
-                       return 0xff;
-               regr = 7;
-       }
+       regr += cont << 3;
 
        switch (pi->mode) {
        case 0:
index 1af64d4..a7adfdc 100644 (file)
@@ -51,6 +51,13 @@ static void pata_parport_dev_select(struct ata_port *ap, unsigned int device)
        ata_sff_pause(ap);
 }
 
+static void pata_parport_set_devctl(struct ata_port *ap, u8 ctl)
+{
+       struct pi_adapter *pi = ap->host->private_data;
+
+       pi->proto->write_regr(pi, 1, 6, ctl);
+}
+
 static bool pata_parport_devchk(struct ata_port *ap, unsigned int device)
 {
        struct pi_adapter *pi = ap->host->private_data;
@@ -64,7 +71,7 @@ static bool pata_parport_devchk(struct ata_port *ap, unsigned int device)
        pi->proto->write_regr(pi, 0, ATA_REG_NSECT, 0xaa);
        pi->proto->write_regr(pi, 0, ATA_REG_LBAL, 0x55);
 
-       pi->proto->write_regr(pi, 0, ATA_REG_NSECT, 055);
+       pi->proto->write_regr(pi, 0, ATA_REG_NSECT, 0x55);
        pi->proto->write_regr(pi, 0, ATA_REG_LBAL, 0xaa);
 
        nsect = pi->proto->read_regr(pi, 0, ATA_REG_NSECT);
@@ -73,6 +80,72 @@ static bool pata_parport_devchk(struct ata_port *ap, unsigned int device)
        return (nsect == 0x55) && (lbal == 0xaa);
 }
 
+static int pata_parport_wait_after_reset(struct ata_link *link,
+                                        unsigned int devmask,
+                                        unsigned long deadline)
+{
+       struct ata_port *ap = link->ap;
+       struct pi_adapter *pi = ap->host->private_data;
+       unsigned int dev0 = devmask & (1 << 0);
+       unsigned int dev1 = devmask & (1 << 1);
+       int rc, ret = 0;
+
+       ata_msleep(ap, ATA_WAIT_AFTER_RESET);
+
+       /* always check readiness of the master device */
+       rc = ata_sff_wait_ready(link, deadline);
+       if (rc) {
+               /*
+                * some adapters return bogus values if master device is not
+                * present, so don't abort now if a slave device is present
+                */
+               if (!dev1)
+                       return rc;
+               ret = -ENODEV;
+       }
+
+       /*
+        * if device 1 was found in ata_devchk, wait for register
+        * access briefly, then wait for BSY to clear.
+        */
+       if (dev1) {
+               int i;
+
+               pata_parport_dev_select(ap, 1);
+
+               /*
+                * Wait for register access.  Some ATAPI devices fail
+                * to set nsect/lbal after reset, so don't waste too
+                * much time on it.  We're gonna wait for !BSY anyway.
+                */
+               for (i = 0; i < 2; i++) {
+                       u8 nsect, lbal;
+
+                       nsect = pi->proto->read_regr(pi, 0, ATA_REG_NSECT);
+                       lbal = pi->proto->read_regr(pi, 0, ATA_REG_LBAL);
+                       if (nsect == 1 && lbal == 1)
+                               break;
+                       /* give drive a breather */
+                       ata_msleep(ap, 50);
+               }
+
+               rc = ata_sff_wait_ready(link, deadline);
+               if (rc) {
+                       if (rc != -ENODEV)
+                               return rc;
+                       ret = rc;
+               }
+       }
+
+       pata_parport_dev_select(ap, 0);
+       if (dev1)
+               pata_parport_dev_select(ap, 1);
+       if (dev0)
+               pata_parport_dev_select(ap, 0);
+
+       return ret;
+}
+
 static int pata_parport_bus_softreset(struct ata_port *ap, unsigned int devmask,
                                      unsigned long deadline)
 {
@@ -87,7 +160,7 @@ static int pata_parport_bus_softreset(struct ata_port *ap, unsigned int devmask,
        ap->last_ctl = ap->ctl;
 
        /* wait the port to become ready */
-       return ata_sff_wait_after_reset(&ap->link, devmask, deadline);
+       return pata_parport_wait_after_reset(&ap->link, devmask, deadline);
 }
 
 static int pata_parport_softreset(struct ata_link *link, unsigned int *classes,
@@ -252,6 +325,7 @@ static struct ata_port_operations pata_parport_port_ops = {
        .hardreset              = NULL,
 
        .sff_dev_select         = pata_parport_dev_select,
+       .sff_set_devctl         = pata_parport_set_devctl,
        .sff_check_status       = pata_parport_check_status,
        .sff_check_altstatus    = pata_parport_check_altstatus,
        .sff_tf_load            = pata_parport_tf_load,
index db716ff..3db88bb 100644 (file)
@@ -453,7 +453,8 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
                if (!rbnode)
                        return -ENOMEM;
                regcache_rbtree_set_register(map, rbnode,
-                                            reg - rbnode->base_reg, value);
+                                            (reg - rbnode->base_reg) / map->reg_stride,
+                                            value);
                regcache_rbtree_insert(map, &rbtree_ctx->root, rbnode);
                rbtree_ctx->cached_rbnode = rbnode;
        }
index df1cd0f..800f131 100644 (file)
@@ -1436,8 +1436,9 @@ static int nbd_start_device_ioctl(struct nbd_device *nbd)
 
 static void nbd_clear_sock_ioctl(struct nbd_device *nbd)
 {
-       blk_mark_disk_dead(nbd->disk);
        nbd_clear_sock(nbd);
+       disk_force_media_change(nbd->disk);
+       nbd_bdev_reset(nbd);
        if (test_and_clear_bit(NBD_RT_HAS_CONFIG_REF,
                               &nbd->config->runtime_flags))
                nbd_config_put(nbd);
index 3de11f0..a999b69 100644 (file)
@@ -632,9 +632,8 @@ void rbd_warn(struct rbd_device *rbd_dev, const char *fmt, ...)
 static void rbd_dev_remove_parent(struct rbd_device *rbd_dev);
 
 static int rbd_dev_refresh(struct rbd_device *rbd_dev);
-static int rbd_dev_v2_header_onetime(struct rbd_device *rbd_dev);
-static int rbd_dev_header_info(struct rbd_device *rbd_dev);
-static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev);
+static int rbd_dev_v2_header_onetime(struct rbd_device *rbd_dev,
+                                    struct rbd_image_header *header);
 static const char *rbd_dev_v2_snap_name(struct rbd_device *rbd_dev,
                                        u64 snap_id);
 static int _rbd_dev_v2_snap_size(struct rbd_device *rbd_dev, u64 snap_id,
@@ -995,15 +994,24 @@ static void rbd_init_layout(struct rbd_device *rbd_dev)
        RCU_INIT_POINTER(rbd_dev->layout.pool_ns, NULL);
 }
 
+static void rbd_image_header_cleanup(struct rbd_image_header *header)
+{
+       kfree(header->object_prefix);
+       ceph_put_snap_context(header->snapc);
+       kfree(header->snap_sizes);
+       kfree(header->snap_names);
+
+       memset(header, 0, sizeof(*header));
+}
+
 /*
  * Fill an rbd image header with information from the given format 1
  * on-disk header.
  */
-static int rbd_header_from_disk(struct rbd_device *rbd_dev,
-                                struct rbd_image_header_ondisk *ondisk)
+static int rbd_header_from_disk(struct rbd_image_header *header,
+                               struct rbd_image_header_ondisk *ondisk,
+                               bool first_time)
 {
-       struct rbd_image_header *header = &rbd_dev->header;
-       bool first_time = header->object_prefix == NULL;
        struct ceph_snap_context *snapc;
        char *object_prefix = NULL;
        char *snap_names = NULL;
@@ -1070,11 +1078,6 @@ static int rbd_header_from_disk(struct rbd_device *rbd_dev,
        if (first_time) {
                header->object_prefix = object_prefix;
                header->obj_order = ondisk->options.order;
-               rbd_init_layout(rbd_dev);
-       } else {
-               ceph_put_snap_context(header->snapc);
-               kfree(header->snap_names);
-               kfree(header->snap_sizes);
        }
 
        /* The remaining fields always get updated (when we refresh) */
@@ -4859,7 +4862,9 @@ out_req:
  * return, the rbd_dev->header field will contain up-to-date
  * information about the image.
  */
-static int rbd_dev_v1_header_info(struct rbd_device *rbd_dev)
+static int rbd_dev_v1_header_info(struct rbd_device *rbd_dev,
+                                 struct rbd_image_header *header,
+                                 bool first_time)
 {
        struct rbd_image_header_ondisk *ondisk = NULL;
        u32 snap_count = 0;
@@ -4907,7 +4912,7 @@ static int rbd_dev_v1_header_info(struct rbd_device *rbd_dev)
                snap_count = le32_to_cpu(ondisk->snap_count);
        } while (snap_count != want_count);
 
-       ret = rbd_header_from_disk(rbd_dev, ondisk);
+       ret = rbd_header_from_disk(header, ondisk, first_time);
 out:
        kfree(ondisk);
 
@@ -4931,39 +4936,6 @@ static void rbd_dev_update_size(struct rbd_device *rbd_dev)
        }
 }
 
-static int rbd_dev_refresh(struct rbd_device *rbd_dev)
-{
-       u64 mapping_size;
-       int ret;
-
-       down_write(&rbd_dev->header_rwsem);
-       mapping_size = rbd_dev->mapping.size;
-
-       ret = rbd_dev_header_info(rbd_dev);
-       if (ret)
-               goto out;
-
-       /*
-        * If there is a parent, see if it has disappeared due to the
-        * mapped image getting flattened.
-        */
-       if (rbd_dev->parent) {
-               ret = rbd_dev_v2_parent_info(rbd_dev);
-               if (ret)
-                       goto out;
-       }
-
-       rbd_assert(!rbd_is_snap(rbd_dev));
-       rbd_dev->mapping.size = rbd_dev->header.image_size;
-
-out:
-       up_write(&rbd_dev->header_rwsem);
-       if (!ret && mapping_size != rbd_dev->mapping.size)
-               rbd_dev_update_size(rbd_dev);
-
-       return ret;
-}
-
 static const struct blk_mq_ops rbd_mq_ops = {
        .queue_rq       = rbd_queue_rq,
 };
@@ -5503,17 +5475,12 @@ static int _rbd_dev_v2_snap_size(struct rbd_device *rbd_dev, u64 snap_id,
        return 0;
 }
 
-static int rbd_dev_v2_image_size(struct rbd_device *rbd_dev)
-{
-       return _rbd_dev_v2_snap_size(rbd_dev, CEPH_NOSNAP,
-                                       &rbd_dev->header.obj_order,
-                                       &rbd_dev->header.image_size);
-}
-
-static int rbd_dev_v2_object_prefix(struct rbd_device *rbd_dev)
+static int rbd_dev_v2_object_prefix(struct rbd_device *rbd_dev,
+                                   char **pobject_prefix)
 {
        size_t size;
        void *reply_buf;
+       char *object_prefix;
        int ret;
        void *p;
 
@@ -5531,16 +5498,16 @@ static int rbd_dev_v2_object_prefix(struct rbd_device *rbd_dev)
                goto out;
 
        p = reply_buf;
-       rbd_dev->header.object_prefix = ceph_extract_encoded_string(&p,
-                                               p + ret, NULL, GFP_NOIO);
+       object_prefix = ceph_extract_encoded_string(&p, p + ret, NULL,
+                                                   GFP_NOIO);
+       if (IS_ERR(object_prefix)) {
+               ret = PTR_ERR(object_prefix);
+               goto out;
+       }
        ret = 0;
 
-       if (IS_ERR(rbd_dev->header.object_prefix)) {
-               ret = PTR_ERR(rbd_dev->header.object_prefix);
-               rbd_dev->header.object_prefix = NULL;
-       } else {
-               dout("  object_prefix = %s\n", rbd_dev->header.object_prefix);
-       }
+       *pobject_prefix = object_prefix;
+       dout("  object_prefix = %s\n", object_prefix);
 out:
        kfree(reply_buf);
 
@@ -5591,13 +5558,6 @@ static int _rbd_dev_v2_snap_features(struct rbd_device *rbd_dev, u64 snap_id,
        return 0;
 }
 
-static int rbd_dev_v2_features(struct rbd_device *rbd_dev)
-{
-       return _rbd_dev_v2_snap_features(rbd_dev, CEPH_NOSNAP,
-                                        rbd_is_ro(rbd_dev),
-                                        &rbd_dev->header.features);
-}
-
 /*
  * These are generic image flags, but since they are used only for
  * object map, store them in rbd_dev->object_map_flags.
@@ -5634,6 +5594,14 @@ struct parent_image_info {
        u64             overlap;
 };
 
+static void rbd_parent_info_cleanup(struct parent_image_info *pii)
+{
+       kfree(pii->pool_ns);
+       kfree(pii->image_id);
+
+       memset(pii, 0, sizeof(*pii));
+}
+
 /*
  * The caller is responsible for @pii.
  */
@@ -5703,6 +5671,9 @@ static int __get_parent_info(struct rbd_device *rbd_dev,
        if (pii->has_overlap)
                ceph_decode_64_safe(&p, end, pii->overlap, e_inval);
 
+       dout("%s pool_id %llu pool_ns %s image_id %s snap_id %llu has_overlap %d overlap %llu\n",
+            __func__, pii->pool_id, pii->pool_ns, pii->image_id, pii->snap_id,
+            pii->has_overlap, pii->overlap);
        return 0;
 
 e_inval:
@@ -5741,14 +5712,17 @@ static int __get_parent_info_legacy(struct rbd_device *rbd_dev,
        pii->has_overlap = true;
        ceph_decode_64_safe(&p, end, pii->overlap, e_inval);
 
+       dout("%s pool_id %llu pool_ns %s image_id %s snap_id %llu has_overlap %d overlap %llu\n",
+            __func__, pii->pool_id, pii->pool_ns, pii->image_id, pii->snap_id,
+            pii->has_overlap, pii->overlap);
        return 0;
 
 e_inval:
        return -EINVAL;
 }
 
-static int get_parent_info(struct rbd_device *rbd_dev,
-                          struct parent_image_info *pii)
+static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev,
+                                 struct parent_image_info *pii)
 {
        struct page *req_page, *reply_page;
        void *p;
@@ -5776,7 +5750,7 @@ static int get_parent_info(struct rbd_device *rbd_dev,
        return ret;
 }
 
-static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
+static int rbd_dev_setup_parent(struct rbd_device *rbd_dev)
 {
        struct rbd_spec *parent_spec;
        struct parent_image_info pii = { 0 };
@@ -5786,37 +5760,12 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
        if (!parent_spec)
                return -ENOMEM;
 
-       ret = get_parent_info(rbd_dev, &pii);
+       ret = rbd_dev_v2_parent_info(rbd_dev, &pii);
        if (ret)
                goto out_err;
 
-       dout("%s pool_id %llu pool_ns %s image_id %s snap_id %llu has_overlap %d overlap %llu\n",
-            __func__, pii.pool_id, pii.pool_ns, pii.image_id, pii.snap_id,
-            pii.has_overlap, pii.overlap);
-
-       if (pii.pool_id == CEPH_NOPOOL || !pii.has_overlap) {
-               /*
-                * Either the parent never existed, or we have
-                * record of it but the image got flattened so it no
-                * longer has a parent.  When the parent of a
-                * layered image disappears we immediately set the
-                * overlap to 0.  The effect of this is that all new
-                * requests will be treated as if the image had no
-                * parent.
-                *
-                * If !pii.has_overlap, the parent image spec is not
-                * applicable.  It's there to avoid duplication in each
-                * snapshot record.
-                */
-               if (rbd_dev->parent_overlap) {
-                       rbd_dev->parent_overlap = 0;
-                       rbd_dev_parent_put(rbd_dev);
-                       pr_info("%s: clone image has been flattened\n",
-                               rbd_dev->disk->disk_name);
-               }
-
+       if (pii.pool_id == CEPH_NOPOOL || !pii.has_overlap)
                goto out;       /* No parent?  No problem. */
-       }
 
        /* The ceph file layout needs to fit pool id in 32 bits */
 
@@ -5828,58 +5777,46 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
        }
 
        /*
-        * The parent won't change (except when the clone is
-        * flattened, already handled that).  So we only need to
-        * record the parent spec we have not already done so.
+        * The parent won't change except when the clone is flattened,
+        * so we only need to record the parent image spec once.
         */
-       if (!rbd_dev->parent_spec) {
-               parent_spec->pool_id = pii.pool_id;
-               if (pii.pool_ns && *pii.pool_ns) {
-                       parent_spec->pool_ns = pii.pool_ns;
-                       pii.pool_ns = NULL;
-               }
-               parent_spec->image_id = pii.image_id;
-               pii.image_id = NULL;
-               parent_spec->snap_id = pii.snap_id;
-
-               rbd_dev->parent_spec = parent_spec;
-               parent_spec = NULL;     /* rbd_dev now owns this */
+       parent_spec->pool_id = pii.pool_id;
+       if (pii.pool_ns && *pii.pool_ns) {
+               parent_spec->pool_ns = pii.pool_ns;
+               pii.pool_ns = NULL;
        }
+       parent_spec->image_id = pii.image_id;
+       pii.image_id = NULL;
+       parent_spec->snap_id = pii.snap_id;
+
+       rbd_assert(!rbd_dev->parent_spec);
+       rbd_dev->parent_spec = parent_spec;
+       parent_spec = NULL;     /* rbd_dev now owns this */
 
        /*
-        * We always update the parent overlap.  If it's zero we issue
-        * a warning, as we will proceed as if there was no parent.
+        * Record the parent overlap.  If it's zero, issue a warning as
+        * we will proceed as if there is no parent.
         */
-       if (!pii.overlap) {
-               if (parent_spec) {
-                       /* refresh, careful to warn just once */
-                       if (rbd_dev->parent_overlap)
-                               rbd_warn(rbd_dev,
-                                   "clone now standalone (overlap became 0)");
-               } else {
-                       /* initial probe */
-                       rbd_warn(rbd_dev, "clone is standalone (overlap 0)");
-               }
-       }
+       if (!pii.overlap)
+               rbd_warn(rbd_dev, "clone is standalone (overlap 0)");
        rbd_dev->parent_overlap = pii.overlap;
 
 out:
        ret = 0;
 out_err:
-       kfree(pii.pool_ns);
-       kfree(pii.image_id);
+       rbd_parent_info_cleanup(&pii);
        rbd_spec_put(parent_spec);
        return ret;
 }
 
-static int rbd_dev_v2_striping_info(struct rbd_device *rbd_dev)
+static int rbd_dev_v2_striping_info(struct rbd_device *rbd_dev,
+                                   u64 *stripe_unit, u64 *stripe_count)
 {
        struct {
                __le64 stripe_unit;
                __le64 stripe_count;
        } __attribute__ ((packed)) striping_info_buf = { 0 };
        size_t size = sizeof (striping_info_buf);
-       void *p;
        int ret;
 
        ret = rbd_obj_method_sync(rbd_dev, &rbd_dev->header_oid,
@@ -5891,27 +5828,33 @@ static int rbd_dev_v2_striping_info(struct rbd_device *rbd_dev)
        if (ret < size)
                return -ERANGE;
 
-       p = &striping_info_buf;
-       rbd_dev->header.stripe_unit = ceph_decode_64(&p);
-       rbd_dev->header.stripe_count = ceph_decode_64(&p);
+       *stripe_unit = le64_to_cpu(striping_info_buf.stripe_unit);
+       *stripe_count = le64_to_cpu(striping_info_buf.stripe_count);
+       dout("  stripe_unit = %llu stripe_count = %llu\n", *stripe_unit,
+            *stripe_count);
+
        return 0;
 }
 
-static int rbd_dev_v2_data_pool(struct rbd_device *rbd_dev)
+static int rbd_dev_v2_data_pool(struct rbd_device *rbd_dev, s64 *data_pool_id)
 {
-       __le64 data_pool_id;
+       __le64 data_pool_buf;
        int ret;
 
        ret = rbd_obj_method_sync(rbd_dev, &rbd_dev->header_oid,
                                  &rbd_dev->header_oloc, "get_data_pool",
-                                 NULL, 0, &data_pool_id, sizeof(data_pool_id));
+                                 NULL, 0, &data_pool_buf,
+                                 sizeof(data_pool_buf));
+       dout("%s: rbd_obj_method_sync returned %d\n", __func__, ret);
        if (ret < 0)
                return ret;
-       if (ret < sizeof(data_pool_id))
+       if (ret < sizeof(data_pool_buf))
                return -EBADMSG;
 
-       rbd_dev->header.data_pool_id = le64_to_cpu(data_pool_id);
-       WARN_ON(rbd_dev->header.data_pool_id == CEPH_NOPOOL);
+       *data_pool_id = le64_to_cpu(data_pool_buf);
+       dout("  data_pool_id = %lld\n", *data_pool_id);
+       WARN_ON(*data_pool_id == CEPH_NOPOOL);
+
        return 0;
 }
 
@@ -6103,7 +6046,8 @@ out_err:
        return ret;
 }
 
-static int rbd_dev_v2_snap_context(struct rbd_device *rbd_dev)
+static int rbd_dev_v2_snap_context(struct rbd_device *rbd_dev,
+                                  struct ceph_snap_context **psnapc)
 {
        size_t size;
        int ret;
@@ -6164,9 +6108,7 @@ static int rbd_dev_v2_snap_context(struct rbd_device *rbd_dev)
        for (i = 0; i < snap_count; i++)
                snapc->snaps[i] = ceph_decode_64(&p);
 
-       ceph_put_snap_context(rbd_dev->header.snapc);
-       rbd_dev->header.snapc = snapc;
-
+       *psnapc = snapc;
        dout("  snap context seq = %llu, snap_count = %u\n",
                (unsigned long long)seq, (unsigned int)snap_count);
 out:
@@ -6215,38 +6157,42 @@ out:
        return snap_name;
 }
 
-static int rbd_dev_v2_header_info(struct rbd_device *rbd_dev)
+static int rbd_dev_v2_header_info(struct rbd_device *rbd_dev,
+                                 struct rbd_image_header *header,
+                                 bool first_time)
 {
-       bool first_time = rbd_dev->header.object_prefix == NULL;
        int ret;
 
-       ret = rbd_dev_v2_image_size(rbd_dev);
+       ret = _rbd_dev_v2_snap_size(rbd_dev, CEPH_NOSNAP,
+                                   first_time ? &header->obj_order : NULL,
+                                   &header->image_size);
        if (ret)
                return ret;
 
        if (first_time) {
-               ret = rbd_dev_v2_header_onetime(rbd_dev);
+               ret = rbd_dev_v2_header_onetime(rbd_dev, header);
                if (ret)
                        return ret;
        }
 
-       ret = rbd_dev_v2_snap_context(rbd_dev);
-       if (ret && first_time) {
-               kfree(rbd_dev->header.object_prefix);
-               rbd_dev->header.object_prefix = NULL;
-       }
+       ret = rbd_dev_v2_snap_context(rbd_dev, &header->snapc);
+       if (ret)
+               return ret;
 
-       return ret;
+       return 0;
 }
 
-static int rbd_dev_header_info(struct rbd_device *rbd_dev)
+static int rbd_dev_header_info(struct rbd_device *rbd_dev,
+                              struct rbd_image_header *header,
+                              bool first_time)
 {
        rbd_assert(rbd_image_format_valid(rbd_dev->image_format));
+       rbd_assert(!header->object_prefix && !header->snapc);
 
        if (rbd_dev->image_format == 1)
-               return rbd_dev_v1_header_info(rbd_dev);
+               return rbd_dev_v1_header_info(rbd_dev, header, first_time);
 
-       return rbd_dev_v2_header_info(rbd_dev);
+       return rbd_dev_v2_header_info(rbd_dev, header, first_time);
 }
 
 /*
@@ -6734,60 +6680,49 @@ out:
  */
 static void rbd_dev_unprobe(struct rbd_device *rbd_dev)
 {
-       struct rbd_image_header *header;
-
        rbd_dev_parent_put(rbd_dev);
        rbd_object_map_free(rbd_dev);
        rbd_dev_mapping_clear(rbd_dev);
 
        /* Free dynamic fields from the header, then zero it out */
 
-       header = &rbd_dev->header;
-       ceph_put_snap_context(header->snapc);
-       kfree(header->snap_sizes);
-       kfree(header->snap_names);
-       kfree(header->object_prefix);
-       memset(header, 0, sizeof (*header));
+       rbd_image_header_cleanup(&rbd_dev->header);
 }
 
-static int rbd_dev_v2_header_onetime(struct rbd_device *rbd_dev)
+static int rbd_dev_v2_header_onetime(struct rbd_device *rbd_dev,
+                                    struct rbd_image_header *header)
 {
        int ret;
 
-       ret = rbd_dev_v2_object_prefix(rbd_dev);
+       ret = rbd_dev_v2_object_prefix(rbd_dev, &header->object_prefix);
        if (ret)
-               goto out_err;
+               return ret;
 
        /*
         * Get the and check features for the image.  Currently the
         * features are assumed to never change.
         */
-       ret = rbd_dev_v2_features(rbd_dev);
+       ret = _rbd_dev_v2_snap_features(rbd_dev, CEPH_NOSNAP,
+                                       rbd_is_ro(rbd_dev), &header->features);
        if (ret)
-               goto out_err;
+               return ret;
 
        /* If the image supports fancy striping, get its parameters */
 
-       if (rbd_dev->header.features & RBD_FEATURE_STRIPINGV2) {
-               ret = rbd_dev_v2_striping_info(rbd_dev);
-               if (ret < 0)
-                       goto out_err;
+       if (header->features & RBD_FEATURE_STRIPINGV2) {
+               ret = rbd_dev_v2_striping_info(rbd_dev, &header->stripe_unit,
+                                              &header->stripe_count);
+               if (ret)
+                       return ret;
        }
 
-       if (rbd_dev->header.features & RBD_FEATURE_DATA_POOL) {
-               ret = rbd_dev_v2_data_pool(rbd_dev);
+       if (header->features & RBD_FEATURE_DATA_POOL) {
+               ret = rbd_dev_v2_data_pool(rbd_dev, &header->data_pool_id);
                if (ret)
-                       goto out_err;
+                       return ret;
        }
 
-       rbd_init_layout(rbd_dev);
        return 0;
-
-out_err:
-       rbd_dev->header.features = 0;
-       kfree(rbd_dev->header.object_prefix);
-       rbd_dev->header.object_prefix = NULL;
-       return ret;
 }
 
 /*
@@ -6982,13 +6917,15 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, int depth)
        if (!depth)
                down_write(&rbd_dev->header_rwsem);
 
-       ret = rbd_dev_header_info(rbd_dev);
+       ret = rbd_dev_header_info(rbd_dev, &rbd_dev->header, true);
        if (ret) {
                if (ret == -ENOENT && !need_watch)
                        rbd_print_dne(rbd_dev, false);
                goto err_out_probe;
        }
 
+       rbd_init_layout(rbd_dev);
+
        /*
         * If this image is the one being mapped, we have pool name and
         * id, image name and id, and snap name - need to fill snap id.
@@ -7017,7 +6954,7 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, int depth)
        }
 
        if (rbd_dev->header.features & RBD_FEATURE_LAYERING) {
-               ret = rbd_dev_v2_parent_info(rbd_dev);
+               ret = rbd_dev_setup_parent(rbd_dev);
                if (ret)
                        goto err_out_probe;
        }
@@ -7043,6 +6980,107 @@ err_out_format:
        return ret;
 }
 
+static void rbd_dev_update_header(struct rbd_device *rbd_dev,
+                                 struct rbd_image_header *header)
+{
+       rbd_assert(rbd_image_format_valid(rbd_dev->image_format));
+       rbd_assert(rbd_dev->header.object_prefix); /* !first_time */
+
+       if (rbd_dev->header.image_size != header->image_size) {
+               rbd_dev->header.image_size = header->image_size;
+
+               if (!rbd_is_snap(rbd_dev)) {
+                       rbd_dev->mapping.size = header->image_size;
+                       rbd_dev_update_size(rbd_dev);
+               }
+       }
+
+       ceph_put_snap_context(rbd_dev->header.snapc);
+       rbd_dev->header.snapc = header->snapc;
+       header->snapc = NULL;
+
+       if (rbd_dev->image_format == 1) {
+               kfree(rbd_dev->header.snap_names);
+               rbd_dev->header.snap_names = header->snap_names;
+               header->snap_names = NULL;
+
+               kfree(rbd_dev->header.snap_sizes);
+               rbd_dev->header.snap_sizes = header->snap_sizes;
+               header->snap_sizes = NULL;
+       }
+}
+
+static void rbd_dev_update_parent(struct rbd_device *rbd_dev,
+                                 struct parent_image_info *pii)
+{
+       if (pii->pool_id == CEPH_NOPOOL || !pii->has_overlap) {
+               /*
+                * Either the parent never existed, or we have
+                * record of it but the image got flattened so it no
+                * longer has a parent.  When the parent of a
+                * layered image disappears we immediately set the
+                * overlap to 0.  The effect of this is that all new
+                * requests will be treated as if the image had no
+                * parent.
+                *
+                * If !pii.has_overlap, the parent image spec is not
+                * applicable.  It's there to avoid duplication in each
+                * snapshot record.
+                */
+               if (rbd_dev->parent_overlap) {
+                       rbd_dev->parent_overlap = 0;
+                       rbd_dev_parent_put(rbd_dev);
+                       pr_info("%s: clone has been flattened\n",
+                               rbd_dev->disk->disk_name);
+               }
+       } else {
+               rbd_assert(rbd_dev->parent_spec);
+
+               /*
+                * Update the parent overlap.  If it became zero, issue
+                * a warning as we will proceed as if there is no parent.
+                */
+               if (!pii->overlap && rbd_dev->parent_overlap)
+                       rbd_warn(rbd_dev,
+                                "clone has become standalone (overlap 0)");
+               rbd_dev->parent_overlap = pii->overlap;
+       }
+}
+
+static int rbd_dev_refresh(struct rbd_device *rbd_dev)
+{
+       struct rbd_image_header header = { 0 };
+       struct parent_image_info pii = { 0 };
+       int ret;
+
+       dout("%s rbd_dev %p\n", __func__, rbd_dev);
+
+       ret = rbd_dev_header_info(rbd_dev, &header, false);
+       if (ret)
+               goto out;
+
+       /*
+        * If there is a parent, see if it has disappeared due to the
+        * mapped image getting flattened.
+        */
+       if (rbd_dev->parent) {
+               ret = rbd_dev_v2_parent_info(rbd_dev, &pii);
+               if (ret)
+                       goto out;
+       }
+
+       down_write(&rbd_dev->header_rwsem);
+       rbd_dev_update_header(rbd_dev, &header);
+       if (rbd_dev->parent)
+               rbd_dev_update_parent(rbd_dev, &pii);
+       up_write(&rbd_dev->header_rwsem);
+
+out:
+       rbd_parent_info_cleanup(&pii);
+       rbd_image_header_cleanup(&header);
+       return ret;
+}
+
 static ssize_t do_rbd_add(const char *buf, size_t count)
 {
        struct rbd_device *rbd_dev = NULL;
index 82597ab..499f480 100644 (file)
@@ -4419,6 +4419,7 @@ static int btusb_probe(struct usb_interface *intf,
 
        if (id->driver_info & BTUSB_QCA_ROME) {
                data->setup_on_usb = btusb_setup_qca;
+               hdev->shutdown = btusb_shutdown_qca;
                hdev->set_bdaddr = btusb_set_bdaddr_ath3012;
                hdev->cmd_timeout = btusb_qca_cmd_timeout;
                set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
index eb4e7be..d57bc06 100644 (file)
@@ -38,6 +38,7 @@ enum sysc_soc {
        SOC_2420,
        SOC_2430,
        SOC_3430,
+       SOC_AM35,
        SOC_3630,
        SOC_4430,
        SOC_4460,
@@ -1097,6 +1098,11 @@ static int sysc_enable_module(struct device *dev)
        if (ddata->cfg.quirks & (SYSC_QUIRK_SWSUP_SIDLE |
                                 SYSC_QUIRK_SWSUP_SIDLE_ACT)) {
                best_mode = SYSC_IDLE_NO;
+
+               /* Clear WAKEUP */
+               if (regbits->enwkup_shift >= 0 &&
+                   ddata->cfg.sysc_val & BIT(regbits->enwkup_shift))
+                       reg &= ~BIT(regbits->enwkup_shift);
        } else {
                best_mode = fls(ddata->cfg.sidlemodes) - 1;
                if (best_mode > SYSC_IDLE_MASK) {
@@ -1224,6 +1230,13 @@ set_sidle:
                }
        }
 
+       if (ddata->cfg.quirks & SYSC_QUIRK_SWSUP_SIDLE_ACT) {
+               /* Set WAKEUP */
+               if (regbits->enwkup_shift >= 0 &&
+                   ddata->cfg.sysc_val & BIT(regbits->enwkup_shift))
+                       reg |= BIT(regbits->enwkup_shift);
+       }
+
        reg &= ~(SYSC_IDLE_MASK << regbits->sidle_shift);
        reg |= best_mode << regbits->sidle_shift;
        if (regbits->autoidle_shift >= 0 &&
@@ -1518,16 +1531,16 @@ struct sysc_revision_quirk {
 static const struct sysc_revision_quirk sysc_revision_quirks[] = {
        /* These drivers need to be fixed to not use pm_runtime_irq_safe() */
        SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x00000046, 0xffffffff,
-                  SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_LEGACY_IDLE),
+                  SYSC_QUIRK_SWSUP_SIDLE_ACT | SYSC_QUIRK_LEGACY_IDLE),
        SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x00000052, 0xffffffff,
-                  SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_LEGACY_IDLE),
+                  SYSC_QUIRK_SWSUP_SIDLE_ACT | SYSC_QUIRK_LEGACY_IDLE),
        /* Uarts on omap4 and later */
        SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x50411e03, 0xffff00ff,
-                  SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_LEGACY_IDLE),
+                  SYSC_QUIRK_SWSUP_SIDLE_ACT | SYSC_QUIRK_LEGACY_IDLE),
        SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x47422e03, 0xffffffff,
-                  SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_LEGACY_IDLE),
+                  SYSC_QUIRK_SWSUP_SIDLE_ACT | SYSC_QUIRK_LEGACY_IDLE),
        SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x47424e03, 0xffffffff,
-                  SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_LEGACY_IDLE),
+                  SYSC_QUIRK_SWSUP_SIDLE_ACT | SYSC_QUIRK_LEGACY_IDLE),
 
        /* Quirks that need to be set based on the module address */
        SYSC_QUIRK("mcpdm", 0x40132000, 0, 0x10, -ENODEV, 0x50000800, 0xffffffff,
@@ -1862,7 +1875,7 @@ static void sysc_pre_reset_quirk_dss(struct sysc *ddata)
                dev_warn(ddata->dev, "%s: timed out %08x !+ %08x\n",
                         __func__, val, irq_mask);
 
-       if (sysc_soc->soc == SOC_3430) {
+       if (sysc_soc->soc == SOC_3430 || sysc_soc->soc == SOC_AM35) {
                /* Clear DSS_SDI_CONTROL */
                sysc_write(ddata, 0x44, 0);
 
@@ -2150,8 +2163,7 @@ static int sysc_reset(struct sysc *ddata)
        }
 
        if (ddata->cfg.srst_udelay)
-               usleep_range(ddata->cfg.srst_udelay,
-                            ddata->cfg.srst_udelay * 2);
+               fsleep(ddata->cfg.srst_udelay);
 
        if (ddata->post_reset_quirk)
                ddata->post_reset_quirk(ddata);
@@ -3025,6 +3037,7 @@ static void ti_sysc_idle(struct work_struct *work)
 static const struct soc_device_attribute sysc_soc_match[] = {
        SOC_FLAG("OMAP242*", SOC_2420),
        SOC_FLAG("OMAP243*", SOC_2430),
+       SOC_FLAG("AM35*", SOC_AM35),
        SOC_FLAG("OMAP3[45]*", SOC_3430),
        SOC_FLAG("OMAP3[67]*", SOC_3630),
        SOC_FLAG("OMAP443*", SOC_4430),
@@ -3229,7 +3242,7 @@ static int sysc_check_active_timer(struct sysc *ddata)
         * can be dropped if we stop supporting old beagleboard revisions
         * A to B4 at some point.
         */
-       if (sysc_soc->soc == SOC_3430)
+       if (sysc_soc->soc == SOC_3430 || sysc_soc->soc == SOC_AM35)
                error = -ENXIO;
        else
                error = -EBUSY;
index 4eaf1b5..ef4ba46 100644 (file)
@@ -96,7 +96,7 @@ static int si521xx_regmap_i2c_write(void *context, unsigned int reg,
                                    unsigned int val)
 {
        struct i2c_client *i2c = context;
-       const u8 data[3] = { reg, 1, val };
+       const u8 data[2] = { reg, val };
        const int count = ARRAY_SIZE(data);
        int ret;
 
@@ -146,7 +146,7 @@ static int si521xx_regmap_i2c_read(void *context, unsigned int reg,
 static const struct regmap_config si521xx_regmap_config = {
        .reg_bits = 8,
        .val_bits = 8,
-       .cache_type = REGCACHE_NONE,
+       .cache_type = REGCACHE_FLAT,
        .max_register = SI521XX_REG_DA,
        .rd_table = &si521xx_readable_table,
        .wr_table = &si521xx_writeable_table,
@@ -281,9 +281,10 @@ static int si521xx_probe(struct i2c_client *client)
 {
        const u16 chip_info = (u16)(uintptr_t)device_get_match_data(&client->dev);
        const struct clk_parent_data clk_parent_data = { .index = 0 };
-       struct si521xx *si;
+       const u8 data[3] = { SI521XX_REG_BC, 1, 1 };
        unsigned char name[6] = "DIFF0";
        struct clk_init_data init = {};
+       struct si521xx *si;
        int i, ret;
 
        if (!chip_info)
@@ -308,7 +309,7 @@ static int si521xx_probe(struct i2c_client *client)
                                     "Failed to allocate register map\n");
 
        /* Always read back 1 Byte via I2C */
-       ret = regmap_write(si->regmap, SI521XX_REG_BC, 1);
+       ret = i2c_master_send(client, data, ARRAY_SIZE(data));
        if (ret < 0)
                return ret;
 
index 7ab2447..3d7de35 100644 (file)
@@ -118,21 +118,21 @@ enum vc3_div {
        VC3_DIV5,
 };
 
-enum vc3_clk_mux {
-       VC3_DIFF2_MUX,
-       VC3_DIFF1_MUX,
-       VC3_SE3_MUX,
-       VC3_SE2_MUX,
-       VC3_SE1_MUX,
-};
-
 enum vc3_clk {
-       VC3_DIFF2,
-       VC3_DIFF1,
-       VC3_SE3,
-       VC3_SE2,
-       VC3_SE1,
        VC3_REF,
+       VC3_SE1,
+       VC3_SE2,
+       VC3_SE3,
+       VC3_DIFF1,
+       VC3_DIFF2,
+};
+
+enum vc3_clk_mux {
+       VC3_SE1_MUX = VC3_SE1 - 1,
+       VC3_SE2_MUX = VC3_SE2 - 1,
+       VC3_SE3_MUX = VC3_SE3 - 1,
+       VC3_DIFF1_MUX = VC3_DIFF1 - 1,
+       VC3_DIFF2_MUX = VC3_DIFF2 - 1,
 };
 
 struct vc3_clk_data {
@@ -401,11 +401,10 @@ static long vc3_pll_round_rate(struct clk_hw *hw, unsigned long rate,
                /* Determine best fractional part, which is 16 bit wide */
                div_frc = rate % *parent_rate;
                div_frc *= BIT(16) - 1;
-               do_div(div_frc, *parent_rate);
 
-               vc3->div_frc = (u32)div_frc;
+               vc3->div_frc = min_t(u64, div64_ul(div_frc, *parent_rate), U16_MAX);
                rate = (*parent_rate *
-                       (vc3->div_int * VC3_2_POW_16 + div_frc) / VC3_2_POW_16);
+                       (vc3->div_int * VC3_2_POW_16 + vc3->div_frc) / VC3_2_POW_16);
        } else {
                rate = *parent_rate * vc3->div_int;
        }
@@ -897,33 +896,33 @@ static struct vc3_hw_data clk_div[] = {
 };
 
 static struct vc3_hw_data clk_mux[] = {
-       [VC3_DIFF2_MUX] = {
+       [VC3_SE1_MUX] = {
                .data = &(struct vc3_clk_data) {
-                       .offs = VC3_DIFF2_CTRL_REG,
-                       .bitmsk = VC3_DIFF2_CTRL_REG_DIFF2_CLK_SEL
+                       .offs = VC3_SE1_DIV4_CTRL,
+                       .bitmsk = VC3_SE1_DIV4_CTRL_SE1_CLK_SEL
                },
                .hw.init = &(struct clk_init_data){
-                       .name = "diff2_mux",
+                       .name = "se1_mux",
                        .ops = &vc3_clk_mux_ops,
                        .parent_hws = (const struct clk_hw *[]) {
-                               &clk_div[VC3_DIV1].hw,
-                               &clk_div[VC3_DIV3].hw
+                               &clk_div[VC3_DIV5].hw,
+                               &clk_div[VC3_DIV4].hw
                        },
                        .num_parents = 2,
                        .flags = CLK_SET_RATE_PARENT
                }
        },
-       [VC3_DIFF1_MUX] = {
+       [VC3_SE2_MUX] = {
                .data = &(struct vc3_clk_data) {
-                       .offs = VC3_DIFF1_CTRL_REG,
-                       .bitmsk = VC3_DIFF1_CTRL_REG_DIFF1_CLK_SEL
+                       .offs = VC3_SE2_CTRL_REG0,
+                       .bitmsk = VC3_SE2_CTRL_REG0_SE2_CLK_SEL
                },
                .hw.init = &(struct clk_init_data){
-                       .name = "diff1_mux",
+                       .name = "se2_mux",
                        .ops = &vc3_clk_mux_ops,
                        .parent_hws = (const struct clk_hw *[]) {
-                               &clk_div[VC3_DIV1].hw,
-                               &clk_div[VC3_DIV3].hw
+                               &clk_div[VC3_DIV5].hw,
+                               &clk_div[VC3_DIV4].hw
                        },
                        .num_parents = 2,
                        .flags = CLK_SET_RATE_PARENT
@@ -945,33 +944,33 @@ static struct vc3_hw_data clk_mux[] = {
                        .flags = CLK_SET_RATE_PARENT
                }
        },
-       [VC3_SE2_MUX] = {
+       [VC3_DIFF1_MUX] = {
                .data = &(struct vc3_clk_data) {
-                       .offs = VC3_SE2_CTRL_REG0,
-                       .bitmsk = VC3_SE2_CTRL_REG0_SE2_CLK_SEL
+                       .offs = VC3_DIFF1_CTRL_REG,
+                       .bitmsk = VC3_DIFF1_CTRL_REG_DIFF1_CLK_SEL
                },
                .hw.init = &(struct clk_init_data){
-                       .name = "se2_mux",
+                       .name = "diff1_mux",
                        .ops = &vc3_clk_mux_ops,
                        .parent_hws = (const struct clk_hw *[]) {
-                               &clk_div[VC3_DIV5].hw,
-                               &clk_div[VC3_DIV4].hw
+                               &clk_div[VC3_DIV1].hw,
+                               &clk_div[VC3_DIV3].hw
                        },
                        .num_parents = 2,
                        .flags = CLK_SET_RATE_PARENT
                }
        },
-       [VC3_SE1_MUX] = {
+       [VC3_DIFF2_MUX] = {
                .data = &(struct vc3_clk_data) {
-                       .offs = VC3_SE1_DIV4_CTRL,
-                       .bitmsk = VC3_SE1_DIV4_CTRL_SE1_CLK_SEL
+                       .offs = VC3_DIFF2_CTRL_REG,
+                       .bitmsk = VC3_DIFF2_CTRL_REG_DIFF2_CLK_SEL
                },
                .hw.init = &(struct clk_init_data){
-                       .name = "se1_mux",
+                       .name = "diff2_mux",
                        .ops = &vc3_clk_mux_ops,
                        .parent_hws = (const struct clk_hw *[]) {
-                               &clk_div[VC3_DIV5].hw,
-                               &clk_div[VC3_DIV4].hw
+                               &clk_div[VC3_DIV1].hw,
+                               &clk_div[VC3_DIV3].hw
                        },
                        .num_parents = 2,
                        .flags = CLK_SET_RATE_PARENT
@@ -1110,7 +1109,7 @@ static int vc3_probe(struct i2c_client *client)
                                name, 0, CLK_SET_RATE_PARENT, 1, 1);
                else
                        clk_out[i] = devm_clk_hw_register_fixed_factor_parent_hw(dev,
-                               name, &clk_mux[i].hw, CLK_SET_RATE_PARENT, 1, 1);
+                               name, &clk_mux[i - 1].hw, CLK_SET_RATE_PARENT, 1, 1);
 
                if (IS_ERR(clk_out[i]))
                        return PTR_ERR(clk_out[i]);
index 8f4441d..9384ecc 100644 (file)
@@ -800,7 +800,7 @@ static SPRD_MUX_CLK_DATA(uart1_clk, "uart1-clk", uart_parents,
                         0x250, 0, 3, UMS512_MUX_FLAG);
 
 static const struct clk_parent_data thm_parents[] = {
-       { .fw_name = "ext-32m" },
+       { .fw_name = "ext-32k" },
        { .hw = &clk_250k.hw  },
 };
 static SPRD_MUX_CLK_DATA(thm0_clk, "thm0-clk", thm_parents,
index a9f3fb4..7bfba0a 100644 (file)
@@ -159,7 +159,7 @@ static unsigned long tegra_bpmp_clk_recalc_rate(struct clk_hw *hw,
 
        err = tegra_bpmp_clk_transfer(clk->bpmp, &msg);
        if (err < 0)
-               return err;
+               return 0;
 
        return response.rate;
 }
index d1c5598..40d0555 100644 (file)
@@ -14,7 +14,7 @@
 
 struct cxl_cxims_data {
        int nr_maps;
-       u64 xormaps[];
+       u64 xormaps[] __counted_by(nr_maps);
 };
 
 /*
@@ -112,9 +112,9 @@ static int cxl_parse_cxims(union acpi_subtable_headers *header, void *arg,
                              GFP_KERNEL);
        if (!cximsd)
                return -ENOMEM;
+       cximsd->nr_maps = nr_maps;
        memcpy(cximsd->xormaps, cxims->xormap_list,
               nr_maps * sizeof(*cximsd->xormaps));
-       cximsd->nr_maps = nr_maps;
        cxlrd->platform_data = cximsd;
 
        return 0;
index ca60bb8..4df4f61 100644 (file)
@@ -715,24 +715,25 @@ static void cxl_walk_cel(struct cxl_memdev_state *mds, size_t size, u8 *cel)
        for (i = 0; i < cel_entries; i++) {
                u16 opcode = le16_to_cpu(cel_entry[i].opcode);
                struct cxl_mem_command *cmd = cxl_mem_find_command(opcode);
+               int enabled = 0;
 
-               if (!cmd && (!cxl_is_poison_command(opcode) ||
-                            !cxl_is_security_command(opcode))) {
-                       dev_dbg(dev,
-                               "Opcode 0x%04x unsupported by driver\n", opcode);
-                       continue;
-               }
-
-               if (cmd)
+               if (cmd) {
                        set_bit(cmd->info.id, mds->enabled_cmds);
+                       enabled++;
+               }
 
-               if (cxl_is_poison_command(opcode))
+               if (cxl_is_poison_command(opcode)) {
                        cxl_set_poison_cmd_enabled(&mds->poison, opcode);
+                       enabled++;
+               }
 
-               if (cxl_is_security_command(opcode))
+               if (cxl_is_security_command(opcode)) {
                        cxl_set_security_cmd_enabled(&mds->security, opcode);
+                       enabled++;
+               }
 
-               dev_dbg(dev, "Opcode 0x%04x enabled\n", opcode);
+               dev_dbg(dev, "Opcode 0x%04x %s\n", opcode,
+                       enabled ? "enabled" : "unsupported by driver");
        }
 }
 
index 724be84..7ca01a8 100644 (file)
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /* Copyright(c) 2020 Intel Corporation. All rights reserved. */
+#include <linux/platform_device.h>
 #include <linux/memregion.h>
 #include <linux/workqueue.h>
 #include <linux/debugfs.h>
@@ -706,16 +707,20 @@ static int cxl_setup_comp_regs(struct device *dev, struct cxl_register_map *map,
        return cxl_setup_regs(map);
 }
 
-static inline int cxl_port_setup_regs(struct cxl_port *port,
-                                     resource_size_t component_reg_phys)
+static int cxl_port_setup_regs(struct cxl_port *port,
+                       resource_size_t component_reg_phys)
 {
+       if (dev_is_platform(port->uport_dev))
+               return 0;
        return cxl_setup_comp_regs(&port->dev, &port->comp_map,
                                   component_reg_phys);
 }
 
-static inline int cxl_dport_setup_regs(struct cxl_dport *dport,
-                                      resource_size_t component_reg_phys)
+static int cxl_dport_setup_regs(struct cxl_dport *dport,
+                               resource_size_t component_reg_phys)
 {
+       if (dev_is_platform(dport->dport_dev))
+               return 0;
        return cxl_setup_comp_regs(dport->dport_dev, &dport->comp_map,
                                   component_reg_phys);
 }
index e115ba3..6d63b87 100644 (file)
@@ -717,13 +717,35 @@ static int match_free_decoder(struct device *dev, void *data)
        return 0;
 }
 
+static int match_auto_decoder(struct device *dev, void *data)
+{
+       struct cxl_region_params *p = data;
+       struct cxl_decoder *cxld;
+       struct range *r;
+
+       if (!is_switch_decoder(dev))
+               return 0;
+
+       cxld = to_cxl_decoder(dev);
+       r = &cxld->hpa_range;
+
+       if (p->res && p->res->start == r->start && p->res->end == r->end)
+               return 1;
+
+       return 0;
+}
+
 static struct cxl_decoder *cxl_region_find_decoder(struct cxl_port *port,
                                                   struct cxl_region *cxlr)
 {
        struct device *dev;
        int id = 0;
 
-       dev = device_find_child(&port->dev, &id, match_free_decoder);
+       if (test_bit(CXL_REGION_F_AUTO, &cxlr->flags))
+               dev = device_find_child(&port->dev, &cxlr->params,
+                                       match_auto_decoder);
+       else
+               dev = device_find_child(&port->dev, &id, match_free_decoder);
        if (!dev)
                return NULL;
        /*
@@ -1154,16 +1176,15 @@ static int cxl_port_setup_targets(struct cxl_port *port,
        }
 
        /*
-        * If @parent_port is masking address bits, pick the next unused address
-        * bit to route @port's targets.
+        * Interleave granularity is a multiple of @parent_port granularity.
+        * Multiplier is the parent port interleave ways.
         */
-       if (parent_iw > 1 && cxl_rr->nr_targets > 1) {
-               u32 address_bit = max(peig + peiw, eiw + peig);
-
-               eig = address_bit - eiw + 1;
-       } else {
-               eiw = peiw;
-               eig = peig;
+       rc = granularity_to_eig(parent_ig * parent_iw, &eig);
+       if (rc) {
+               dev_dbg(&cxlr->dev,
+                       "%s: invalid granularity calculation (%d * %d)\n",
+                       dev_name(&parent_port->dev), parent_ig, parent_iw);
+               return rc;
        }
 
        rc = eig_to_granularity(eig, &ig);
index 1cb1494..44a21ab 100644 (file)
@@ -529,7 +529,6 @@ static int cxl_pci_setup_regs(struct pci_dev *pdev, enum cxl_regloc_type type,
 
 static int cxl_pci_ras_unmask(struct pci_dev *pdev)
 {
-       struct pci_host_bridge *host_bridge = pci_find_host_bridge(pdev->bus);
        struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
        void __iomem *addr;
        u32 orig_val, val, mask;
@@ -541,9 +540,9 @@ static int cxl_pci_ras_unmask(struct pci_dev *pdev)
                return 0;
        }
 
-       /* BIOS has CXL error control */
-       if (!host_bridge->native_cxl_error)
-               return -ENXIO;
+       /* BIOS has PCIe AER error control */
+       if (!pcie_aer_is_native(pdev))
+               return 0;
 
        rc = pcie_capability_read_word(pdev, PCI_EXP_DEVCTL, &cap);
        if (rc)
index 789193e..c278d5f 100644 (file)
@@ -558,6 +558,9 @@ int k3_udma_glue_tx_get_irq(struct k3_udma_glue_tx_channel *tx_chn)
                tx_chn->virq = k3_ringacc_get_ring_irq_num(tx_chn->ringtxcq);
        }
 
+       if (!tx_chn->virq)
+               return -ENXIO;
+
        return tx_chn->virq;
 }
 EXPORT_SYMBOL_GPL(k3_udma_glue_tx_get_irq);
index 26db5b8..749868b 100644 (file)
@@ -81,7 +81,8 @@ MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device "
  *
  * - power condition
  *   Set the power condition field in the START STOP UNIT commands sent by
- *   sd_mod on suspend, resume, and shutdown (if manage_start_stop is on).
+ *   sd_mod on suspend, resume, and shutdown (if manage_system_start_stop or
+ *   manage_runtime_start_stop is on).
  *   Some disks need this to spin down or to resume properly.
  *
  * - override internal blacklist
@@ -1517,8 +1518,10 @@ static int sbp2_scsi_slave_configure(struct scsi_device *sdev)
 
        sdev->use_10_for_rw = 1;
 
-       if (sbp2_param_exclusive_login)
-               sdev->manage_start_stop = 1;
+       if (sbp2_param_exclusive_login) {
+               sdev->manage_system_start_stop = true;
+               sdev->manage_runtime_start_stop = true;
+       }
 
        if (sdev->type == TYPE_ROM)
                sdev->use_10_for_ms = 1;
index 2109cd1..121f4fc 100644 (file)
@@ -397,6 +397,19 @@ static u32 ffa_get_num_pages_sg(struct scatterlist *sg)
        return num_pages;
 }
 
+static u8 ffa_memory_attributes_get(u32 func_id)
+{
+       /*
+        * For the memory lend or donate operation, if the receiver is a PE or
+        * a proxy endpoint, the owner/sender must not specify the attributes
+        */
+       if (func_id == FFA_FN_NATIVE(MEM_LEND) ||
+           func_id == FFA_MEM_LEND)
+               return 0;
+
+       return FFA_MEM_NORMAL | FFA_MEM_WRITE_BACK | FFA_MEM_INNER_SHAREABLE;
+}
+
 static int
 ffa_setup_and_transmit(u32 func_id, void *buffer, u32 max_fragsize,
                       struct ffa_mem_ops_args *args)
@@ -413,8 +426,7 @@ ffa_setup_and_transmit(u32 func_id, void *buffer, u32 max_fragsize,
        mem_region->tag = args->tag;
        mem_region->flags = args->flags;
        mem_region->sender_id = drv_info->vm_id;
-       mem_region->attributes = FFA_MEM_NORMAL | FFA_MEM_WRITE_BACK |
-                                FFA_MEM_INNER_SHAREABLE;
+       mem_region->attributes = ffa_memory_attributes_get(func_id);
        ep_mem_access = &mem_region->ep_mem_access[0];
 
        for (idx = 0; idx < args->nattrs; idx++, ep_mem_access++) {
index c0cd556..30dedd6 100644 (file)
@@ -1080,6 +1080,8 @@ static int scmi_perf_protocol_init(const struct scmi_protocol_handle *ph)
        if (!pinfo)
                return -ENOMEM;
 
+       pinfo->version = version;
+
        ret = scmi_perf_attributes_get(ph, pinfo);
        if (ret)
                return ret;
@@ -1104,8 +1106,6 @@ static int scmi_perf_protocol_init(const struct scmi_protocol_handle *ph)
        if (ret)
                return ret;
 
-       pinfo->version = version;
-
        return ph->set_priv(ph, pinfo);
 }
 
index 49b70c7..79d4254 100644 (file)
@@ -1863,15 +1863,15 @@ static int cs_dsp_adsp2_setup_algs(struct cs_dsp *dsp)
                return PTR_ERR(adsp2_alg);
 
        for (i = 0; i < n_algs; i++) {
-               cs_dsp_info(dsp,
-                           "%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n",
-                           i, be32_to_cpu(adsp2_alg[i].alg.id),
-                           (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16,
-                           (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8,
-                           be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff,
-                           be32_to_cpu(adsp2_alg[i].xm),
-                           be32_to_cpu(adsp2_alg[i].ym),
-                           be32_to_cpu(adsp2_alg[i].zm));
+               cs_dsp_dbg(dsp,
+                          "%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n",
+                          i, be32_to_cpu(adsp2_alg[i].alg.id),
+                          (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16,
+                          (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8,
+                          be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff,
+                          be32_to_cpu(adsp2_alg[i].xm),
+                          be32_to_cpu(adsp2_alg[i].ym),
+                          be32_to_cpu(adsp2_alg[i].zm));
 
                alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_XM,
                                                  adsp2_alg[i].alg.id,
@@ -1996,14 +1996,14 @@ static int cs_dsp_halo_setup_algs(struct cs_dsp *dsp)
                return PTR_ERR(halo_alg);
 
        for (i = 0; i < n_algs; i++) {
-               cs_dsp_info(dsp,
-                           "%d: ID %x v%d.%d.%d XM@%x YM@%x\n",
-                           i, be32_to_cpu(halo_alg[i].alg.id),
-                           (be32_to_cpu(halo_alg[i].alg.ver) & 0xff0000) >> 16,
-                           (be32_to_cpu(halo_alg[i].alg.ver) & 0xff00) >> 8,
-                           be32_to_cpu(halo_alg[i].alg.ver) & 0xff,
-                           be32_to_cpu(halo_alg[i].xm_base),
-                           be32_to_cpu(halo_alg[i].ym_base));
+               cs_dsp_dbg(dsp,
+                          "%d: ID %x v%d.%d.%d XM@%x YM@%x\n",
+                          i, be32_to_cpu(halo_alg[i].alg.id),
+                          (be32_to_cpu(halo_alg[i].alg.ver) & 0xff0000) >> 16,
+                          (be32_to_cpu(halo_alg[i].alg.ver) & 0xff00) >> 8,
+                          be32_to_cpu(halo_alg[i].alg.ver) & 0xff,
+                          be32_to_cpu(halo_alg[i].xm_base),
+                          be32_to_cpu(halo_alg[i].ym_base));
 
                ret = cs_dsp_halo_create_regions(dsp, halo_alg[i].alg.id,
                                                 halo_alg[i].alg.ver,
index 1599f11..ce20a60 100644 (file)
@@ -623,6 +623,34 @@ static __init int match_config_table(const efi_guid_t *guid,
        return 0;
 }
 
+/**
+ * reserve_unaccepted - Map and reserve unaccepted configuration table
+ * @unaccepted: Pointer to unaccepted memory table
+ *
+ * memblock_add() makes sure that the table is mapped in direct mapping. During
+ * normal boot it happens automatically because the table is allocated from
+ * usable memory. But during crashkernel boot only memory specifically reserved
+ * for crash scenario is mapped. memblock_add() forces the table to be mapped
+ * in crashkernel case.
+ *
+ * Align the range to the nearest page borders. Ranges smaller than page size
+ * are not going to be mapped.
+ *
+ * memblock_reserve() makes sure that future allocations will not touch the
+ * table.
+ */
+
+static __init void reserve_unaccepted(struct efi_unaccepted_memory *unaccepted)
+{
+       phys_addr_t start, size;
+
+       start = PAGE_ALIGN_DOWN(efi.unaccepted);
+       size = PAGE_ALIGN(sizeof(*unaccepted) + unaccepted->size);
+
+       memblock_add(start, size);
+       memblock_reserve(start, size);
+}
+
 int __init efi_config_parse_tables(const efi_config_table_t *config_tables,
                                   int count,
                                   const efi_config_table_type_t *arch_tables)
@@ -751,11 +779,9 @@ int __init efi_config_parse_tables(const efi_config_table_t *config_tables,
 
                unaccepted = early_memremap(efi.unaccepted, sizeof(*unaccepted));
                if (unaccepted) {
-                       unsigned long size;
 
                        if (unaccepted->version == 1) {
-                               size = sizeof(*unaccepted) + unaccepted->size;
-                               memblock_reserve(efi.unaccepted, size);
+                               reserve_unaccepted(unaccepted);
                        } else {
                                efi.unaccepted = EFI_INVALID_TABLE_ADDR;
                        }
index 3dba590..508eab3 100644 (file)
@@ -114,6 +114,7 @@ static int imx_dsp_setup_channels(struct imx_dsp_ipc *dsp_ipc)
                dsp_chan->idx = i % 2;
                dsp_chan->ch = mbox_request_channel_byname(cl, chan_name);
                if (IS_ERR(dsp_chan->ch)) {
+                       kfree(dsp_chan->name);
                        ret = PTR_ERR(dsp_chan->ch);
                        if (ret != -EPROBE_DEFER)
                                dev_err(dev, "Failed to request mbox chan %s ret %d\n",
index da33bbb..58f1071 100644 (file)
@@ -973,7 +973,7 @@ static int aspeed_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
        else if (param == PIN_CONFIG_BIAS_DISABLE ||
                        param == PIN_CONFIG_BIAS_PULL_DOWN ||
                        param == PIN_CONFIG_DRIVE_STRENGTH)
-               return pinctrl_gpio_set_config(offset, config);
+               return pinctrl_gpio_set_config(chip->base + offset, config);
        else if (param == PIN_CONFIG_DRIVE_OPEN_DRAIN ||
                        param == PIN_CONFIG_DRIVE_OPEN_SOURCE)
                /* Return -ENOTSUPP to trigger emulation, as per datasheet */
index 2b9b7be..01c0fd0 100644 (file)
@@ -352,6 +352,7 @@ static int sprd_pmic_eic_probe(struct platform_device *pdev)
        pmic_eic->chip.set_config = sprd_pmic_eic_set_config;
        pmic_eic->chip.set = sprd_pmic_eic_set;
        pmic_eic->chip.get = sprd_pmic_eic_get;
+       pmic_eic->chip.can_sleep = true;
 
        irq = &pmic_eic->chip.irq;
        gpio_irq_chip_set_chip(irq, &pmic_eic_irq_chip);
index 7e9f7a3..cae9661 100644 (file)
@@ -237,6 +237,7 @@ static bool pxa_gpio_has_pinctrl(void)
        switch (gpio_type) {
        case PXA3XX_GPIO:
        case MMP2_GPIO:
+       case MMP_GPIO:
                return false;
 
        default:
index 271db36..44bf170 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/irq.h>
 #include <linux/irq_sim.h>
 #include <linux/list.h>
+#include <linux/minmax.h>
 #include <linux/mod_devicetable.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
@@ -685,52 +686,32 @@ gpio_sim_device_config_live_show(struct config_item *item, char *page)
        return sprintf(page, "%c\n", live ? '1' : '0');
 }
 
-static char **gpio_sim_make_line_names(struct gpio_sim_bank *bank,
-                                      unsigned int *line_names_size)
+static unsigned int gpio_sim_get_line_names_size(struct gpio_sim_bank *bank)
 {
-       unsigned int max_offset = 0;
-       bool has_line_names = false;
        struct gpio_sim_line *line;
-       char **line_names;
+       unsigned int size = 0;
 
        list_for_each_entry(line, &bank->line_list, siblings) {
-               if (line->offset >= bank->num_lines)
+               if (!line->name || (line->offset >= bank->num_lines))
                        continue;
 
-               if (line->name) {
-                       if (line->offset > max_offset)
-                               max_offset = line->offset;
-
-                       /*
-                        * max_offset can stay at 0 so it's not an indicator
-                        * of whether line names were configured at all.
-                        */
-                       has_line_names = true;
-               }
+               size = max(size, line->offset + 1);
        }
 
-       if (!has_line_names)
-               /*
-                * This is not an error - NULL means, there are no line
-                * names configured.
-                */
-               return NULL;
-
-       *line_names_size = max_offset + 1;
+       return size;
+}
 
-       line_names = kcalloc(*line_names_size, sizeof(*line_names), GFP_KERNEL);
-       if (!line_names)
-               return ERR_PTR(-ENOMEM);
+static void
+gpio_sim_set_line_names(struct gpio_sim_bank *bank, char **line_names)
+{
+       struct gpio_sim_line *line;
 
        list_for_each_entry(line, &bank->line_list, siblings) {
-               if (line->offset >= bank->num_lines)
+               if (!line->name || (line->offset >= bank->num_lines))
                        continue;
 
-               if (line->name && (line->offset <= max_offset))
-                       line_names[line->offset] = line->name;
+               line_names[line->offset] = line->name;
        }
-
-       return line_names;
 }
 
 static void gpio_sim_remove_hogs(struct gpio_sim_device *dev)
@@ -834,7 +815,7 @@ gpio_sim_make_bank_swnode(struct gpio_sim_bank *bank,
                          struct fwnode_handle *parent)
 {
        struct property_entry properties[GPIO_SIM_PROP_MAX];
-       unsigned int prop_idx = 0, line_names_size = 0;
+       unsigned int prop_idx = 0, line_names_size;
        char **line_names __free(kfree) = NULL;
 
        memset(properties, 0, sizeof(properties));
@@ -845,14 +826,19 @@ gpio_sim_make_bank_swnode(struct gpio_sim_bank *bank,
                properties[prop_idx++] = PROPERTY_ENTRY_STRING("gpio-sim,label",
                                                               bank->label);
 
-       line_names = gpio_sim_make_line_names(bank, &line_names_size);
-       if (IS_ERR(line_names))
-               return ERR_CAST(line_names);
+       line_names_size = gpio_sim_get_line_names_size(bank);
+       if (line_names_size) {
+               line_names = kcalloc(line_names_size, sizeof(*line_names),
+                                    GFP_KERNEL);
+               if (!line_names)
+                       return ERR_PTR(-ENOMEM);
+
+               gpio_sim_set_line_names(bank, line_names);
 
-       if (line_names)
                properties[prop_idx++] = PROPERTY_ENTRY_STRING_ARRAY_LEN(
                                                "gpio-line-names",
                                                line_names, line_names_size);
+       }
 
        return fwnode_create_software_node(properties, parent);
 }
index 78f8790..f96d260 100644 (file)
@@ -195,7 +195,7 @@ static int tb10x_gpio_probe(struct platform_device *pdev)
                                handle_edge_irq, IRQ_NOREQUEST, IRQ_NOPROBE,
                                IRQ_GC_INIT_MASK_CACHE);
                if (ret)
-                       return ret;
+                       goto err_remove_domain;
 
                gc = tb10x_gpio->domain->gc->gc[0];
                gc->reg_base                         = tb10x_gpio->base;
@@ -209,6 +209,10 @@ static int tb10x_gpio_probe(struct platform_device *pdev)
        }
 
        return 0;
+
+err_remove_domain:
+       irq_domain_remove(tb10x_gpio->domain);
+       return ret;
 }
 
 static int tb10x_gpio_remove(struct platform_device *pdev)
index bbd9e91..fad9797 100644 (file)
@@ -43,9 +43,10 @@ static int timbgpio_update_bit(struct gpio_chip *gpio, unsigned index,
        unsigned offset, bool enabled)
 {
        struct timbgpio *tgpio = gpiochip_get_data(gpio);
+       unsigned long flags;
        u32 reg;
 
-       spin_lock(&tgpio->lock);
+       spin_lock_irqsave(&tgpio->lock, flags);
        reg = ioread32(tgpio->membase + offset);
 
        if (enabled)
@@ -54,7 +55,7 @@ static int timbgpio_update_bit(struct gpio_chip *gpio, unsigned index,
                reg &= ~(1 << index);
 
        iowrite32(reg, tgpio->membase + offset);
-       spin_unlock(&tgpio->lock);
+       spin_unlock_irqrestore(&tgpio->lock, flags);
 
        return 0;
 }
index ab9ef1c..3caa020 100644 (file)
@@ -136,7 +136,7 @@ config DRM_FBDEV_EMULATION
        bool "Enable legacy fbdev support for your modesetting driver"
        depends on DRM
        select FRAMEBUFFER_CONSOLE_DETECT_PRIMARY if FRAMEBUFFER_CONSOLE
-       default y
+       default FB
        help
          Choose this option if you have a need for the legacy fbdev
          support. Note that this support also provides the linux console
index 73ee14f..dce9e7d 100644 (file)
@@ -1776,7 +1776,7 @@ static ssize_t amdgpu_atombios_get_vbios_version(struct device *dev,
        struct amdgpu_device *adev = drm_to_adev(ddev);
        struct atom_context *ctx = adev->mode_info.atom_context;
 
-       return sysfs_emit(buf, "%s\n", ctx->vbios_ver_str);
+       return sysfs_emit(buf, "%s\n", ctx->vbios_pn);
 }
 
 static DEVICE_ATTR(vbios_version, 0444, amdgpu_atombios_get_vbios_version,
index 30c4f5c..2b83566 100644 (file)
@@ -2093,7 +2093,7 @@ static int amdgpu_device_ip_early_init(struct amdgpu_device *adev)
                adev->flags |= AMD_IS_PX;
 
        if (!(adev->flags & AMD_IS_APU)) {
-               parent = pci_upstream_bridge(adev->pdev);
+               parent = pcie_find_root_port(adev->pdev);
                adev->has_pr3 = parent ? pci_pr3_present(parent) : false;
        }
 
index 9c66d98..7cd0dfa 100644 (file)
@@ -170,6 +170,7 @@ int amdgpu_fru_get_product_info(struct amdgpu_device *adev)
                csum += pia[size - 1];
        if (csum) {
                DRM_ERROR("Bad Product Info Area checksum: 0x%02x", csum);
+               kfree(pia);
                return -EIO;
        }
 
index 937c54f..163445b 100644 (file)
@@ -801,6 +801,7 @@ int amdgpu_ras_feature_enable(struct amdgpu_device *adev,
                                enable ? "enable":"disable",
                                get_ras_block_str(head),
                                amdgpu_ras_is_poison_mode_supported(adev), ret);
+                       kfree(info);
                        return ret;
                }
 
index 8a6cb41..0d3d538 100644 (file)
@@ -216,7 +216,7 @@ static int add_queue_mes(struct device_queue_manager *dqm, struct queue *q,
 
        if (q->wptr_bo) {
                wptr_addr_off = (uint64_t)q->properties.write_ptr & (PAGE_SIZE - 1);
-               queue_input.wptr_mc_addr = ((uint64_t)q->wptr_bo->tbo.resource->start << PAGE_SHIFT) + wptr_addr_off;
+               queue_input.wptr_mc_addr = amdgpu_bo_gpu_offset(q->wptr_bo) + wptr_addr_off;
        }
 
        queue_input.is_kfd_process = 1;
index c6fd34b..868946d 100644 (file)
@@ -6098,8 +6098,6 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
 
        if (recalculate_timing)
                drm_mode_set_crtcinfo(&saved_mode, 0);
-       else if (!old_stream)
-               drm_mode_set_crtcinfo(&mode, 0);
 
        /*
         * If scaling is enabled and refresh rate didn't change
@@ -6661,6 +6659,8 @@ enum drm_mode_status amdgpu_dm_connector_mode_valid(struct drm_connector *connec
                goto fail;
        }
 
+       drm_mode_set_crtcinfo(mode, 0);
+
        stream = create_validate_stream_for_sink(aconnector, mode,
                                                 to_dm_connector_state(connector->state),
                                                 NULL);
index c435f76..5ee8796 100644 (file)
@@ -157,7 +157,7 @@ void dcn20_update_clocks_update_dentist(struct clk_mgr_internal *clk_mgr, struct
                        int32_t N;
                        int32_t j;
 
-                       if (!pipe_ctx->stream)
+                       if (!resource_is_pipe_type(pipe_ctx, OTG_MASTER))
                                continue;
                        /* Virtual encoders don't have this function */
                        if (!stream_enc->funcs->get_fifo_cal_average_level)
@@ -188,7 +188,7 @@ void dcn20_update_clocks_update_dentist(struct clk_mgr_internal *clk_mgr, struct
                        int32_t N;
                        int32_t j;
 
-                       if (!pipe_ctx->stream)
+                       if (!resource_is_pipe_type(pipe_ctx, OTG_MASTER))
                                continue;
                        /* Virtual encoders don't have this function */
                        if (!stream_enc->funcs->get_fifo_cal_average_level)
index 984b529..e9345f6 100644 (file)
@@ -355,7 +355,7 @@ static void dcn32_update_clocks_update_dentist(
                        int32_t N;
                        int32_t j;
 
-                       if (!pipe_ctx->stream)
+                       if (!resource_is_pipe_type(pipe_ctx, OTG_MASTER))
                                continue;
                        /* Virtual encoders don't have this function */
                        if (!stream_enc->funcs->get_fifo_cal_average_level)
@@ -401,7 +401,7 @@ static void dcn32_update_clocks_update_dentist(
                        int32_t N;
                        int32_t j;
 
-                       if (!pipe_ctx->stream)
+                       if (!resource_is_pipe_type(pipe_ctx, OTG_MASTER))
                                continue;
                        /* Virtual encoders don't have this function */
                        if (!stream_enc->funcs->get_fifo_cal_average_level)
index 478281f..2a61575 100644 (file)
@@ -1178,12 +1178,15 @@ void dce110_disable_stream(struct pipe_ctx *pipe_ctx)
                dto_params.otg_inst = tg->inst;
                dto_params.timing = &pipe_ctx->stream->timing;
                dp_hpo_inst = pipe_ctx->stream_res.hpo_dp_stream_enc->inst;
-               dccg->funcs->set_dtbclk_dto(dccg, &dto_params);
-               dccg->funcs->disable_symclk32_se(dccg, dp_hpo_inst);
-               dccg->funcs->set_dpstreamclk(dccg, REFCLK, tg->inst, dp_hpo_inst);
-       } else if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST && dccg->funcs->disable_symclk_se)
+               if (dccg) {
+                       dccg->funcs->set_dtbclk_dto(dccg, &dto_params);
+                       dccg->funcs->disable_symclk32_se(dccg, dp_hpo_inst);
+                       dccg->funcs->set_dpstreamclk(dccg, REFCLK, tg->inst, dp_hpo_inst);
+               }
+       } else if (dccg && dccg->funcs->disable_symclk_se) {
                dccg->funcs->disable_symclk_se(dccg, stream_enc->stream_enc_inst,
                                link_enc->transmitter - TRANSMITTER_UNIPHY_A);
+       }
 
        if (dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) {
                /* TODO: This looks like a bug to me as we are disabling HPO IO when
@@ -2658,11 +2661,11 @@ void dce110_prepare_bandwidth(
        struct clk_mgr *dccg = dc->clk_mgr;
 
        dce110_set_safe_displaymarks(&context->res_ctx, dc->res_pool);
-
-       dccg->funcs->update_clocks(
-                       dccg,
-                       context,
-                       false);
+       if (dccg)
+               dccg->funcs->update_clocks(
+                               dccg,
+                               context,
+                               false);
 }
 
 void dce110_optimize_bandwidth(
@@ -2673,10 +2676,11 @@ void dce110_optimize_bandwidth(
 
        dce110_set_displaymarks(dc, context);
 
-       dccg->funcs->update_clocks(
-                       dccg,
-                       context,
-                       true);
+       if (dccg)
+               dccg->funcs->update_clocks(
+                               dccg,
+                               context,
+                               true);
 }
 
 static void dce110_program_front_end_for_pipe(
index e72f15a..aeadc58 100644 (file)
@@ -2692,8 +2692,6 @@ void dcn20_enable_stream(struct pipe_ctx *pipe_ctx)
        struct dce_hwseq *hws = dc->hwseq;
        unsigned int k1_div = PIXEL_RATE_DIV_NA;
        unsigned int k2_div = PIXEL_RATE_DIV_NA;
-       struct link_encoder *link_enc = link_enc_cfg_get_link_enc(pipe_ctx->stream->link);
-       struct stream_encoder *stream_enc = pipe_ctx->stream_res.stream_enc;
 
        if (dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) {
                if (dc->hwseq->funcs.setup_hpo_hw_control)
@@ -2713,10 +2711,8 @@ void dcn20_enable_stream(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_dtbclk_dto(dccg, &dto_params);
-       } else if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST && dccg->funcs->enable_symclk_se)
-               dccg->funcs->enable_symclk_se(dccg,
-                       stream_enc->stream_enc_inst, link_enc->transmitter - TRANSMITTER_UNIPHY_A);
-
+       } else {
+               }
        if (hws->funcs.calculate_dccg_k1_k2_values && dc->res_pool->dccg->funcs->set_pixel_rate_div) {
                hws->funcs.calculate_dccg_k1_k2_values(pipe_ctx, &k1_div, &k2_div);
 
index 3082da0..1d052f0 100644 (file)
@@ -75,7 +75,7 @@ void mpc32_power_on_blnd_lut(
                if (power_on) {
                        REG_UPDATE(MPCC_MCM_MEM_PWR_CTRL[mpcc_id], MPCC_MCM_1DLUT_MEM_PWR_FORCE, 0);
                        REG_WAIT(MPCC_MCM_MEM_PWR_CTRL[mpcc_id], MPCC_MCM_1DLUT_MEM_PWR_STATE, 0, 1, 5);
-               } else {
+               } else if (!mpc->ctx->dc->debug.disable_mem_low_power) {
                        ASSERT(false);
                        /* TODO: change to mpc
                         *  dpp_base->ctx->dc->optimized_required = true;
index 41147da..8bb2da1 100644 (file)
@@ -2040,6 +2040,7 @@ static int default_attr_update(struct amdgpu_device *adev, struct amdgpu_device_
                case IP_VERSION(11, 0, 0):
                case IP_VERSION(11, 0, 1):
                case IP_VERSION(11, 0, 2):
+               case IP_VERSION(11, 0, 3):
                        *states = ATTR_STATE_SUPPORTED;
                        break;
                default:
index 4bb289f..da2860d 100644 (file)
@@ -2082,36 +2082,41 @@ static int sienna_cichlid_display_disable_memory_clock_switch(struct smu_context
        return ret;
 }
 
+#define MAX(a, b)      ((a) > (b) ? (a) : (b))
+
 static int sienna_cichlid_update_pcie_parameters(struct smu_context *smu,
                                         uint32_t pcie_gen_cap,
                                         uint32_t pcie_width_cap)
 {
        struct smu_11_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context;
        struct smu_11_0_pcie_table *pcie_table = &dpm_context->dpm_tables.pcie_table;
-       u32 smu_pcie_arg;
+       uint8_t *table_member1, *table_member2;
+       uint32_t min_gen_speed, max_gen_speed;
+       uint32_t min_lane_width, max_lane_width;
+       uint32_t smu_pcie_arg;
        int ret, i;
 
-       /* PCIE gen speed and lane width override */
-       if (!amdgpu_device_pcie_dynamic_switching_supported()) {
-               if (pcie_table->pcie_gen[NUM_LINK_LEVELS - 1] < pcie_gen_cap)
-                       pcie_gen_cap = pcie_table->pcie_gen[NUM_LINK_LEVELS - 1];
+       GET_PPTABLE_MEMBER(PcieGenSpeed, &table_member1);
+       GET_PPTABLE_MEMBER(PcieLaneCount, &table_member2);
 
-               if (pcie_table->pcie_lane[NUM_LINK_LEVELS - 1] < pcie_width_cap)
-                       pcie_width_cap = pcie_table->pcie_lane[NUM_LINK_LEVELS - 1];
+       min_gen_speed = MAX(0, table_member1[0]);
+       max_gen_speed = MIN(pcie_gen_cap, table_member1[1]);
+       min_gen_speed = min_gen_speed > max_gen_speed ?
+                       max_gen_speed : min_gen_speed;
+       min_lane_width = MAX(1, table_member2[0]);
+       max_lane_width = MIN(pcie_width_cap, table_member2[1]);
+       min_lane_width = min_lane_width > max_lane_width ?
+                        max_lane_width : min_lane_width;
 
-               /* Force all levels to use the same settings */
-               for (i = 0; i < NUM_LINK_LEVELS; i++) {
-                       pcie_table->pcie_gen[i] = pcie_gen_cap;
-                       pcie_table->pcie_lane[i] = pcie_width_cap;
-               }
+       if (!amdgpu_device_pcie_dynamic_switching_supported()) {
+               pcie_table->pcie_gen[0] = max_gen_speed;
+               pcie_table->pcie_lane[0] = max_lane_width;
        } else {
-               for (i = 0; i < NUM_LINK_LEVELS; i++) {
-                       if (pcie_table->pcie_gen[i] > pcie_gen_cap)
-                               pcie_table->pcie_gen[i] = pcie_gen_cap;
-                       if (pcie_table->pcie_lane[i] > pcie_width_cap)
-                               pcie_table->pcie_lane[i] = pcie_width_cap;
-               }
+               pcie_table->pcie_gen[0] = min_gen_speed;
+               pcie_table->pcie_lane[0] = min_lane_width;
        }
+       pcie_table->pcie_gen[1] = max_gen_speed;
+       pcie_table->pcie_lane[1] = max_lane_width;
 
        for (i = 0; i < NUM_LINK_LEVELS; i++) {
                smu_pcie_arg = (i << 16 |
index 0cb646c..d5c1529 100644 (file)
@@ -38,6 +38,14 @@ static const struct drm_dmi_panel_orientation_data gpd_micropc = {
        .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP,
 };
 
+static const struct drm_dmi_panel_orientation_data gpd_onemix2s = {
+       .width = 1200,
+       .height = 1920,
+       .bios_dates = (const char * const []){ "05/21/2018", "10/26/2018",
+               "03/04/2019", NULL },
+       .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP,
+};
+
 static const struct drm_dmi_panel_orientation_data gpd_pocket = {
        .width = 1200,
        .height = 1920,
@@ -401,6 +409,14 @@ static const struct dmi_system_id orientation_data[] = {
                  DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "LTH17"),
                },
                .driver_data = (void *)&lcd800x1280_rightside_up,
+       }, {    /* One Mix 2S (generic strings, also match on bios date) */
+               .matches = {
+                 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Default string"),
+                 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Default string"),
+                 DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Default string"),
+                 DMI_EXACT_MATCH(DMI_BOARD_NAME, "Default string"),
+               },
+               .driver_data = (void *)&gpd_onemix2s,
        },
        {}
 };
index 6b6d22c..0ba9556 100644 (file)
@@ -198,7 +198,7 @@ static void flush_tlb_invalidate(struct drm_i915_gem_object *obj)
 
        for_each_gt(gt, i915, id) {
                if (!obj->mm.tlb[id])
-                       return;
+                       continue;
 
                intel_gt_invalidate_tlb_full(gt, obj->mm.tlb[id]);
                obj->mm.tlb[id] = 0;
index 8f1633c..73a4a4e 100644 (file)
@@ -100,6 +100,7 @@ int shmem_sg_alloc_table(struct drm_i915_private *i915, struct sg_table *st,
        st->nents = 0;
        for (i = 0; i < page_count; i++) {
                struct folio *folio;
+               unsigned long nr_pages;
                const unsigned int shrink[] = {
                        I915_SHRINK_BOUND | I915_SHRINK_UNBOUND,
                        0,
@@ -150,6 +151,8 @@ int shmem_sg_alloc_table(struct drm_i915_private *i915, struct sg_table *st,
                        }
                } while (1);
 
+               nr_pages = min_t(unsigned long,
+                               folio_nr_pages(folio), page_count - i);
                if (!i ||
                    sg->length >= max_segment ||
                    folio_pfn(folio) != next_pfn) {
@@ -157,13 +160,13 @@ int shmem_sg_alloc_table(struct drm_i915_private *i915, struct sg_table *st,
                                sg = sg_next(sg);
 
                        st->nents++;
-                       sg_set_folio(sg, folio, folio_size(folio), 0);
+                       sg_set_folio(sg, folio, nr_pages * PAGE_SIZE, 0);
                } else {
                        /* XXX: could overflow? */
-                       sg->length += folio_size(folio);
+                       sg->length += nr_pages * PAGE_SIZE;
                }
-               next_pfn = folio_pfn(folio) + folio_nr_pages(folio);
-               i += folio_nr_pages(folio) - 1;
+               next_pfn = folio_pfn(folio) + nr_pages;
+               i += nr_pages - 1;
 
                /* Check that the i965g/gm workaround works. */
                GEM_BUG_ON(gfp & __GFP_DMA32 && next_pfn >= 0x00100000UL);
index a4ff55a..7ad3619 100644 (file)
@@ -271,8 +271,17 @@ int gen12_emit_flush_rcs(struct i915_request *rq, u32 mode)
                if (GRAPHICS_VER_FULL(rq->i915) >= IP_VER(12, 70))
                        bit_group_0 |= PIPE_CONTROL_CCS_FLUSH;
 
+               /*
+                * L3 fabric flush is needed for AUX CCS invalidation
+                * which happens as part of pipe-control so we can
+                * ignore PIPE_CONTROL_FLUSH_L3. Also PIPE_CONTROL_FLUSH_L3
+                * deals with Protected Memory which is not needed for
+                * AUX CCS invalidation and lead to unwanted side effects.
+                */
+               if (mode & EMIT_FLUSH)
+                       bit_group_1 |= PIPE_CONTROL_FLUSH_L3;
+
                bit_group_1 |= PIPE_CONTROL_TILE_CACHE_FLUSH;
-               bit_group_1 |= PIPE_CONTROL_FLUSH_L3;
                bit_group_1 |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH;
                bit_group_1 |= PIPE_CONTROL_DEPTH_CACHE_FLUSH;
                /* Wa_1409600907:tgl,adl-p */
index ee15486..e85d70a 100644 (file)
@@ -558,7 +558,6 @@ static int intel_engine_setup(struct intel_gt *gt, enum intel_engine_id id,
                DRIVER_CAPS(i915)->has_logical_contexts = true;
 
        ewma__engine_latency_init(&engine->latency);
-       seqcount_init(&engine->stats.execlists.lock);
 
        ATOMIC_INIT_NOTIFIER_HEAD(&engine->context_status_notifier);
 
index 8a641bc..3292524 100644 (file)
@@ -3550,6 +3550,8 @@ int intel_execlists_submission_setup(struct intel_engine_cs *engine)
        logical_ring_default_vfuncs(engine);
        logical_ring_default_irqs(engine);
 
+       seqcount_init(&engine->stats.execlists.lock);
+
        if (engine->flags & I915_ENGINE_HAS_RCS_REG_STATE)
                rcs_submission_override(engine);
 
index dd0ed94..da21f27 100644 (file)
@@ -511,20 +511,31 @@ void intel_ggtt_unbind_vma(struct i915_address_space *vm,
        vm->clear_range(vm, vma_res->start, vma_res->vma_size);
 }
 
+/*
+ * Reserve the top of the GuC address space for firmware images. Addresses
+ * beyond GUC_GGTT_TOP in the GuC address space are inaccessible by GuC,
+ * which makes for a suitable range to hold GuC/HuC firmware images if the
+ * size of the GGTT is 4G. However, on a 32-bit platform the size of the GGTT
+ * is limited to 2G, which is less than GUC_GGTT_TOP, but we reserve a chunk
+ * of the same size anyway, which is far more than needed, to keep the logic
+ * in uc_fw_ggtt_offset() simple.
+ */
+#define GUC_TOP_RESERVE_SIZE (SZ_4G - GUC_GGTT_TOP)
+
 static int ggtt_reserve_guc_top(struct i915_ggtt *ggtt)
 {
-       u64 size;
+       u64 offset;
        int ret;
 
        if (!intel_uc_uses_guc(&ggtt->vm.gt->uc))
                return 0;
 
-       GEM_BUG_ON(ggtt->vm.total <= GUC_GGTT_TOP);
-       size = ggtt->vm.total - GUC_GGTT_TOP;
+       GEM_BUG_ON(ggtt->vm.total <= GUC_TOP_RESERVE_SIZE);
+       offset = ggtt->vm.total - GUC_TOP_RESERVE_SIZE;
 
-       ret = i915_gem_gtt_reserve(&ggtt->vm, NULL, &ggtt->uc_fw, size,
-                                  GUC_GGTT_TOP, I915_COLOR_UNEVICTABLE,
-                                  PIN_NOEVICT);
+       ret = i915_gem_gtt_reserve(&ggtt->vm, NULL, &ggtt->uc_fw,
+                                  GUC_TOP_RESERVE_SIZE, offset,
+                                  I915_COLOR_UNEVICTABLE, PIN_NOEVICT);
        if (ret)
                drm_dbg(&ggtt->vm.i915->drm,
                        "Failed to reserve top of GGTT for GuC\n");
index 957d0ae..c378cc7 100644 (file)
@@ -1094,6 +1094,9 @@ __lrc_alloc_state(struct intel_context *ce, struct intel_engine_cs *engine)
                                          I915_BO_ALLOC_PM_VOLATILE);
        if (IS_ERR(obj)) {
                obj = i915_gem_object_create_shmem(engine->i915, context_size);
+               if (IS_ERR(obj))
+                       return ERR_CAST(obj);
+
                /*
                 * Wa_22016122933: For Media version 13.0, all Media GT shared
                 * memory needs to be mapped as WC on CPU side and UC (PAT
@@ -1102,8 +1105,6 @@ __lrc_alloc_state(struct intel_context *ce, struct intel_engine_cs *engine)
                if (intel_gt_needs_wa_22016122933(engine->gt))
                        i915_gem_object_set_cache_coherency(obj, I915_CACHE_NONE);
        }
-       if (IS_ERR(obj))
-               return ERR_CAST(obj);
 
        vma = i915_vma_instance(obj, &engine->gt->ggtt->vm, NULL);
        if (IS_ERR(vma)) {
index b5b7f2f..dc7b40e 100644 (file)
@@ -1433,6 +1433,36 @@ static void guc_timestamp_ping(struct work_struct *wrk)
        int srcu, ret;
 
        /*
+        * Ideally the busyness worker should take a gt pm wakeref because the
+        * worker only needs to be active while gt is awake. However, the
+        * gt_park path cancels the worker synchronously and this complicates
+        * the flow if the worker is also running at the same time. The cancel
+        * waits for the worker and when the worker releases the wakeref, that
+        * would call gt_park and would lead to a deadlock.
+        *
+        * The resolution is to take the global pm wakeref if runtime pm is
+        * already active. If not, we don't need to update the busyness stats as
+        * the stats would already be updated when the gt was parked.
+        *
+        * Note:
+        * - We do not requeue the worker if we cannot take a reference to runtime
+        *   pm since intel_guc_busyness_unpark would requeue the worker in the
+        *   resume path.
+        *
+        * - If the gt was parked longer than time taken for GT timestamp to roll
+        *   over, we ignore those rollovers since we don't care about tracking
+        *   the exact GT time. We only care about roll overs when the gt is
+        *   active and running workloads.
+        *
+        * - There is a window of time between gt_park and runtime suspend,
+        *   where the worker may run. This is acceptable since the worker will
+        *   not find any new data to update busyness.
+        */
+       wakeref = intel_runtime_pm_get_if_active(&gt->i915->runtime_pm);
+       if (!wakeref)
+               return;
+
+       /*
         * Synchronize with gt reset to make sure the worker does not
         * corrupt the engine/guc stats. NB: can't actually block waiting
         * for a reset to complete as the reset requires flushing out
@@ -1440,10 +1470,9 @@ static void guc_timestamp_ping(struct work_struct *wrk)
         */
        ret = intel_gt_reset_trylock(gt, &srcu);
        if (ret)
-               return;
+               goto err_trylock;
 
-       with_intel_runtime_pm(&gt->i915->runtime_pm, wakeref)
-               __update_guc_busyness_stats(guc);
+       __update_guc_busyness_stats(guc);
 
        /* adjust context stats for overflow */
        xa_for_each(&guc->context_lookup, index, ce)
@@ -1452,6 +1481,9 @@ static void guc_timestamp_ping(struct work_struct *wrk)
        intel_gt_reset_unlock(gt, srcu);
 
        guc_enable_busyness_worker(guc);
+
+err_trylock:
+       intel_runtime_pm_put(&gt->i915->runtime_pm, wakeref);
 }
 
 static int guc_action_enable_usage_stats(struct intel_guc *guc)
index 1f65bb3..a8551ce 100644 (file)
@@ -1199,6 +1199,13 @@ int i915_gem_init(struct drm_i915_private *dev_priv)
                        goto err_unlock;
        }
 
+       /*
+        * Register engines early to ensure the engine list is in its final
+        * rb-tree form, lowering the amount of code that has to deal with
+        * the intermediate llist state.
+        */
+       intel_engines_driver_register(dev_priv);
+
        return 0;
 
        /*
@@ -1246,8 +1253,6 @@ err_unlock:
 void i915_gem_driver_register(struct drm_i915_private *i915)
 {
        i915_gem_driver_register__shrinker(i915);
-
-       intel_engines_driver_register(i915);
 }
 
 void i915_gem_driver_unregister(struct drm_i915_private *i915)
index 9913971..25ea765 100644 (file)
@@ -334,6 +334,8 @@ static void meson_encoder_hdmi_hpd_notify(struct drm_bridge *bridge,
                        return;
 
                cec_notifier_set_phys_addr_from_edid(encoder_hdmi->cec_notifier, edid);
+
+               kfree(edid);
        } else
                cec_notifier_phys_addr_invalidate(encoder_hdmi->cec_notifier);
 }
index 30afbec..2edd7bb 100644 (file)
@@ -31,6 +31,7 @@
 
 #include "nouveau_drv.h"
 #include "nouveau_dma.h"
+#include "nouveau_exec.h"
 #include "nouveau_gem.h"
 #include "nouveau_chan.h"
 #include "nouveau_abi16.h"
@@ -183,6 +184,20 @@ nouveau_abi16_fini(struct nouveau_abi16 *abi16)
        cli->abi16 = NULL;
 }
 
+static inline int
+getparam_dma_ib_max(struct nvif_device *device)
+{
+       const struct nvif_mclass dmas[] = {
+               { NV03_CHANNEL_DMA, 0 },
+               { NV10_CHANNEL_DMA, 0 },
+               { NV17_CHANNEL_DMA, 0 },
+               { NV40_CHANNEL_DMA, 0 },
+               {}
+       };
+
+       return nvif_mclass(&device->object, dmas) < 0 ? NV50_DMA_IB_MAX : 0;
+}
+
 int
 nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS)
 {
@@ -247,6 +262,12 @@ nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS)
        case NOUVEAU_GETPARAM_GRAPH_UNITS:
                getparam->value = nvkm_gr_units(gr);
                break;
+       case NOUVEAU_GETPARAM_EXEC_PUSH_MAX: {
+               int ib_max = getparam_dma_ib_max(device);
+
+               getparam->value = nouveau_exec_push_max_from_ib_max(ib_max);
+               break;
+       }
        default:
                NV_PRINTK(dbg, cli, "unknown parameter %lld\n", getparam->param);
                return -EINVAL;
index bb3d6e5..7c97b28 100644 (file)
@@ -257,10 +257,7 @@ static int
 nouveau_channel_ctor(struct nouveau_drm *drm, struct nvif_device *device, bool priv, u64 runm,
                     struct nouveau_channel **pchan)
 {
-       static const struct {
-               s32 oclass;
-               int version;
-       } hosts[] = {
+       const struct nvif_mclass hosts[] = {
                {  AMPERE_CHANNEL_GPFIFO_B, 0 },
                {  AMPERE_CHANNEL_GPFIFO_A, 0 },
                {  TURING_CHANNEL_GPFIFO_A, 0 },
@@ -443,9 +440,11 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart)
        }
 
        /* initialise dma tracking parameters */
-       switch (chan->user.oclass & 0x00ff) {
-       case 0x006b:
-       case 0x006e:
+       switch (chan->user.oclass) {
+       case NV03_CHANNEL_DMA:
+       case NV10_CHANNEL_DMA:
+       case NV17_CHANNEL_DMA:
+       case NV40_CHANNEL_DMA:
                chan->user_put = 0x40;
                chan->user_get = 0x44;
                chan->dma.max = (0x10000 / 4) - 2;
@@ -455,7 +454,7 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart)
                chan->user_get = 0x44;
                chan->user_get_hi = 0x60;
                chan->dma.ib_base =  0x10000 / 4;
-               chan->dma.ib_max  = (0x02000 / 8) - 1;
+               chan->dma.ib_max  = NV50_DMA_IB_MAX;
                chan->dma.ib_put  = 0;
                chan->dma.ib_free = chan->dma.ib_max - chan->dma.ib_put;
                chan->dma.max = chan->dma.ib_base;
index 1744d95..c52cda8 100644 (file)
@@ -49,6 +49,9 @@ void nv50_dma_push(struct nouveau_channel *, u64 addr, u32 length,
 /* Maximum push buffer size. */
 #define NV50_DMA_PUSH_MAX_LENGTH 0x7fffff
 
+/* Maximum IBs per ring. */
+#define NV50_DMA_IB_MAX ((0x02000 / 8) - 1)
+
 /* Object handles - for stuff that's doesn't use handle == oclass. */
 enum {
        NvDmaFB         = 0x80000002,
index 1fe17ff..e73a233 100644 (file)
@@ -189,21 +189,12 @@ u_free(void *addr)
 static inline void *
 u_memcpya(uint64_t user, unsigned int nmemb, unsigned int size)
 {
-       void *mem;
-       void __user *userptr = (void __force __user *)(uintptr_t)user;
+       void __user *userptr = u64_to_user_ptr(user);
+       size_t bytes;
 
-       size *= nmemb;
-
-       mem = kvmalloc(size, GFP_KERNEL);
-       if (!mem)
-               return ERR_PTR(-ENOMEM);
-
-       if (copy_from_user(mem, userptr, size)) {
-               u_free(mem);
-               return ERR_PTR(-EFAULT);
-       }
-
-       return mem;
+       if (unlikely(check_mul_overflow(nmemb, size, &bytes)))
+               return ERR_PTR(-EOVERFLOW);
+       return vmemdup_user(userptr, bytes);
 }
 
 #include <nvif/object.h>
index 19024ce..c1837ba 100644 (file)
@@ -213,7 +213,7 @@ nouveau_exec_job_timeout(struct nouveau_job *job)
 
        nouveau_sched_entity_fini(job->entity);
 
-       return DRM_GPU_SCHED_STAT_ENODEV;
+       return DRM_GPU_SCHED_STAT_NOMINAL;
 }
 
 static struct nouveau_job_ops nouveau_exec_job_ops = {
@@ -379,7 +379,7 @@ nouveau_exec_ioctl_exec(struct drm_device *dev,
        struct nouveau_channel *chan = NULL;
        struct nouveau_exec_job_args args = {};
        struct drm_nouveau_exec *req = data;
-       int ret = 0;
+       int push_max, ret = 0;
 
        if (unlikely(!abi16))
                return -ENOMEM;
@@ -404,9 +404,10 @@ nouveau_exec_ioctl_exec(struct drm_device *dev,
        if (!chan->dma.ib_max)
                return nouveau_abi16_put(abi16, -ENOSYS);
 
-       if (unlikely(req->push_count > NOUVEAU_GEM_MAX_PUSH)) {
+       push_max = nouveau_exec_push_max_from_ib_max(chan->dma.ib_max);
+       if (unlikely(req->push_count > push_max)) {
                NV_PRINTK(err, cli, "pushbuf push count exceeds limit: %d max %d\n",
-                        req->push_count, NOUVEAU_GEM_MAX_PUSH);
+                         req->push_count, push_max);
                return nouveau_abi16_put(abi16, -EINVAL);
        }
 
index 778cacd..5488d33 100644 (file)
@@ -51,4 +51,14 @@ int nouveau_exec_job_init(struct nouveau_exec_job **job,
 int nouveau_exec_ioctl_exec(struct drm_device *dev, void *data,
                            struct drm_file *file_priv);
 
+static inline unsigned int
+nouveau_exec_push_max_from_ib_max(int ib_max)
+{
+       /* Limit the number of IBs per job to half the size of the ring in order
+        * to avoid the ring running dry between submissions and preserve one
+        * more slot for the job's HW fence.
+        */
+       return ib_max > 1 ? ib_max / 2 - 1 : 0;
+}
+
 #endif
index 61d9e70..ca762ea 100644 (file)
@@ -207,7 +207,7 @@ nouveau_fence_context_new(struct nouveau_channel *chan, struct nouveau_fence_cha
 int
 nouveau_fence_emit(struct nouveau_fence *fence)
 {
-       struct nouveau_channel *chan = fence->channel;
+       struct nouveau_channel *chan = unrcu_pointer(fence->channel);
        struct nouveau_fence_chan *fctx = chan->fence;
        struct nouveau_fence_priv *priv = (void*)chan->drm->fence;
        int ret;
index 8821718..3b7ea52 100644 (file)
@@ -375,14 +375,20 @@ nouveau_sched_run_job(struct drm_sched_job *sched_job)
 static enum drm_gpu_sched_stat
 nouveau_sched_timedout_job(struct drm_sched_job *sched_job)
 {
+       struct drm_gpu_scheduler *sched = sched_job->sched;
        struct nouveau_job *job = to_nouveau_job(sched_job);
+       enum drm_gpu_sched_stat stat = DRM_GPU_SCHED_STAT_NOMINAL;
 
-       NV_PRINTK(warn, job->cli, "Job timed out.\n");
+       drm_sched_stop(sched, sched_job);
 
        if (job->ops->timeout)
-               return job->ops->timeout(job);
+               stat = job->ops->timeout(job);
+       else
+               NV_PRINTK(warn, job->cli, "Generic job timeout.\n");
+
+       drm_sched_start(sched, true);
 
-       return DRM_GPU_SCHED_STAT_ENODEV;
+       return stat;
 }
 
 static void
index c1dfbfc..bccb33b 100644 (file)
@@ -118,7 +118,7 @@ void drm_kunit_helper_free_device(struct kunit *test, struct device *dev)
 
        kunit_release_action(test,
                             kunit_action_platform_driver_unregister,
-                            pdev);
+                            &fake_platform_driver);
 }
 EXPORT_SYMBOL_GPL(drm_kunit_helper_free_device);
 
index 186b28d..05d5e7a 100644 (file)
@@ -939,7 +939,7 @@ static void drm_test_mm_insert_range(struct kunit *test)
                KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert_range(test, count, size, 0, max - 1));
                KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert_range(test, count, size, 0, max / 2));
                KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert_range(test, count, size,
-                                                                   max / 2, max / 2));
+                                                                   max / 2, max));
                KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert_range(test, count, size,
                                                                    max / 4 + 1, 3 * max / 4 - 1));
 
index 3c00135..5c51494 100644 (file)
@@ -361,7 +361,6 @@ static void virtio_gpu_complete_submit(struct virtio_gpu_submit *submit)
        submit->buf = NULL;
        submit->buflist = NULL;
        submit->sync_file = NULL;
-       submit->out_fence = NULL;
        submit->out_fence_fd = -1;
 }
 
index 0cea301..790aa90 100644 (file)
@@ -799,6 +799,8 @@ config HID_NVIDIA_SHIELD
        tristate "NVIDIA SHIELD devices"
        depends on USB_HID
        depends on BT_HIDP
+       depends on LEDS_CLASS
+       select POWER_SUPPLY
        help
          Support for NVIDIA SHIELD accessories.
 
index 403506b..b346d68 100644 (file)
@@ -130,6 +130,10 @@ static int holtek_kbd_input_event(struct input_dev *dev, unsigned int type,
                return -ENODEV;
 
        boot_hid = usb_get_intfdata(boot_interface);
+       if (list_empty(&boot_hid->inputs)) {
+               hid_err(hid, "no inputs found\n");
+               return -ENODEV;
+       }
        boot_hid_input = list_first_entry(&boot_hid->inputs,
                struct hid_input, list);
 
index 7e49999..e4d2dfd 100644 (file)
 #define I2C_DEVICE_ID_HP_SPECTRE_X360_13T_AW100        0x29F5
 #define I2C_DEVICE_ID_HP_SPECTRE_X360_14T_EA100_V1     0x2BED
 #define I2C_DEVICE_ID_HP_SPECTRE_X360_14T_EA100_V2     0x2BEE
+#define I2C_DEVICE_ID_HP_ENVY_X360_15_EU0556NG         0x2D02
 
 #define USB_VENDOR_ID_ELECOM           0x056e
 #define USB_DEVICE_ID_ELECOM_BM084     0x0061
index 0235cc1..c8b20d4 100644 (file)
@@ -409,6 +409,8 @@ static const struct hid_device_id hid_battery_quirks[] = {
          HID_BATTERY_QUIRK_IGNORE },
        { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_SPECTRE_X360_14T_EA100_V2),
          HID_BATTERY_QUIRK_IGNORE },
+       { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_ENVY_X360_15_EU0556NG),
+         HID_BATTERY_QUIRK_IGNORE },
        {}
 };
 
index 05f5b5f..a209d51 100644 (file)
@@ -4515,7 +4515,8 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
                        goto hid_hw_init_fail;
        }
 
-       hidpp_connect_event(hidpp);
+       schedule_work(&hidpp->work);
+       flush_work(&hidpp->work);
 
        if (will_restart) {
                /* Reset the HID node state */
@@ -4677,6 +4678,8 @@ static const struct hid_device_id hidpp_devices[] = {
          HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb008) },
        { /* MX Master mouse over Bluetooth */
          HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb012) },
+       { /* M720 Triathlon mouse over Bluetooth */
+         HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb015) },
        { /* MX Ergo trackball over Bluetooth */
          HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb01d) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb01e) },
index 521b2ff..8db4ae0 100644 (file)
@@ -2146,6 +2146,10 @@ static const struct hid_device_id mt_devices[] = {
        /* Synaptics devices */
        { .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT,
                HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
+                       USB_VENDOR_ID_SYNAPTICS, 0xcd7e) },
+
+       { .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT,
+               HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
                        USB_VENDOR_ID_SYNAPTICS, 0xce08) },
 
        { .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT,
index 250f5d2..10468f7 100644 (file)
@@ -2088,7 +2088,9 @@ static int joycon_read_info(struct joycon_ctlr *ctlr)
        struct joycon_input_report *report;
 
        req.subcmd_id = JC_SUBCMD_REQ_DEV_INFO;
+       mutex_lock(&ctlr->output_mutex);
        ret = joycon_send_subcmd(ctlr, &req, 0, HZ);
+       mutex_unlock(&ctlr->output_mutex);
        if (ret) {
                hid_err(ctlr->hdev, "Failed to get joycon info; ret=%d\n", ret);
                return ret;
@@ -2117,6 +2119,85 @@ static int joycon_read_info(struct joycon_ctlr *ctlr)
        return 0;
 }
 
+static int joycon_init(struct hid_device *hdev)
+{
+       struct joycon_ctlr *ctlr = hid_get_drvdata(hdev);
+       int ret = 0;
+
+       mutex_lock(&ctlr->output_mutex);
+       /* if handshake command fails, assume ble pro controller */
+       if ((jc_type_is_procon(ctlr) || jc_type_is_chrggrip(ctlr)) &&
+           !joycon_send_usb(ctlr, JC_USB_CMD_HANDSHAKE, HZ)) {
+               hid_dbg(hdev, "detected USB controller\n");
+               /* set baudrate for improved latency */
+               ret = joycon_send_usb(ctlr, JC_USB_CMD_BAUDRATE_3M, HZ);
+               if (ret) {
+                       hid_err(hdev, "Failed to set baudrate; ret=%d\n", ret);
+                       goto out_unlock;
+               }
+               /* handshake */
+               ret = joycon_send_usb(ctlr, JC_USB_CMD_HANDSHAKE, HZ);
+               if (ret) {
+                       hid_err(hdev, "Failed handshake; ret=%d\n", ret);
+                       goto out_unlock;
+               }
+               /*
+                * Set no timeout (to keep controller in USB mode).
+                * This doesn't send a response, so ignore the timeout.
+                */
+               joycon_send_usb(ctlr, JC_USB_CMD_NO_TIMEOUT, HZ/10);
+       } else if (jc_type_is_chrggrip(ctlr)) {
+               hid_err(hdev, "Failed charging grip handshake\n");
+               ret = -ETIMEDOUT;
+               goto out_unlock;
+       }
+
+       /* get controller calibration data, and parse it */
+       ret = joycon_request_calibration(ctlr);
+       if (ret) {
+               /*
+                * We can function with default calibration, but it may be
+                * inaccurate. Provide a warning, and continue on.
+                */
+               hid_warn(hdev, "Analog stick positions may be inaccurate\n");
+       }
+
+       /* get IMU calibration data, and parse it */
+       ret = joycon_request_imu_calibration(ctlr);
+       if (ret) {
+               /*
+                * We can function with default calibration, but it may be
+                * inaccurate. Provide a warning, and continue on.
+                */
+               hid_warn(hdev, "Unable to read IMU calibration data\n");
+       }
+
+       /* Set the reporting mode to 0x30, which is the full report mode */
+       ret = joycon_set_report_mode(ctlr);
+       if (ret) {
+               hid_err(hdev, "Failed to set report mode; ret=%d\n", ret);
+               goto out_unlock;
+       }
+
+       /* Enable rumble */
+       ret = joycon_enable_rumble(ctlr);
+       if (ret) {
+               hid_err(hdev, "Failed to enable rumble; ret=%d\n", ret);
+               goto out_unlock;
+       }
+
+       /* Enable the IMU */
+       ret = joycon_enable_imu(ctlr);
+       if (ret) {
+               hid_err(hdev, "Failed to enable the IMU; ret=%d\n", ret);
+               goto out_unlock;
+       }
+
+out_unlock:
+       mutex_unlock(&ctlr->output_mutex);
+       return ret;
+}
+
 /* Common handler for parsing inputs */
 static int joycon_ctlr_read_handler(struct joycon_ctlr *ctlr, u8 *data,
                                                              int size)
@@ -2248,85 +2329,19 @@ static int nintendo_hid_probe(struct hid_device *hdev,
 
        hid_device_io_start(hdev);
 
-       /* Initialize the controller */
-       mutex_lock(&ctlr->output_mutex);
-       /* if handshake command fails, assume ble pro controller */
-       if ((jc_type_is_procon(ctlr) || jc_type_is_chrggrip(ctlr)) &&
-           !joycon_send_usb(ctlr, JC_USB_CMD_HANDSHAKE, HZ)) {
-               hid_dbg(hdev, "detected USB controller\n");
-               /* set baudrate for improved latency */
-               ret = joycon_send_usb(ctlr, JC_USB_CMD_BAUDRATE_3M, HZ);
-               if (ret) {
-                       hid_err(hdev, "Failed to set baudrate; ret=%d\n", ret);
-                       goto err_mutex;
-               }
-               /* handshake */
-               ret = joycon_send_usb(ctlr, JC_USB_CMD_HANDSHAKE, HZ);
-               if (ret) {
-                       hid_err(hdev, "Failed handshake; ret=%d\n", ret);
-                       goto err_mutex;
-               }
-               /*
-                * Set no timeout (to keep controller in USB mode).
-                * This doesn't send a response, so ignore the timeout.
-                */
-               joycon_send_usb(ctlr, JC_USB_CMD_NO_TIMEOUT, HZ/10);
-       } else if (jc_type_is_chrggrip(ctlr)) {
-               hid_err(hdev, "Failed charging grip handshake\n");
-               ret = -ETIMEDOUT;
-               goto err_mutex;
-       }
-
-       /* get controller calibration data, and parse it */
-       ret = joycon_request_calibration(ctlr);
+       ret = joycon_init(hdev);
        if (ret) {
-               /*
-                * We can function with default calibration, but it may be
-                * inaccurate. Provide a warning, and continue on.
-                */
-               hid_warn(hdev, "Analog stick positions may be inaccurate\n");
-       }
-
-       /* get IMU calibration data, and parse it */
-       ret = joycon_request_imu_calibration(ctlr);
-       if (ret) {
-               /*
-                * We can function with default calibration, but it may be
-                * inaccurate. Provide a warning, and continue on.
-                */
-               hid_warn(hdev, "Unable to read IMU calibration data\n");
-       }
-
-       /* Set the reporting mode to 0x30, which is the full report mode */
-       ret = joycon_set_report_mode(ctlr);
-       if (ret) {
-               hid_err(hdev, "Failed to set report mode; ret=%d\n", ret);
-               goto err_mutex;
-       }
-
-       /* Enable rumble */
-       ret = joycon_enable_rumble(ctlr);
-       if (ret) {
-               hid_err(hdev, "Failed to enable rumble; ret=%d\n", ret);
-               goto err_mutex;
-       }
-
-       /* Enable the IMU */
-       ret = joycon_enable_imu(ctlr);
-       if (ret) {
-               hid_err(hdev, "Failed to enable the IMU; ret=%d\n", ret);
-               goto err_mutex;
+               hid_err(hdev, "Failed to initialize controller; ret=%d\n", ret);
+               goto err_close;
        }
 
        ret = joycon_read_info(ctlr);
        if (ret) {
                hid_err(hdev, "Failed to retrieve controller info; ret=%d\n",
                        ret);
-               goto err_mutex;
+               goto err_close;
        }
 
-       mutex_unlock(&ctlr->output_mutex);
-
        /* Initialize the leds */
        ret = joycon_leds_create(ctlr);
        if (ret) {
@@ -2352,8 +2367,6 @@ static int nintendo_hid_probe(struct hid_device *hdev,
        hid_dbg(hdev, "probe - success\n");
        return 0;
 
-err_mutex:
-       mutex_unlock(&ctlr->output_mutex);
 err_close:
        hid_hw_close(hdev);
 err_stop:
@@ -2383,6 +2396,20 @@ static void nintendo_hid_remove(struct hid_device *hdev)
        hid_hw_stop(hdev);
 }
 
+#ifdef CONFIG_PM
+
+static int nintendo_hid_resume(struct hid_device *hdev)
+{
+       int ret = joycon_init(hdev);
+
+       if (ret)
+               hid_err(hdev, "Failed to restore controller after resume");
+
+       return ret;
+}
+
+#endif
+
 static const struct hid_device_id nintendo_hid_devices[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_NINTENDO,
                         USB_DEVICE_ID_NINTENDO_PROCON) },
@@ -2404,6 +2431,10 @@ static struct hid_driver nintendo_hid_driver = {
        .probe          = nintendo_hid_probe,
        .remove         = nintendo_hid_remove,
        .raw_event      = nintendo_hid_event,
+
+#ifdef CONFIG_PM
+       .resume         = nintendo_hid_resume,
+#endif
 };
 module_hid_driver(nintendo_hid_driver);
 
index 9a3576d..c463e54 100644 (file)
@@ -801,7 +801,7 @@ static inline int thunderstrike_led_create(struct thunderstrike *ts)
        led->name = devm_kasprintf(&ts->base.hdev->dev, GFP_KERNEL,
                                   "thunderstrike%d:blue:led", ts->id);
        led->max_brightness = 1;
-       led->flags = LED_CORE_SUSPENDRESUME;
+       led->flags = LED_CORE_SUSPENDRESUME | LED_RETAIN_AT_SHUTDOWN;
        led->brightness_get = &thunderstrike_led_get_brightness;
        led->brightness_set = &thunderstrike_led_set_brightness;
 
@@ -1058,7 +1058,7 @@ static int shield_probe(struct hid_device *hdev, const struct hid_device_id *id)
        ret = hid_hw_start(hdev, HID_CONNECT_HIDINPUT);
        if (ret) {
                hid_err(hdev, "Failed to start HID device\n");
-               goto err_haptics;
+               goto err_ts_create;
        }
 
        ret = hid_hw_open(hdev);
@@ -1073,9 +1073,12 @@ static int shield_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
 err_stop:
        hid_hw_stop(hdev);
-err_haptics:
+err_ts_create:
+       power_supply_unregister(ts->base.battery_dev.psy);
        if (ts->haptics_dev)
                input_unregister_device(ts->haptics_dev);
+       led_classdev_unregister(&ts->led_dev);
+       ida_free(&thunderstrike_ida, ts->id);
        return ret;
 }
 
index dd94206..ebc0aa4 100644 (file)
@@ -2155,6 +2155,8 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
        return ret;
 
 err:
+       usb_free_urb(sc->ghl_urb);
+
        hid_hw_stop(hdev);
        return ret;
 }
index 43d2cf7..b3edadf 100644 (file)
@@ -390,7 +390,7 @@ static int steelseries_headset_arctis_1_fetch_battery(struct hid_device *hdev)
        ret = hid_hw_raw_request(hdev, arctis_1_battery_request[0],
                                 write_buf, sizeof(arctis_1_battery_request),
                                 HID_OUTPUT_REPORT, HID_REQ_SET_REPORT);
-       if (ret < sizeof(arctis_1_battery_request)) {
+       if (ret < (int)sizeof(arctis_1_battery_request)) {
                hid_err(hdev, "hid_hw_raw_request() failed with %d\n", ret);
                ret = -ENODATA;
        }
index 9601c06..2735cd5 100644 (file)
@@ -998,45 +998,29 @@ static int i2c_hid_core_resume(struct i2c_hid *ihid)
        return hid_driver_reset_resume(hid);
 }
 
-/**
- * __do_i2c_hid_core_initial_power_up() - First time power up of the i2c-hid device.
- * @ihid: The ihid object created during probe.
- *
- * This function is called at probe time.
- *
- * The initial power on is where we do some basic validation that the device
- * exists, where we fetch the HID descriptor, and where we create the actual
- * HID devices.
- *
- * Return: 0 or error code.
+/*
+ * Check that the device exists and parse the HID descriptor.
  */
-static int __do_i2c_hid_core_initial_power_up(struct i2c_hid *ihid)
+static int __i2c_hid_core_probe(struct i2c_hid *ihid)
 {
        struct i2c_client *client = ihid->client;
        struct hid_device *hid = ihid->hid;
        int ret;
 
-       ret = i2c_hid_core_power_up(ihid);
-       if (ret)
-               return ret;
-
        /* Make sure there is something at this address */
        ret = i2c_smbus_read_byte(client);
        if (ret < 0) {
                i2c_hid_dbg(ihid, "nothing at this address: %d\n", ret);
-               ret = -ENXIO;
-               goto err;
+               return -ENXIO;
        }
 
        ret = i2c_hid_fetch_hid_descriptor(ihid);
        if (ret < 0) {
                dev_err(&client->dev,
                        "Failed to fetch the HID Descriptor\n");
-               goto err;
+               return ret;
        }
 
-       enable_irq(client->irq);
-
        hid->version = le16_to_cpu(ihid->hdesc.bcdVersion);
        hid->vendor = le16_to_cpu(ihid->hdesc.wVendorID);
        hid->product = le16_to_cpu(ihid->hdesc.wProductID);
@@ -1050,17 +1034,49 @@ static int __do_i2c_hid_core_initial_power_up(struct i2c_hid *ihid)
 
        ihid->quirks = i2c_hid_lookup_quirk(hid->vendor, hid->product);
 
+       return 0;
+}
+
+static int i2c_hid_core_register_hid(struct i2c_hid *ihid)
+{
+       struct i2c_client *client = ihid->client;
+       struct hid_device *hid = ihid->hid;
+       int ret;
+
+       enable_irq(client->irq);
+
        ret = hid_add_device(hid);
        if (ret) {
                if (ret != -ENODEV)
                        hid_err(client, "can't add hid device: %d\n", ret);
-               goto err;
+               disable_irq(client->irq);
+               return ret;
        }
 
        return 0;
+}
+
+static int i2c_hid_core_probe_panel_follower(struct i2c_hid *ihid)
+{
+       int ret;
+
+       ret = i2c_hid_core_power_up(ihid);
+       if (ret)
+               return ret;
 
-err:
+       ret = __i2c_hid_core_probe(ihid);
+       if (ret)
+               goto err_power_down;
+
+       ret = i2c_hid_core_register_hid(ihid);
+       if (ret)
+               goto err_power_down;
+
+       return 0;
+
+err_power_down:
        i2c_hid_core_power_down(ihid);
+
        return ret;
 }
 
@@ -1077,7 +1093,7 @@ static void ihid_core_panel_prepare_work(struct work_struct *work)
         * steps.
         */
        if (!hid->version)
-               ret = __do_i2c_hid_core_initial_power_up(ihid);
+               ret = i2c_hid_core_probe_panel_follower(ihid);
        else
                ret = i2c_hid_core_resume(ihid);
 
@@ -1136,7 +1152,6 @@ static int i2c_hid_core_register_panel_follower(struct i2c_hid *ihid)
        struct device *dev = &ihid->client->dev;
        int ret;
 
-       ihid->is_panel_follower = true;
        ihid->panel_follower.funcs = &i2c_hid_core_panel_follower_funcs;
 
        /*
@@ -1156,30 +1171,6 @@ static int i2c_hid_core_register_panel_follower(struct i2c_hid *ihid)
        return 0;
 }
 
-static int i2c_hid_core_initial_power_up(struct i2c_hid *ihid)
-{
-       /*
-        * If we're a panel follower, we'll register and do our initial power
-        * up when the panel turns on; otherwise we do it right away.
-        */
-       if (drm_is_panel_follower(&ihid->client->dev))
-               return i2c_hid_core_register_panel_follower(ihid);
-       else
-               return __do_i2c_hid_core_initial_power_up(ihid);
-}
-
-static void i2c_hid_core_final_power_down(struct i2c_hid *ihid)
-{
-       /*
-        * If we're a follower, the act of unfollowing will cause us to be
-        * powered down. Otherwise we need to manually do it.
-        */
-       if (ihid->is_panel_follower)
-               drm_panel_remove_follower(&ihid->panel_follower);
-       else
-               i2c_hid_core_suspend(ihid, true);
-}
-
 int i2c_hid_core_probe(struct i2c_client *client, struct i2chid_ops *ops,
                       u16 hid_descriptor_address, u32 quirks)
 {
@@ -1211,6 +1202,7 @@ int i2c_hid_core_probe(struct i2c_client *client, struct i2chid_ops *ops,
        ihid->ops = ops;
        ihid->client = client;
        ihid->wHIDDescRegister = cpu_to_le16(hid_descriptor_address);
+       ihid->is_panel_follower = drm_is_panel_follower(&client->dev);
 
        init_waitqueue_head(&ihid->wait);
        mutex_init(&ihid->reset_lock);
@@ -1224,14 +1216,10 @@ int i2c_hid_core_probe(struct i2c_client *client, struct i2chid_ops *ops,
                return ret;
        device_enable_async_suspend(&client->dev);
 
-       ret = i2c_hid_init_irq(client);
-       if (ret < 0)
-               goto err_buffers_allocated;
-
        hid = hid_allocate_device();
        if (IS_ERR(hid)) {
                ret = PTR_ERR(hid);
-               goto err_irq;
+               goto err_free_buffers;
        }
 
        ihid->hid = hid;
@@ -1242,19 +1230,42 @@ int i2c_hid_core_probe(struct i2c_client *client, struct i2chid_ops *ops,
        hid->bus = BUS_I2C;
        hid->initial_quirks = quirks;
 
-       ret = i2c_hid_core_initial_power_up(ihid);
+       /* Power on and probe unless device is a panel follower. */
+       if (!ihid->is_panel_follower) {
+               ret = i2c_hid_core_power_up(ihid);
+               if (ret < 0)
+                       goto err_destroy_device;
+
+               ret = __i2c_hid_core_probe(ihid);
+               if (ret < 0)
+                       goto err_power_down;
+       }
+
+       ret = i2c_hid_init_irq(client);
+       if (ret < 0)
+               goto err_power_down;
+
+       /*
+        * If we're a panel follower, we'll register when the panel turns on;
+        * otherwise we do it right away.
+        */
+       if (ihid->is_panel_follower)
+               ret = i2c_hid_core_register_panel_follower(ihid);
+       else
+               ret = i2c_hid_core_register_hid(ihid);
        if (ret)
-               goto err_mem_free;
+               goto err_free_irq;
 
        return 0;
 
-err_mem_free:
-       hid_destroy_device(hid);
-
-err_irq:
+err_free_irq:
        free_irq(client->irq, ihid);
-
-err_buffers_allocated:
+err_power_down:
+       if (!ihid->is_panel_follower)
+               i2c_hid_core_power_down(ihid);
+err_destroy_device:
+       hid_destroy_device(hid);
+err_free_buffers:
        i2c_hid_free_buffers(ihid);
 
        return ret;
@@ -1266,7 +1277,14 @@ void i2c_hid_core_remove(struct i2c_client *client)
        struct i2c_hid *ihid = i2c_get_clientdata(client);
        struct hid_device *hid;
 
-       i2c_hid_core_final_power_down(ihid);
+       /*
+        * If we're a follower, the act of unfollowing will cause us to be
+        * powered down. Otherwise we need to manually do it.
+        */
+       if (ihid->is_panel_follower)
+               drm_panel_remove_follower(&ihid->panel_follower);
+       else
+               i2c_hid_core_suspend(ihid, true);
 
        hid = ihid->hid;
        hid_destroy_device(hid);
index 55cb250..710fda5 100644 (file)
@@ -133,6 +133,14 @@ static int enable_gpe(struct device *dev)
        }
        wakeup = &adev->wakeup;
 
+       /*
+        * Call acpi_disable_gpe(), so that reference count
+        * gpe_event_info->runtime_count doesn't overflow.
+        * When gpe_event_info->runtime_count = 0, the call
+        * to acpi_disable_gpe() simply return.
+        */
+       acpi_disable_gpe(wakeup->gpe_device, wakeup->gpe_number);
+
        acpi_sts = acpi_enable_gpe(wakeup->gpe_device, wakeup->gpe_number);
        if (ACPI_FAILURE(acpi_sts)) {
                dev_err(dev, "enable ose_gpe failed\n");
index 02a7124..b5b81bd 100644 (file)
@@ -1910,6 +1910,10 @@ static umode_t nct6775_in_is_visible(struct kobject *kobj,
        struct device *dev = kobj_to_dev(kobj);
        struct nct6775_data *data = dev_get_drvdata(dev);
        int in = index / 5;     /* voltage index */
+       int nr = index % 5;     /* attribute index */
+
+       if (nr == 1 && data->ALARM_BITS[in] == -1)
+               return 0;
 
        if (!(data->have_in & BIT(in)))
                return 0;
index cdd8c67..affcfb2 100644 (file)
@@ -441,8 +441,25 @@ err_release_lock:
 
 void __i2c_dw_disable(struct dw_i2c_dev *dev)
 {
+       unsigned int raw_intr_stats;
+       unsigned int enable;
        int timeout = 100;
+       bool abort_needed;
        unsigned int status;
+       int ret;
+
+       regmap_read(dev->map, DW_IC_RAW_INTR_STAT, &raw_intr_stats);
+       regmap_read(dev->map, DW_IC_ENABLE, &enable);
+
+       abort_needed = raw_intr_stats & DW_IC_INTR_MST_ON_HOLD;
+       if (abort_needed) {
+               regmap_write(dev->map, DW_IC_ENABLE, enable | DW_IC_ENABLE_ABORT);
+               ret = regmap_read_poll_timeout(dev->map, DW_IC_ENABLE, enable,
+                                              !(enable & DW_IC_ENABLE_ABORT), 10,
+                                              100);
+               if (ret)
+                       dev_err(dev->dev, "timeout while trying to abort current transfer\n");
+       }
 
        do {
                __i2c_dw_disable_nowait(dev);
index cf4f684..a7f6f3e 100644 (file)
@@ -98,6 +98,7 @@
 #define DW_IC_INTR_START_DET                   BIT(10)
 #define DW_IC_INTR_GEN_CALL                    BIT(11)
 #define DW_IC_INTR_RESTART_DET                 BIT(12)
+#define DW_IC_INTR_MST_ON_HOLD                 BIT(13)
 
 #define DW_IC_INTR_DEFAULT_MASK                        (DW_IC_INTR_RX_FULL | \
                                                 DW_IC_INTR_TX_ABRT | \
                                                 DW_IC_INTR_RX_UNDER | \
                                                 DW_IC_INTR_RD_REQ)
 
+#define DW_IC_ENABLE_ABORT                     BIT(1)
+
 #define DW_IC_STATUS_ACTIVITY                  BIT(0)
 #define DW_IC_STATUS_TFE                       BIT(2)
 #define DW_IC_STATUS_RFNE                      BIT(3)
index 73ae064..1d85525 100644 (file)
@@ -1754,6 +1754,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
                "SMBus I801 adapter at %04lx", priv->smba);
        err = i2c_add_adapter(&priv->adapter);
        if (err) {
+               platform_device_unregister(priv->tco_pdev);
                i801_acpi_remove(priv);
                return err;
        }
index 495a8b5..ae4bae6 100644 (file)
@@ -694,6 +694,7 @@ static void npcm_i2c_callback(struct npcm_i2c *bus,
 {
        struct i2c_msg *msgs;
        int msgs_num;
+       bool do_complete = false;
 
        msgs = bus->msgs;
        msgs_num = bus->msgs_num;
@@ -722,23 +723,17 @@ static void npcm_i2c_callback(struct npcm_i2c *bus,
                                 msgs[1].flags & I2C_M_RD)
                                msgs[1].len = info;
                }
-               if (completion_done(&bus->cmd_complete) == false)
-                       complete(&bus->cmd_complete);
-       break;
-
+               do_complete = true;
+               break;
        case I2C_NACK_IND:
                /* MASTER transmit got a NACK before tx all bytes */
                bus->cmd_err = -ENXIO;
-               if (bus->master_or_slave == I2C_MASTER)
-                       complete(&bus->cmd_complete);
-
+               do_complete = true;
                break;
        case I2C_BUS_ERR_IND:
                /* Bus error */
                bus->cmd_err = -EAGAIN;
-               if (bus->master_or_slave == I2C_MASTER)
-                       complete(&bus->cmd_complete);
-
+               do_complete = true;
                break;
        case I2C_WAKE_UP_IND:
                /* I2C wake up */
@@ -752,6 +747,8 @@ static void npcm_i2c_callback(struct npcm_i2c *bus,
        if (bus->slave)
                bus->master_or_slave = I2C_SLAVE;
 #endif
+       if (do_complete)
+               complete(&bus->cmd_complete);
 }
 
 static u8 npcm_i2c_fifo_usage(struct npcm_i2c *bus)
index b3bb977..71391b5 100644 (file)
@@ -710,7 +710,7 @@ static irqreturn_t xiic_process(int irq, void *dev_id)
                 * reset the IP instead of just flush fifos
                 */
                ret = xiic_reinit(i2c);
-               if (!ret)
+               if (ret < 0)
                        dev_dbg(i2c->adap.dev.parent, "reinit failed\n");
 
                if (i2c->rx_msg) {
index 313904b..57ff09f 100644 (file)
@@ -341,7 +341,7 @@ int i2c_mux_add_adapter(struct i2c_mux_core *muxc,
                priv->adap.lock_ops = &i2c_parent_lock_ops;
 
        /* Sanity check on class */
-       if (i2c_mux_parent_classes(parent) & class)
+       if (i2c_mux_parent_classes(parent) & class & ~I2C_CLASS_DEPRECATED)
                dev_err(&parent->dev,
                        "Segment %d behind mux can't share classes with ancestors\n",
                        chan_id);
index a3a122f..22f2280 100644 (file)
@@ -243,6 +243,10 @@ static int i2c_demux_pinctrl_probe(struct platform_device *pdev)
 
                props[i].name = devm_kstrdup(&pdev->dev, "status", GFP_KERNEL);
                props[i].value = devm_kstrdup(&pdev->dev, "ok", GFP_KERNEL);
+               if (!props[i].name || !props[i].value) {
+                       err = -ENOMEM;
+                       goto err_rollback;
+               }
                props[i].length = 3;
 
                of_changeset_init(&priv->chan[i].chgset);
index 5d5cbe0..5ca03bd 100644 (file)
@@ -105,8 +105,10 @@ static int i2c_mux_gpio_probe_fw(struct gpiomux *mux,
 
                } else if (is_acpi_node(child)) {
                        rc = acpi_get_local_address(ACPI_HANDLE_FWNODE(child), values + i);
-                       if (rc)
+                       if (rc) {
+                               fwnode_handle_put(child);
                                return dev_err_probe(dev, rc, "Cannot get address\n");
+                       }
                }
 
                i++;
index c343edf..1e2cd7c 100644 (file)
@@ -4968,7 +4968,7 @@ static int cma_iboe_join_multicast(struct rdma_id_private *id_priv,
        int err = 0;
        struct sockaddr *addr = (struct sockaddr *)&mc->addr;
        struct net_device *ndev = NULL;
-       struct ib_sa_multicast ib;
+       struct ib_sa_multicast ib = {};
        enum ib_gid_type gid_type;
        bool send_only;
 
index 7b68b3e..f2fb2d8 100644 (file)
@@ -217,7 +217,7 @@ static int make_cma_ports(struct cma_dev_group *cma_dev_group,
                return -ENOMEM;
 
        for (i = 0; i < ports_num; i++) {
-               char port_str[10];
+               char port_str[11];
 
                ports[i].port_num = i + 1;
                snprintf(port_str, sizeof(port_str), "%u", i + 1);
index d5d3e4f..6d1dbc9 100644 (file)
@@ -2529,6 +2529,7 @@ static const struct rdma_nl_cbs nldev_cb_table[RDMA_NLDEV_NUM_OPS] = {
        },
        [RDMA_NLDEV_CMD_SYS_SET] = {
                .doit = nldev_set_sys_set_doit,
+               .flags = RDMA_NL_ADMIN_PERM,
        },
        [RDMA_NLDEV_CMD_STAT_SET] = {
                .doit = nldev_stat_set_doit,
index bf800f8..495d5a5 100644 (file)
@@ -546,7 +546,7 @@ static ssize_t verify_hdr(struct ib_uverbs_cmd_hdr *hdr,
        if (hdr->in_words * 4 != count)
                return -EINVAL;
 
-       if (count < method_elm->req_size + sizeof(hdr)) {
+       if (count < method_elm->req_size + sizeof(*hdr)) {
                /*
                 * rdma-core v18 and v19 have a bug where they send DESTROY_CQ
                 * with a 16 byte write instead of 24. Old kernels didn't
index 0848c2c..faa88d1 100644 (file)
@@ -910,6 +910,10 @@ int bnxt_re_destroy_qp(struct ib_qp *ib_qp, struct ib_udata *udata)
        list_del(&qp->list);
        mutex_unlock(&rdev->qp_lock);
        atomic_dec(&rdev->stats.res.qp_count);
+       if (qp->qplib_qp.type == CMDQ_CREATE_QP_TYPE_RC)
+               atomic_dec(&rdev->stats.res.rc_qp_count);
+       else if (qp->qplib_qp.type == CMDQ_CREATE_QP_TYPE_UD)
+               atomic_dec(&rdev->stats.res.ud_qp_count);
 
        ib_umem_release(qp->rumem);
        ib_umem_release(qp->sumem);
index c8c4017..e47b4ca 100644 (file)
@@ -665,7 +665,6 @@ static int bnxt_qplib_process_qp_event(struct bnxt_qplib_rcfw *rcfw,
                blocked = cookie & RCFW_CMD_IS_BLOCKING;
                cookie &= RCFW_MAX_COOKIE_VALUE;
                crsqe = &rcfw->crsqe_tbl[cookie];
-               crsqe->is_in_used = false;
 
                if (WARN_ONCE(test_bit(FIRMWARE_STALL_DETECTED,
                                       &rcfw->cmdq.flags),
@@ -681,8 +680,14 @@ static int bnxt_qplib_process_qp_event(struct bnxt_qplib_rcfw *rcfw,
                        atomic_dec(&rcfw->timeout_send);
 
                if (crsqe->is_waiter_alive) {
-                       if (crsqe->resp)
+                       if (crsqe->resp) {
                                memcpy(crsqe->resp, qp_event, sizeof(*qp_event));
+                               /* Insert write memory barrier to ensure that
+                                * response data is copied before clearing the
+                                * flags
+                                */
+                               smp_wmb();
+                       }
                        if (!blocked)
                                wait_cmds++;
                }
@@ -694,6 +699,8 @@ static int bnxt_qplib_process_qp_event(struct bnxt_qplib_rcfw *rcfw,
                if (!is_waiter_alive)
                        crsqe->resp = NULL;
 
+               crsqe->is_in_used = false;
+
                hwq->cons += req_size;
 
                /* This is a case to handle below scenario -
index ced615b..040ba22 100644 (file)
@@ -1965,6 +1965,9 @@ static int send_fw_act_open_req(struct c4iw_ep *ep, unsigned int atid)
        int win;
 
        skb = get_skb(NULL, sizeof(*req), GFP_KERNEL);
+       if (!skb)
+               return -ENOMEM;
+
        req = __skb_put_zero(skb, sizeof(*req));
        req->op_compl = htonl(WR_OP_V(FW_OFLD_CONNECTION_WR));
        req->len16_pkd = htonl(FW_WR_LEN16_V(DIV_ROUND_UP(sizeof(*req), 16)));
index dcccb60..c317947 100644 (file)
@@ -133,8 +133,8 @@ static int create_qp_cmd(struct erdma_ucontext *uctx, struct erdma_qp *qp)
 static int regmr_cmd(struct erdma_dev *dev, struct erdma_mr *mr)
 {
        struct erdma_pd *pd = to_epd(mr->ibmr.pd);
+       u32 mtt_level = ERDMA_MR_MTT_0LEVEL;
        struct erdma_cmdq_reg_mr_req req;
-       u32 mtt_level;
 
        erdma_cmdq_build_reqhdr(&req.hdr, CMDQ_SUBMOD_RDMA, CMDQ_OPCODE_REG_MR);
 
@@ -147,10 +147,9 @@ static int regmr_cmd(struct erdma_dev *dev, struct erdma_mr *mr)
                        req.phy_addr[0] = sg_dma_address(mr->mem.mtt->sglist);
                        mtt_level = mr->mem.mtt->level;
                }
-       } else {
+       } else if (mr->type != ERDMA_MR_TYPE_DMA) {
                memcpy(req.phy_addr, mr->mem.mtt->buf,
                       MTT_SIZE(mr->mem.page_cnt));
-               mtt_level = ERDMA_MR_MTT_0LEVEL;
        }
 
        req.cfg0 = FIELD_PREP(ERDMA_CMD_MR_VALID_MASK, mr->valid) |
@@ -655,7 +654,7 @@ static struct erdma_mtt *erdma_create_scatter_mtt(struct erdma_dev *dev,
 
        mtt = kzalloc(sizeof(*mtt), GFP_KERNEL);
        if (!mtt)
-               return NULL;
+               return ERR_PTR(-ENOMEM);
 
        mtt->size = ALIGN(size, PAGE_SIZE);
        mtt->buf = vzalloc(mtt->size);
index 24ee79a..88f534c 100644 (file)
@@ -223,7 +223,7 @@ void del_sysfs_port_mcg_attr(struct mlx4_ib_dev *device, int port_num,
 static int add_port_entries(struct mlx4_ib_dev *device, int port_num)
 {
        int i;
-       char buff[11];
+       char buff[12];
        struct mlx4_ib_iov_port *port = NULL;
        int ret = 0 ;
        struct ib_port_attr attr;
index 1e419e0..520034a 100644 (file)
@@ -2470,8 +2470,8 @@ destroy_res:
        mlx5_steering_anchor_destroy_res(ft_prio);
 put_flow_table:
        put_flow_table(dev, ft_prio, true);
-       mutex_unlock(&dev->flow_db->lock);
 free_obj:
+       mutex_unlock(&dev->flow_db->lock);
        kfree(obj);
 
        return err;
index aed5cde..555629b 100644 (file)
@@ -2084,7 +2084,7 @@ static inline char *mmap_cmd2str(enum mlx5_ib_mmap_cmd cmd)
        case MLX5_IB_MMAP_DEVICE_MEM:
                return "Device Memory";
        default:
-               return NULL;
+               return "Unknown";
        }
 }
 
index 3e345ef..8a3762d 100644 (file)
@@ -301,7 +301,8 @@ static int get_mkc_octo_size(unsigned int access_mode, unsigned int ndescs)
 
 static void set_cache_mkc(struct mlx5_cache_ent *ent, void *mkc)
 {
-       set_mkc_access_pd_addr_fields(mkc, 0, 0, ent->dev->umrc.pd);
+       set_mkc_access_pd_addr_fields(mkc, ent->rb_key.access_flags, 0,
+                                     ent->dev->umrc.pd);
        MLX5_SET(mkc, mkc, free, 1);
        MLX5_SET(mkc, mkc, umr_en, 1);
        MLX5_SET(mkc, mkc, access_mode_1_0, ent->rb_key.access_mode & 0x3);
@@ -1024,19 +1025,26 @@ void mlx5_mkey_cache_cleanup(struct mlx5_ib_dev *dev)
        if (!dev->cache.wq)
                return;
 
-       cancel_delayed_work_sync(&dev->cache.remove_ent_dwork);
        mutex_lock(&dev->cache.rb_lock);
        for (node = rb_first(root); node; node = rb_next(node)) {
                ent = rb_entry(node, struct mlx5_cache_ent, node);
                xa_lock_irq(&ent->mkeys);
                ent->disabled = true;
                xa_unlock_irq(&ent->mkeys);
-               cancel_delayed_work_sync(&ent->dwork);
        }
+       mutex_unlock(&dev->cache.rb_lock);
+
+       /*
+        * After all entries are disabled and will not reschedule on WQ,
+        * flush it and all async commands.
+        */
+       flush_workqueue(dev->cache.wq);
 
        mlx5_mkey_cache_debugfs_cleanup(dev);
        mlx5_cmd_cleanup_async_ctx(&dev->async_ctx);
 
+       /* At this point all entries are disabled and have no concurrent work. */
+       mutex_lock(&dev->cache.rb_lock);
        node = rb_first(root);
        while (node) {
                ent = rb_entry(node, struct mlx5_cache_ent, node);
index a260517..43e7760 100644 (file)
@@ -976,6 +976,7 @@ static void siw_accept_newconn(struct siw_cep *cep)
                        siw_cep_put(cep);
                        new_cep->listen_cep = NULL;
                        if (rv) {
+                               siw_cancel_mpatimer(new_cep);
                                siw_cep_set_free(new_cep);
                                goto error;
                        }
@@ -1100,9 +1101,12 @@ static void siw_cm_work_handler(struct work_struct *w)
                                /*
                                 * Socket close before MPA request received.
                                 */
-                               siw_dbg_cep(cep, "no mpareq: drop listener\n");
-                               siw_cep_put(cep->listen_cep);
-                               cep->listen_cep = NULL;
+                               if (cep->listen_cep) {
+                                       siw_dbg_cep(cep,
+                                               "no mpareq: drop listener\n");
+                                       siw_cep_put(cep->listen_cep);
+                                       cep->listen_cep = NULL;
+                               }
                        }
                }
                release_cep = 1;
@@ -1227,7 +1231,11 @@ static void siw_cm_llp_data_ready(struct sock *sk)
        if (!cep)
                goto out;
 
-       siw_dbg_cep(cep, "state: %d\n", cep->state);
+       siw_dbg_cep(cep, "cep state: %d, socket state %d\n",
+                   cep->state, sk->sk_state);
+
+       if (sk->sk_state != TCP_ESTABLISHED)
+               goto out;
 
        switch (cep->state) {
        case SIW_EPSTATE_RDMA_MODE:
index 1574218..2916e77 100644 (file)
@@ -2784,7 +2784,6 @@ static int srp_abort(struct scsi_cmnd *scmnd)
        u32 tag;
        u16 ch_idx;
        struct srp_rdma_ch *ch;
-       int ret;
 
        shost_printk(KERN_ERR, target->scsi_host, "SRP abort called\n");
 
@@ -2798,19 +2797,14 @@ static int srp_abort(struct scsi_cmnd *scmnd)
        shost_printk(KERN_ERR, target->scsi_host,
                     "Sending SRP abort for tag %#x\n", tag);
        if (srp_send_tsk_mgmt(ch, tag, scmnd->device->lun,
-                             SRP_TSK_ABORT_TASK, NULL) == 0)
-               ret = SUCCESS;
-       else if (target->rport->state == SRP_RPORT_LOST)
-               ret = FAST_IO_FAIL;
-       else
-               ret = FAILED;
-       if (ret == SUCCESS) {
+                             SRP_TSK_ABORT_TASK, NULL) == 0) {
                srp_free_req(ch, req, scmnd, 0);
-               scmnd->result = DID_ABORT << 16;
-               scsi_done(scmnd);
+               return SUCCESS;
        }
+       if (target->rport->state == SRP_RPORT_LOST)
+               return FAST_IO_FAIL;
 
-       return ret;
+       return FAILED;
 }
 
 static int srp_reset_device(struct scsi_cmnd *scmnd)
index 2082081..0b89275 100644 (file)
@@ -671,8 +671,7 @@ static int apple_dart_attach_dev(struct iommu_domain *domain,
                return ret;
 
        switch (domain->type) {
-       case IOMMU_DOMAIN_DMA:
-       case IOMMU_DOMAIN_UNMANAGED:
+       default:
                ret = apple_dart_domain_add_streams(dart_domain, cfg);
                if (ret)
                        return ret;
index 4d83edc..8a16cd3 100644 (file)
@@ -186,6 +186,15 @@ static void arm_smmu_free_shared_cd(struct arm_smmu_ctx_desc *cd)
        }
 }
 
+/*
+ * Cloned from the MAX_TLBI_OPS in arch/arm64/include/asm/tlbflush.h, this
+ * is used as a threshold to replace per-page TLBI commands to issue in the
+ * command queue with an address-space TLBI command, when SMMU w/o a range
+ * invalidation feature handles too many per-page TLBI commands, which will
+ * otherwise result in a soft lockup.
+ */
+#define CMDQ_MAX_TLBI_OPS              (1 << (PAGE_SHIFT - 3))
+
 static void arm_smmu_mm_arch_invalidate_secondary_tlbs(struct mmu_notifier *mn,
                                                struct mm_struct *mm,
                                                unsigned long start,
@@ -201,8 +210,13 @@ static void arm_smmu_mm_arch_invalidate_secondary_tlbs(struct mmu_notifier *mn,
         * range. So do a simple translation here by calculating size correctly.
         */
        size = end - start;
-       if (size == ULONG_MAX)
-               size = 0;
+       if (!(smmu_domain->smmu->features & ARM_SMMU_FEAT_RANGE_INV)) {
+               if (size >= CMDQ_MAX_TLBI_OPS * PAGE_SIZE)
+                       size = 0;
+       } else {
+               if (size == ULONG_MAX)
+                       size = 0;
+       }
 
        if (!(smmu_domain->smmu->features & ARM_SMMU_FEAT_BTM)) {
                if (!size)
index e82bf1c..bd0a596 100644 (file)
@@ -1895,18 +1895,23 @@ static void __arm_smmu_tlb_inv_range(struct arm_smmu_cmdq_ent *cmd,
                /* Get the leaf page size */
                tg = __ffs(smmu_domain->domain.pgsize_bitmap);
 
+               num_pages = size >> tg;
+
                /* Convert page size of 12,14,16 (log2) to 1,2,3 */
                cmd->tlbi.tg = (tg - 10) / 2;
 
                /*
-                * Determine what level the granule is at. For non-leaf, io-pgtable
-                * assumes .tlb_flush_walk can invalidate multiple levels at once,
-                * so ignore the nominal last-level granule and leave TTL=0.
+                * Determine what level the granule is at. For non-leaf, both
+                * io-pgtable and SVA pass a nominal last-level granule because
+                * they don't know what level(s) actually apply, so ignore that
+                * and leave TTL=0. However for various errata reasons we still
+                * want to use a range command, so avoid the SVA corner case
+                * where both scale and num could be 0 as well.
                 */
                if (cmd->tlbi.leaf)
                        cmd->tlbi.ttl = 4 - ((ilog2(granule) - 3) / (tg - 3));
-
-               num_pages = size >> tg;
+               else if ((num_pages & CMDQ_TLBI_RANGE_NUM_MAX) == 1)
+                       num_pages++;
        }
 
        cmds.num = 0;
index 5db283c..3685ba9 100644 (file)
@@ -2998,13 +2998,6 @@ static int iommu_suspend(void)
        struct intel_iommu *iommu = NULL;
        unsigned long flag;
 
-       for_each_active_iommu(iommu, drhd) {
-               iommu->iommu_state = kcalloc(MAX_SR_DMAR_REGS, sizeof(u32),
-                                            GFP_KERNEL);
-               if (!iommu->iommu_state)
-                       goto nomem;
-       }
-
        iommu_flush_all();
 
        for_each_active_iommu(iommu, drhd) {
@@ -3024,12 +3017,6 @@ static int iommu_suspend(void)
                raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
        }
        return 0;
-
-nomem:
-       for_each_active_iommu(iommu, drhd)
-               kfree(iommu->iommu_state);
-
-       return -ENOMEM;
 }
 
 static void iommu_resume(void)
@@ -3061,9 +3048,6 @@ static void iommu_resume(void)
 
                raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
        }
-
-       for_each_active_iommu(iommu, drhd)
-               kfree(iommu->iommu_state);
 }
 
 static struct syscore_ops iommu_syscore_ops = {
index c18fb69..7dac94f 100644 (file)
@@ -681,7 +681,7 @@ struct intel_iommu {
        struct iopf_queue *iopf_queue;
        unsigned char iopfq_name[16];
        struct q_inval  *qi;            /* Queued invalidation info */
-       u32 *iommu_state; /* Store iommu states between suspend and resume.*/
+       u32 iommu_state[MAX_SR_DMAR_REGS]; /* Store iommu states between suspend and resume.*/
 
 #ifdef CONFIG_IRQ_REMAP
        struct ir_table *ir_table;      /* Interrupt remapping info */
index 6402758..fab6c34 100644 (file)
@@ -262,7 +262,7 @@ struct mtk_iommu_data {
        struct device                   *smicomm_dev;
 
        struct mtk_iommu_bank_data      *bank;
-       struct mtk_iommu_domain         *share_dom; /* For 2 HWs share pgtable */
+       struct mtk_iommu_domain         *share_dom;
 
        struct regmap                   *pericfg;
        struct mutex                    mutex; /* Protect m4u_group/m4u_dom above */
@@ -643,8 +643,8 @@ static int mtk_iommu_domain_finalise(struct mtk_iommu_domain *dom,
        struct mtk_iommu_domain *share_dom = data->share_dom;
        const struct mtk_iommu_iova_region *region;
 
-       /* Always use share domain in sharing pgtable case */
-       if (MTK_IOMMU_HAS_FLAG(data->plat_data, SHARE_PGTABLE) && share_dom) {
+       /* Share pgtable when 2 MM IOMMU share the pgtable or one IOMMU use multiple iova ranges */
+       if (share_dom) {
                dom->iop = share_dom->iop;
                dom->cfg = share_dom->cfg;
                dom->domain.pgsize_bitmap = share_dom->cfg.pgsize_bitmap;
@@ -677,8 +677,7 @@ static int mtk_iommu_domain_finalise(struct mtk_iommu_domain *dom,
        /* Update our support page sizes bitmap */
        dom->domain.pgsize_bitmap = dom->cfg.pgsize_bitmap;
 
-       if (MTK_IOMMU_HAS_FLAG(data->plat_data, SHARE_PGTABLE))
-               data->share_dom = dom;
+       data->share_dom = dom;
 
 update_iova_region:
        /* Update the iova region for this domain */
index 3db4592..f407cce 100644 (file)
@@ -29,4 +29,8 @@ void gic_enable_quirks(u32 iidr, const struct gic_quirk *quirks,
 void gic_enable_of_quirks(const struct device_node *np,
                          const struct gic_quirk *quirks, void *data);
 
+#define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING    (1 << 0)
+#define RDIST_FLAGS_RD_TABLES_PREALLOCATED     (1 << 1)
+#define RDIST_FLAGS_FORCE_NON_SHAREABLE        (1 << 2)
+
 #endif /* _IRQ_GIC_COMMON_H */
index e0c2b10..75a2dd5 100644 (file)
 #define ITS_FLAGS_WORKAROUND_CAVIUM_23144      (1ULL << 2)
 #define ITS_FLAGS_FORCE_NON_SHAREABLE          (1ULL << 3)
 
-#define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING    (1 << 0)
-#define RDIST_FLAGS_RD_TABLES_PREALLOCATED     (1 << 1)
-#define RDIST_FLAGS_FORCE_NON_SHAREABLE                (1 << 2)
-
 #define RD_LOCAL_LPI_ENABLED                    BIT(0)
 #define RD_LOCAL_PENDTABLE_PREALLOCATED         BIT(1)
 #define RD_LOCAL_MEMRESERVE_DONE                BIT(2)
@@ -4754,6 +4750,14 @@ static bool __maybe_unused its_enable_rk3588001(void *data)
        return true;
 }
 
+static bool its_set_non_coherent(void *data)
+{
+       struct its_node *its = data;
+
+       its->flags |= ITS_FLAGS_FORCE_NON_SHAREABLE;
+       return true;
+}
+
 static const struct gic_quirk its_quirks[] = {
 #ifdef CONFIG_CAVIUM_ERRATUM_22375
        {
@@ -4809,6 +4813,11 @@ static const struct gic_quirk its_quirks[] = {
        },
 #endif
        {
+               .desc   = "ITS: non-coherent attribute",
+               .property = "dma-noncoherent",
+               .init   = its_set_non_coherent,
+       },
+       {
        }
 };
 
@@ -4817,6 +4826,10 @@ static void its_enable_quirks(struct its_node *its)
        u32 iidr = readl_relaxed(its->base + GITS_IIDR);
 
        gic_enable_quirks(iidr, its_quirks, its);
+
+       if (is_of_node(its->fwnode_handle))
+               gic_enable_of_quirks(to_of_node(its->fwnode_handle),
+                                    its_quirks, its);
 }
 
 static int its_save_disable(void)
@@ -4952,7 +4965,7 @@ out_unmap:
        return NULL;
 }
 
-static int its_init_domain(struct fwnode_handle *handle, struct its_node *its)
+static int its_init_domain(struct its_node *its)
 {
        struct irq_domain *inner_domain;
        struct msi_domain_info *info;
@@ -4966,7 +4979,7 @@ static int its_init_domain(struct fwnode_handle *handle, struct its_node *its)
 
        inner_domain = irq_domain_create_hierarchy(its_parent,
                                                   its->msi_domain_flags, 0,
-                                                  handle, &its_domain_ops,
+                                                  its->fwnode_handle, &its_domain_ops,
                                                   info);
        if (!inner_domain) {
                kfree(info);
@@ -5017,8 +5030,7 @@ static int its_init_vpe_domain(void)
        return 0;
 }
 
-static int __init its_compute_its_list_map(struct resource *res,
-                                          void __iomem *its_base)
+static int __init its_compute_its_list_map(struct its_node *its)
 {
        int its_number;
        u32 ctlr;
@@ -5032,15 +5044,15 @@ static int __init its_compute_its_list_map(struct resource *res,
        its_number = find_first_zero_bit(&its_list_map, GICv4_ITS_LIST_MAX);
        if (its_number >= GICv4_ITS_LIST_MAX) {
                pr_err("ITS@%pa: No ITSList entry available!\n",
-                      &res->start);
+                      &its->phys_base);
                return -EINVAL;
        }
 
-       ctlr = readl_relaxed(its_base + GITS_CTLR);
+       ctlr = readl_relaxed(its->base + GITS_CTLR);
        ctlr &= ~GITS_CTLR_ITS_NUMBER;
        ctlr |= its_number << GITS_CTLR_ITS_NUMBER_SHIFT;
-       writel_relaxed(ctlr, its_base + GITS_CTLR);
-       ctlr = readl_relaxed(its_base + GITS_CTLR);
+       writel_relaxed(ctlr, its->base + GITS_CTLR);
+       ctlr = readl_relaxed(its->base + GITS_CTLR);
        if ((ctlr & GITS_CTLR_ITS_NUMBER) != (its_number << GITS_CTLR_ITS_NUMBER_SHIFT)) {
                its_number = ctlr & GITS_CTLR_ITS_NUMBER;
                its_number >>= GITS_CTLR_ITS_NUMBER_SHIFT;
@@ -5048,75 +5060,50 @@ static int __init its_compute_its_list_map(struct resource *res,
 
        if (test_and_set_bit(its_number, &its_list_map)) {
                pr_err("ITS@%pa: Duplicate ITSList entry %d\n",
-                      &res->start, its_number);
+                      &its->phys_base, its_number);
                return -EINVAL;
        }
 
        return its_number;
 }
 
-static int __init its_probe_one(struct resource *res,
-                               struct fwnode_handle *handle, int numa_node)
+static int __init its_probe_one(struct its_node *its)
 {
-       struct its_node *its;
-       void __iomem *its_base;
-       u64 baser, tmp, typer;
+       u64 baser, tmp;
        struct page *page;
        u32 ctlr;
        int err;
 
-       its_base = its_map_one(res, &err);
-       if (!its_base)
-               return err;
-
-       pr_info("ITS %pR\n", res);
-
-       its = kzalloc(sizeof(*its), GFP_KERNEL);
-       if (!its) {
-               err = -ENOMEM;
-               goto out_unmap;
-       }
-
-       raw_spin_lock_init(&its->lock);
-       mutex_init(&its->dev_alloc_lock);
-       INIT_LIST_HEAD(&its->entry);
-       INIT_LIST_HEAD(&its->its_device_list);
-       typer = gic_read_typer(its_base + GITS_TYPER);
-       its->typer = typer;
-       its->base = its_base;
-       its->phys_base = res->start;
        if (is_v4(its)) {
-               if (!(typer & GITS_TYPER_VMOVP)) {
-                       err = its_compute_its_list_map(res, its_base);
+               if (!(its->typer & GITS_TYPER_VMOVP)) {
+                       err = its_compute_its_list_map(its);
                        if (err < 0)
-                               goto out_free_its;
+                               goto out;
 
                        its->list_nr = err;
 
                        pr_info("ITS@%pa: Using ITS number %d\n",
-                               &res->start, err);
+                               &its->phys_base, err);
                } else {
-                       pr_info("ITS@%pa: Single VMOVP capable\n", &res->start);
+                       pr_info("ITS@%pa: Single VMOVP capable\n", &its->phys_base);
                }
 
                if (is_v4_1(its)) {
-                       u32 svpet = FIELD_GET(GITS_TYPER_SVPET, typer);
+                       u32 svpet = FIELD_GET(GITS_TYPER_SVPET, its->typer);
 
-                       its->sgir_base = ioremap(res->start + SZ_128K, SZ_64K);
+                       its->sgir_base = ioremap(its->phys_base + SZ_128K, SZ_64K);
                        if (!its->sgir_base) {
                                err = -ENOMEM;
-                               goto out_free_its;
+                               goto out;
                        }
 
-                       its->mpidr = readl_relaxed(its_base + GITS_MPIDR);
+                       its->mpidr = readl_relaxed(its->base + GITS_MPIDR);
 
                        pr_info("ITS@%pa: Using GICv4.1 mode %08x %08x\n",
-                               &res->start, its->mpidr, svpet);
+                               &its->phys_base, its->mpidr, svpet);
                }
        }
 
-       its->numa_node = numa_node;
-
        page = alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO,
                                get_order(ITS_CMD_QUEUE_SZ));
        if (!page) {
@@ -5125,12 +5112,9 @@ static int __init its_probe_one(struct resource *res,
        }
        its->cmd_base = (void *)page_address(page);
        its->cmd_write = its->cmd_base;
-       its->fwnode_handle = handle;
        its->get_msi_base = its_irq_get_msi_base;
        its->msi_domain_flags = IRQ_DOMAIN_FLAG_ISOLATED_MSI;
 
-       its_enable_quirks(its);
-
        err = its_alloc_tables(its);
        if (err)
                goto out_free_cmd;
@@ -5174,7 +5158,7 @@ static int __init its_probe_one(struct resource *res,
                ctlr |= GITS_CTLR_ImDe;
        writel_relaxed(ctlr, its->base + GITS_CTLR);
 
-       err = its_init_domain(handle, its);
+       err = its_init_domain(its);
        if (err)
                goto out_free_tables;
 
@@ -5191,11 +5175,8 @@ out_free_cmd:
 out_unmap_sgir:
        if (its->sgir_base)
                iounmap(its->sgir_base);
-out_free_its:
-       kfree(its);
-out_unmap:
-       iounmap(its_base);
-       pr_err("ITS@%pa: failed probing (%d)\n", &res->start, err);
+out:
+       pr_err("ITS@%pa: failed probing (%d)\n", &its->phys_base, err);
        return err;
 }
 
@@ -5356,10 +5337,53 @@ static const struct of_device_id its_device_id[] = {
        {},
 };
 
+static struct its_node __init *its_node_init(struct resource *res,
+                                            struct fwnode_handle *handle, int numa_node)
+{
+       void __iomem *its_base;
+       struct its_node *its;
+       int err;
+
+       its_base = its_map_one(res, &err);
+       if (!its_base)
+               return NULL;
+
+       pr_info("ITS %pR\n", res);
+
+       its = kzalloc(sizeof(*its), GFP_KERNEL);
+       if (!its)
+               goto out_unmap;
+
+       raw_spin_lock_init(&its->lock);
+       mutex_init(&its->dev_alloc_lock);
+       INIT_LIST_HEAD(&its->entry);
+       INIT_LIST_HEAD(&its->its_device_list);
+
+       its->typer = gic_read_typer(its_base + GITS_TYPER);
+       its->base = its_base;
+       its->phys_base = res->start;
+
+       its->numa_node = numa_node;
+       its->fwnode_handle = handle;
+
+       return its;
+
+out_unmap:
+       iounmap(its_base);
+       return NULL;
+}
+
+static void its_node_destroy(struct its_node *its)
+{
+       iounmap(its->base);
+       kfree(its);
+}
+
 static int __init its_of_probe(struct device_node *node)
 {
        struct device_node *np;
        struct resource res;
+       int err;
 
        /*
         * Make sure *all* the ITS are reset before we probe any, as
@@ -5369,8 +5393,6 @@ static int __init its_of_probe(struct device_node *node)
         */
        for (np = of_find_matching_node(node, its_device_id); np;
             np = of_find_matching_node(np, its_device_id)) {
-               int err;
-
                if (!of_device_is_available(np) ||
                    !of_property_read_bool(np, "msi-controller") ||
                    of_address_to_resource(np, 0, &res))
@@ -5383,6 +5405,8 @@ static int __init its_of_probe(struct device_node *node)
 
        for (np = of_find_matching_node(node, its_device_id); np;
             np = of_find_matching_node(np, its_device_id)) {
+               struct its_node *its;
+
                if (!of_device_is_available(np))
                        continue;
                if (!of_property_read_bool(np, "msi-controller")) {
@@ -5396,7 +5420,17 @@ static int __init its_of_probe(struct device_node *node)
                        continue;
                }
 
-               its_probe_one(&res, &np->fwnode, of_node_to_nid(np));
+
+               its = its_node_init(&res, &np->fwnode, of_node_to_nid(np));
+               if (!its)
+                       return -ENOMEM;
+
+               its_enable_quirks(its);
+               err = its_probe_one(its);
+               if (err)  {
+                       its_node_destroy(its);
+                       return err;
+               }
        }
        return 0;
 }
@@ -5508,6 +5542,7 @@ static int __init gic_acpi_parse_madt_its(union acpi_subtable_headers *header,
 {
        struct acpi_madt_generic_translator *its_entry;
        struct fwnode_handle *dom_handle;
+       struct its_node *its;
        struct resource res;
        int err;
 
@@ -5532,11 +5567,18 @@ static int __init gic_acpi_parse_madt_its(union acpi_subtable_headers *header,
                goto dom_err;
        }
 
-       err = its_probe_one(&res, dom_handle,
-                       acpi_get_its_numa_node(its_entry->translation_id));
+       its = its_node_init(&res, dom_handle,
+                           acpi_get_its_numa_node(its_entry->translation_id));
+       if (!its) {
+               err = -ENOMEM;
+               goto node_err;
+       }
+
+       err = its_probe_one(its);
        if (!err)
                return 0;
 
+node_err:
        iort_deregister_domain_token(its_entry->translation_id);
 dom_err:
        irq_domain_free_fwnode(dom_handle);
index eedfa8e..f59ac95 100644 (file)
@@ -1857,6 +1857,14 @@ static bool gic_enable_quirk_arm64_2941627(void *data)
        return true;
 }
 
+static bool rd_set_non_coherent(void *data)
+{
+       struct gic_chip_data *d = data;
+
+       d->rdists.flags |= RDIST_FLAGS_FORCE_NON_SHAREABLE;
+       return true;
+}
+
 static const struct gic_quirk gic_quirks[] = {
        {
                .desc   = "GICv3: Qualcomm MSM8996 broken firmware",
@@ -1924,6 +1932,11 @@ static const struct gic_quirk gic_quirks[] = {
                .init   = gic_enable_quirk_arm64_2941627,
        },
        {
+               .desc   = "GICv3: non-coherent attribute",
+               .property = "dma-noncoherent",
+               .init   = rd_set_non_coherent,
+       },
+       {
        }
 };
 
index 4bbfa2b..96f4e32 100644 (file)
@@ -118,7 +118,7 @@ static void rzg2l_irqc_irq_disable(struct irq_data *d)
 
                raw_spin_lock(&priv->lock);
                reg = readl_relaxed(priv->base + TSSR(tssr_index));
-               reg &= ~(TSSEL_MASK << tssr_offset);
+               reg &= ~(TSSEL_MASK << TSSEL_SHIFT(tssr_offset));
                writel_relaxed(reg, priv->base + TSSR(tssr_index));
                raw_spin_unlock(&priv->lock);
        }
@@ -130,8 +130,8 @@ static void rzg2l_irqc_irq_enable(struct irq_data *d)
        unsigned int hw_irq = irqd_to_hwirq(d);
 
        if (hw_irq >= IRQC_TINT_START && hw_irq < IRQC_NUM_IRQ) {
+               unsigned long tint = (uintptr_t)irq_data_get_irq_chip_data(d);
                struct rzg2l_irqc_priv *priv = irq_data_to_priv(d);
-               unsigned long tint = (uintptr_t)d->chip_data;
                u32 offset = hw_irq - IRQC_TINT_START;
                u32 tssr_offset = TSSR_OFFSET(offset);
                u8 tssr_index = TSSR_INDEX(offset);
index 4adeee1..e8d01b1 100644 (file)
@@ -155,8 +155,16 @@ static int __init riscv_intc_init(struct device_node *node,
         * for each INTC DT node. We only need to do INTC initialization
         * for the INTC DT node belonging to boot CPU (or boot HART).
         */
-       if (riscv_hartid_to_cpuid(hartid) != smp_processor_id())
+       if (riscv_hartid_to_cpuid(hartid) != smp_processor_id()) {
+               /*
+                * The INTC nodes of each CPU are suppliers for downstream
+                * interrupt controllers (such as PLIC, IMSIC and APLIC
+                * direct-mode) so we should mark an INTC node as initialized
+                * if we are not creating IRQ domain for it.
+                */
+               fwnode_dev_initialized(of_fwnode_handle(node), true);
                return 0;
+       }
 
        return riscv_intc_init_common(of_node_to_fwnode(node));
 }
index d8ba5fb..971240e 100644 (file)
@@ -460,6 +460,7 @@ static const struct irq_domain_ops irq_exti_domain_ops = {
        .map    = irq_map_generic_chip,
        .alloc  = stm32_exti_alloc,
        .free   = stm32_exti_free,
+       .xlate  = irq_domain_xlate_twocell,
 };
 
 static void stm32_irq_ack(struct irq_data *d)
index 8c581c9..7f314e5 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/irqdomain.h>
 #include <linux/irq.h>
 #include <linux/irqchip.h>
+#include <linux/irqchip/xtensa-mx.h>
 #include <linux/of.h>
 
 #include <asm/mxregs.h>
index a32c0d2..74b2f12 100644 (file)
 
 #define PDC_MAX_GPIO_IRQS      256
 
+/* Valid only on HW version < 3.2 */
 #define IRQ_ENABLE_BANK                0x10
 #define IRQ_i_CFG              0x110
 
+/* Valid only on HW version >= 3.2 */
+#define IRQ_i_CFG_IRQ_ENABLE   3
+
+#define IRQ_i_CFG_TYPE_MASK    GENMASK(2, 0)
+
+#define PDC_VERSION_REG                0x1000
+
+/* Notable PDC versions */
+#define PDC_VERSION_3_2                0x30200
+
 struct pdc_pin_region {
        u32 pin_base;
        u32 parent_base;
@@ -37,6 +48,7 @@ static DEFINE_RAW_SPINLOCK(pdc_lock);
 static void __iomem *pdc_base;
 static struct pdc_pin_region *pdc_region;
 static int pdc_region_cnt;
+static unsigned int pdc_version;
 
 static void pdc_reg_write(int reg, u32 i, u32 val)
 {
@@ -48,20 +60,32 @@ static u32 pdc_reg_read(int reg, u32 i)
        return readl_relaxed(pdc_base + reg + i * sizeof(u32));
 }
 
-static void pdc_enable_intr(struct irq_data *d, bool on)
+static void __pdc_enable_intr(int pin_out, bool on)
 {
-       int pin_out = d->hwirq;
        unsigned long enable;
-       unsigned long flags;
-       u32 index, mask;
 
-       index = pin_out / 32;
-       mask = pin_out % 32;
+       if (pdc_version < PDC_VERSION_3_2) {
+               u32 index, mask;
+
+               index = pin_out / 32;
+               mask = pin_out % 32;
+
+               enable = pdc_reg_read(IRQ_ENABLE_BANK, index);
+               __assign_bit(mask, &enable, on);
+               pdc_reg_write(IRQ_ENABLE_BANK, index, enable);
+       } else {
+               enable = pdc_reg_read(IRQ_i_CFG, pin_out);
+               __assign_bit(IRQ_i_CFG_IRQ_ENABLE, &enable, on);
+               pdc_reg_write(IRQ_i_CFG, pin_out, enable);
+       }
+}
+
+static void pdc_enable_intr(struct irq_data *d, bool on)
+{
+       unsigned long flags;
 
        raw_spin_lock_irqsave(&pdc_lock, flags);
-       enable = pdc_reg_read(IRQ_ENABLE_BANK, index);
-       __assign_bit(mask, &enable, on);
-       pdc_reg_write(IRQ_ENABLE_BANK, index, enable);
+       __pdc_enable_intr(d->hwirq, on);
        raw_spin_unlock_irqrestore(&pdc_lock, flags);
 }
 
@@ -142,6 +166,7 @@ static int qcom_pdc_gic_set_type(struct irq_data *d, unsigned int type)
        }
 
        old_pdc_type = pdc_reg_read(IRQ_i_CFG, d->hwirq);
+       pdc_type |= (old_pdc_type & ~IRQ_i_CFG_TYPE_MASK);
        pdc_reg_write(IRQ_i_CFG, d->hwirq, pdc_type);
 
        ret = irq_chip_set_type_parent(d, type);
@@ -246,7 +271,6 @@ static const struct irq_domain_ops qcom_pdc_ops = {
 static int pdc_setup_pin_mapping(struct device_node *np)
 {
        int ret, n, i;
-       u32 irq_index, reg_index, val;
 
        n = of_property_count_elems_of_size(np, "qcom,pdc-ranges", sizeof(u32));
        if (n <= 0 || n % 3)
@@ -276,29 +300,38 @@ static int pdc_setup_pin_mapping(struct device_node *np)
                if (ret)
                        return ret;
 
-               for (i = 0; i < pdc_region[n].cnt; i++) {
-                       reg_index = (i + pdc_region[n].pin_base) >> 5;
-                       irq_index = (i + pdc_region[n].pin_base) & 0x1f;
-                       val = pdc_reg_read(IRQ_ENABLE_BANK, reg_index);
-                       val &= ~BIT(irq_index);
-                       pdc_reg_write(IRQ_ENABLE_BANK, reg_index, val);
-               }
+               for (i = 0; i < pdc_region[n].cnt; i++)
+                       __pdc_enable_intr(i + pdc_region[n].pin_base, 0);
        }
 
        return 0;
 }
 
+#define QCOM_PDC_SIZE 0x30000
+
 static int qcom_pdc_init(struct device_node *node, struct device_node *parent)
 {
        struct irq_domain *parent_domain, *pdc_domain;
+       resource_size_t res_size;
+       struct resource res;
        int ret;
 
-       pdc_base = of_iomap(node, 0);
+       /* compat with old sm8150 DT which had very small region for PDC */
+       if (of_address_to_resource(node, 0, &res))
+               return -EINVAL;
+
+       res_size = max_t(resource_size_t, resource_size(&res), QCOM_PDC_SIZE);
+       if (res_size > resource_size(&res))
+               pr_warn("%pOF: invalid reg size, please fix DT\n", node);
+
+       pdc_base = ioremap(res.start, res_size);
        if (!pdc_base) {
                pr_err("%pOF: unable to map PDC registers\n", node);
                return -ENXIO;
        }
 
+       pdc_version = pdc_reg_read(PDC_VERSION_REG, 0);
+
        parent_domain = irq_find_host(parent);
        if (!parent_domain) {
                pr_err("%pOF: unable to find PDC's parent domain\n", node);
index 04f9ea6..214ed81 100644 (file)
@@ -479,10 +479,6 @@ int led_compose_name(struct device *dev, struct led_init_data *init_data,
 
        led_parse_fwnode_props(dev, fwnode, &props);
 
-       /* We want to label LEDs that can produce full range of colors
-        * as RGB, not multicolor */
-       BUG_ON(props.color == LED_COLOR_ID_MULTI);
-
        if (props.label) {
                /*
                 * If init_data.devicename is NULL, then it indicates that
index f2662c2..5315fd2 100644 (file)
@@ -753,7 +753,8 @@ static int crypt_iv_eboiv_gen(struct crypt_config *cc, u8 *iv,
        int err;
        u8 *buf;
 
-       reqsize = ALIGN(crypto_skcipher_reqsize(tfm), __alignof__(__le64));
+       reqsize = sizeof(*req) + crypto_skcipher_reqsize(tfm);
+       reqsize = ALIGN(reqsize, __alignof__(__le64));
 
        req = kmalloc(reqsize + cc->iv_size, GFP_NOIO);
        if (!req)
index ad8e670..b487f7a 100644 (file)
@@ -748,17 +748,16 @@ err:
 /*
  * Cleanup zoned device information.
  */
-static void dmz_put_zoned_device(struct dm_target *ti)
+static void dmz_put_zoned_devices(struct dm_target *ti)
 {
        struct dmz_target *dmz = ti->private;
        int i;
 
-       for (i = 0; i < dmz->nr_ddevs; i++) {
-               if (dmz->ddev[i]) {
+       for (i = 0; i < dmz->nr_ddevs; i++)
+               if (dmz->ddev[i])
                        dm_put_device(ti, dmz->ddev[i]);
-                       dmz->ddev[i] = NULL;
-               }
-       }
+
+       kfree(dmz->ddev);
 }
 
 static int dmz_fixup_devices(struct dm_target *ti)
@@ -948,7 +947,7 @@ err_bio:
 err_meta:
        dmz_dtr_metadata(dmz->metadata);
 err_dev:
-       dmz_put_zoned_device(ti);
+       dmz_put_zoned_devices(ti);
 err:
        kfree(dmz->dev);
        kfree(dmz);
@@ -978,7 +977,7 @@ static void dmz_dtr(struct dm_target *ti)
 
        bioset_exit(&dmz->bio_set);
 
-       dmz_put_zoned_device(ti);
+       dmz_put_zoned_devices(ti);
 
        mutex_destroy(&dmz->chunk_lock);
 
index 4cb9c60..284cd71 100644 (file)
@@ -854,6 +854,13 @@ struct stripe_head *raid5_get_active_stripe(struct r5conf *conf,
 
                set_bit(R5_INACTIVE_BLOCKED, &conf->cache_state);
                r5l_wake_reclaim(conf->log, 0);
+
+               /* release batch_last before wait to avoid risk of deadlock */
+               if (ctx && ctx->batch_last) {
+                       raid5_release_stripe(ctx->batch_last);
+                       ctx->batch_last = NULL;
+               }
+
                wait_event_lock_irq(conf->wait_for_stripe,
                                    is_inactive_blocked(conf, hash),
                                    *(conf->hash_locks + hash));
index 0f430dd..fd87747 100644 (file)
  * different type underlying the specified range of virtual addresses.
  * When the function isn't able to map a single page, it returns error.
  *
+ * Note that get_vaddr_frames() cannot follow VM_IO mappings. It used
+ * to be able to do that, but that could (racily) return non-refcounted
+ * pfns.
+ *
  * This function takes care of grabbing mmap_lock as necessary.
  */
 int get_vaddr_frames(unsigned long start, unsigned int nr_frames, bool write,
@@ -59,8 +63,6 @@ int get_vaddr_frames(unsigned long start, unsigned int nr_frames, bool write,
        if (likely(ret > 0))
                return ret;
 
-       /* This used to (racily) return non-refcounted pfns. Let people know */
-       WARN_ONCE(1, "get_vaddr_frames() cannot follow VM_IO mapping");
        vec->nr_frames = 0;
        return ret ? ret : -EFAULT;
 }
index a1136fd..ec53abe 100644 (file)
@@ -691,12 +691,12 @@ static int imx219_init_cfg(struct v4l2_subdev *sd,
        struct v4l2_mbus_framefmt *format;
        struct v4l2_rect *crop;
 
-       /* Initialize try_fmt */
+       /* Initialize the format. */
        format = v4l2_subdev_get_pad_format(sd, state, 0);
        imx219_update_pad_format(imx219, &supported_modes[0], format,
                                 MEDIA_BUS_FMT_SRGGB10_1X10);
 
-       /* Initialize crop rectangle. */
+       /* Initialize the crop rectangle. */
        crop = v4l2_subdev_get_pad_crop(sd, state, 0);
        crop->top = IMX219_PIXEL_ARRAY_TOP;
        crop->left = IMX219_PIXEL_ARRAY_LEFT;
@@ -750,6 +750,7 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd,
        const struct imx219_mode *mode;
        int exposure_max, exposure_def, hblank;
        struct v4l2_mbus_framefmt *format;
+       struct v4l2_rect *crop;
 
        mode = v4l2_find_nearest_size(supported_modes,
                                      ARRAY_SIZE(supported_modes),
@@ -757,10 +758,12 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd,
                                      fmt->format.width, fmt->format.height);
 
        imx219_update_pad_format(imx219, mode, &fmt->format, fmt->format.code);
+
        format = v4l2_subdev_get_pad_format(sd, sd_state, 0);
+       crop = v4l2_subdev_get_pad_crop(sd, sd_state, 0);
 
-       if (imx219->mode == mode && format->code == fmt->format.code)
-               return 0;
+       *format = fmt->format;
+       *crop = mode->crop;
 
        if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
                imx219->mode = mode;
@@ -788,8 +791,6 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd,
                                         hblank);
        }
 
-       *format = fmt->format;
-
        return 0;
 }
 
index 20e7c7c..be84ff1 100644 (file)
@@ -1110,7 +1110,6 @@ err_async:
 
 static void max9286_v4l2_unregister(struct max9286_priv *priv)
 {
-       fwnode_handle_put(priv->sd.fwnode);
        v4l2_ctrl_handler_free(&priv->ctrls);
        v4l2_async_unregister_subdev(&priv->sd);
        max9286_v4l2_notifier_unregister(priv);
index a36a709..3e22df3 100644 (file)
@@ -608,7 +608,6 @@ static void rdacm21_remove(struct i2c_client *client)
        v4l2_async_unregister_subdev(&dev->sd);
        v4l2_ctrl_handler_free(&dev->ctrls);
        i2c_unregister_device(dev->isp);
-       fwnode_handle_put(dev->sd.fwnode);
 }
 
 static const struct of_device_id rdacm21_of_ids[] = {
index 436baf6..241a696 100644 (file)
@@ -68,9 +68,7 @@ bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
        sg = sglist;
        for (line = 0; line < store_lines; line++) {
                if ((line >= (store_lines - VCR_HACK_LINES)) &&
-                   (btv->opt_vcr_hack ||
-                   (V4L2_FIELD_HAS_BOTH(btv->field) ||
-                    btv->field == V4L2_FIELD_ALTERNATE)))
+                   btv->opt_vcr_hack)
                        continue;
                while (offset && offset >= sg_dma_len(sg)) {
                        offset -= sg_dma_len(sg);
index e113902..ee46841 100644 (file)
@@ -1,11 +1,19 @@
 # SPDX-License-Identifier: GPL-2.0-only
+
+source "drivers/media/pci/intel/ipu3/Kconfig"
+source "drivers/media/pci/intel/ivsc/Kconfig"
+
 config IPU_BRIDGE
-       tristate
+       tristate "Intel IPU Bridge"
        depends on I2C && ACPI
        help
-         This is a helper module for the IPU bridge, which can be
-         used by ipu3 and other drivers. In order to handle module
-         dependencies, this is selected by each driver that needs it.
+         The IPU bridge is a helper library for Intel IPU drivers to
+         function on systems shipped with Windows.
 
-source "drivers/media/pci/intel/ipu3/Kconfig"
-source "drivers/media/pci/intel/ivsc/Kconfig"
+         Currently used by the ipu3-cio2 and atomisp drivers.
+
+         Supported systems include:
+
+         - Microsoft Surface models (except Surface Pro 3)
+         - The Lenovo Miix line (for example the 510, 520, 710 and 720)
+         - Dell 7285
index 0951545..c0a250d 100644 (file)
@@ -2,13 +2,13 @@
 config VIDEO_IPU3_CIO2
        tristate "Intel ipu3-cio2 driver"
        depends on VIDEO_DEV && PCI
+       depends on IPU_BRIDGE || !IPU_BRIDGE
        depends on ACPI || COMPILE_TEST
        depends on X86
        select MEDIA_CONTROLLER
        select VIDEO_V4L2_SUBDEV_API
        select V4L2_FWNODE
        select VIDEOBUF2_DMA_SG
-       select IPU_BRIDGE if CIO2_BRIDGE
 
        help
          This is the Intel IPU3 CIO2 CSI-2 receiver unit, found in Intel
@@ -18,22 +18,3 @@ config VIDEO_IPU3_CIO2
          Say Y or M here if you have a Skylake/Kaby Lake SoC with MIPI CSI-2
          connected camera.
          The module will be called ipu3-cio2.
-
-config CIO2_BRIDGE
-       bool "IPU3 CIO2 Sensors Bridge"
-       depends on VIDEO_IPU3_CIO2 && ACPI
-       depends on I2C
-       help
-         This extension provides an API for the ipu3-cio2 driver to create
-         connections to cameras that are hidden in the SSDB buffer in ACPI.
-         It can be used to enable support for cameras in detachable / hybrid
-         devices that ship with Windows.
-
-         Say Y here if your device is a detachable / hybrid laptop that comes
-         with Windows installed by the OEM, for example:
-
-               - Microsoft Surface models (except Surface Pro 3)
-               - The Lenovo Miix line (for example the 510, 520, 710 and 720)
-               - Dell 7285
-
-         If in doubt, say N here.
index 1ef1c4e..a8cb981 100644 (file)
@@ -3,7 +3,10 @@
 
 config INTEL_VSC
        tristate "Intel Visual Sensing Controller"
-       depends on INTEL_MEI && ACPI
+       depends on INTEL_MEI && ACPI && VIDEO_DEV
+       select MEDIA_CONTROLLER
+       select VIDEO_V4L2_SUBDEV_API
+       select V4L2_FWNODE
        help
          This adds support for Intel Visual Sensing Controller (IVSC).
 
index 6e6caf5..59b89e4 100644 (file)
@@ -2398,7 +2398,7 @@ static int pxa_camera_probe(struct platform_device *pdev)
                               PXA_CAM_DRV_NAME, pcdev);
        if (err) {
                dev_err(&pdev->dev, "Camera interrupt register failed\n");
-               goto exit_v4l2_device_unregister;
+               goto exit_deactivate;
        }
 
        pcdev->notifier.ops = &pxa_camera_sensor_ops;
index ec1a167..d6499ff 100644 (file)
@@ -7,7 +7,7 @@ config VIDEO_CAFE_CCIC
        depends on V4L_PLATFORM_DRIVERS
        depends on PCI && I2C && VIDEO_DEV
        depends on COMMON_CLK
-       select VIDEO_OV7670
+       select VIDEO_OV7670 if MEDIA_SUBDRV_AUTOSELECT && VIDEO_CAMERA_SENSOR
        select VIDEOBUF2_VMALLOC
        select VIDEOBUF2_DMA_CONTIG
        select VIDEOBUF2_DMA_SG
@@ -22,7 +22,7 @@ config VIDEO_MMP_CAMERA
        depends on I2C && VIDEO_DEV
        depends on ARCH_MMP || COMPILE_TEST
        depends on COMMON_CLK
-       select VIDEO_OV7670
+       select VIDEO_OV7670 if MEDIA_SUBDRV_AUTOSELECT && VIDEO_CAMERA_SENSOR
        select I2C_GPIO
        select VIDEOBUF2_VMALLOC
        select VIDEOBUF2_DMA_CONTIG
index d299cc2..ae6290d 100644 (file)
@@ -138,7 +138,8 @@ int vpu_enc_init(struct venc_vpu_inst *vpu)
        vpu->ctx->vpu_inst = vpu;
 
        status = mtk_vcodec_fw_ipi_register(vpu->ctx->dev->fw_handler, vpu->id,
-                                           vpu_enc_ipi_handler, "venc", NULL);
+                                           vpu_enc_ipi_handler, "venc",
+                                           vpu->ctx->dev);
 
        if (status) {
                mtk_venc_err(vpu->ctx, "vpu_ipi_register fail %d", status);
index 16f19a6..5f93712 100644 (file)
@@ -1490,7 +1490,6 @@ err_cleanup:
        v4l2_async_unregister_subdev(&csis->sd);
 err_disable_clock:
        mipi_csis_clk_disable(csis);
-       fwnode_handle_put(csis->sd.fwnode);
 
        return ret;
 }
@@ -1510,7 +1509,6 @@ static void mipi_csis_remove(struct platform_device *pdev)
        mipi_csis_clk_disable(csis);
        v4l2_subdev_cleanup(&csis->sd);
        media_entity_cleanup(&csis->sd.entity);
-       fwnode_handle_put(csis->sd.fwnode);
        pm_runtime_set_suspended(&pdev->dev);
 }
 
index 8926eb0..6e603c0 100644 (file)
@@ -7,7 +7,7 @@ config VIDEO_VIA_CAMERA
        depends on V4L_PLATFORM_DRIVERS
        depends on FB_VIA && VIDEO_DEV
        select VIDEOBUF2_DMA_SG
-       select VIDEO_OV7670
+       select VIDEO_OV7670 if VIDEO_CAMERA_SENSOR
        help
           Driver support for the integrated camera controller in VIA
           Chrome9 chipsets.  Currently only tested on OLPC xo-1.5 systems
index b3c472b..cb61fd6 100644 (file)
@@ -12,8 +12,8 @@ config VIDEO_EM28XX_V4L2
        select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT
        select VIDEO_TVP5150 if MEDIA_SUBDRV_AUTOSELECT
        select VIDEO_MSP3400 if MEDIA_SUBDRV_AUTOSELECT
-       select VIDEO_MT9V011 if MEDIA_SUBDRV_AUTOSELECT && MEDIA_CAMERA_SUPPORT
-       select VIDEO_OV2640 if MEDIA_SUBDRV_AUTOSELECT && MEDIA_CAMERA_SUPPORT
+       select VIDEO_MT9V011 if MEDIA_SUBDRV_AUTOSELECT && VIDEO_CAMERA_SENSOR
+       select VIDEO_OV2640 if MEDIA_SUBDRV_AUTOSELECT && VIDEO_CAMERA_SENSOR
        help
          This is a video4linux driver for Empia 28xx based TV cards.
 
index 4ff7994..b2a15d9 100644 (file)
@@ -12,8 +12,8 @@ config VIDEO_GO7007
        select VIDEO_TW2804 if MEDIA_SUBDRV_AUTOSELECT
        select VIDEO_TW9903 if MEDIA_SUBDRV_AUTOSELECT
        select VIDEO_TW9906 if MEDIA_SUBDRV_AUTOSELECT
-       select VIDEO_OV7640 if MEDIA_SUBDRV_AUTOSELECT && MEDIA_CAMERA_SUPPORT
        select VIDEO_UDA1342 if MEDIA_SUBDRV_AUTOSELECT
+       select VIDEO_OV7640 if MEDIA_SUBDRV_AUTOSELECT && VIDEO_CAMERA_SENSOR
        help
          This is a video4linux driver for the WIS GO7007 MPEG
          encoder chip.
index 5e9d3da..e59a463 100644 (file)
@@ -1402,6 +1402,9 @@ int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
        query_menu->id = id;
        query_menu->index = index;
 
+       if (index >= BITS_PER_TYPE(mapping->menu_mask))
+               return -EINVAL;
+
        ret = mutex_lock_interruptible(&chain->ctrl_mutex);
        if (ret < 0)
                return -ERESTARTSYS;
index aea9574..90ce58f 100644 (file)
@@ -241,6 +241,7 @@ config MFD_CS42L43
        tristate
        select MFD_CORE
        select REGMAP
+       select REGMAP_IRQ
 
 config MFD_CS42L43_I2C
        tristate "Cirrus Logic CS42L43 (I2C)"
index 37b23e9..7b6d07c 100644 (file)
@@ -1178,8 +1178,8 @@ err:
 }
 
 EXPORT_NS_GPL_DEV_PM_OPS(cs42l43_pm_ops, MFD_CS42L43) = {
-       SET_SYSTEM_SLEEP_PM_OPS(cs42l43_suspend, cs42l43_resume)
-       SET_RUNTIME_PM_OPS(cs42l43_runtime_suspend, cs42l43_runtime_resume, NULL)
+       SYSTEM_SLEEP_PM_OPS(cs42l43_suspend, cs42l43_resume)
+       RUNTIME_PM_OPS(cs42l43_runtime_suspend, cs42l43_runtime_resume, NULL)
 };
 
 MODULE_DESCRIPTION("CS42L43 Core Driver");
index 3dae5e3..cd51228 100644 (file)
@@ -83,63 +83,20 @@ static void rts5227_fetch_vendor_settings(struct rtsx_pcr *pcr)
 
 static void rts5227_init_from_cfg(struct rtsx_pcr *pcr)
 {
-       struct pci_dev *pdev = pcr->pci;
-       int l1ss;
-       u32 lval;
        struct rtsx_cr_option *option = &pcr->option;
 
-       l1ss = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_L1SS);
-       if (!l1ss)
-               return;
-
-       pci_read_config_dword(pdev, l1ss + PCI_L1SS_CTL1, &lval);
-
        if (CHK_PCI_PID(pcr, 0x522A)) {
-               if (0 == (lval & 0x0F))
-                       rtsx_pci_enable_oobs_polling(pcr);
-               else
+               if (rtsx_check_dev_flag(pcr, ASPM_L1_1_EN | ASPM_L1_2_EN
+                               | PM_L1_1_EN | PM_L1_2_EN))
                        rtsx_pci_disable_oobs_polling(pcr);
+               else
+                       rtsx_pci_enable_oobs_polling(pcr);
        }
 
-       if (lval & PCI_L1SS_CTL1_ASPM_L1_1)
-               rtsx_set_dev_flag(pcr, ASPM_L1_1_EN);
-       else
-               rtsx_clear_dev_flag(pcr, ASPM_L1_1_EN);
-
-       if (lval & PCI_L1SS_CTL1_ASPM_L1_2)
-               rtsx_set_dev_flag(pcr, ASPM_L1_2_EN);
-       else
-               rtsx_clear_dev_flag(pcr, ASPM_L1_2_EN);
-
-       if (lval & PCI_L1SS_CTL1_PCIPM_L1_1)
-               rtsx_set_dev_flag(pcr, PM_L1_1_EN);
-       else
-               rtsx_clear_dev_flag(pcr, PM_L1_1_EN);
-
-       if (lval & PCI_L1SS_CTL1_PCIPM_L1_2)
-               rtsx_set_dev_flag(pcr, PM_L1_2_EN);
-       else
-               rtsx_clear_dev_flag(pcr, PM_L1_2_EN);
-
        if (option->ltr_en) {
-               u16 val;
-
-               pcie_capability_read_word(pcr->pci, PCI_EXP_DEVCTL2, &val);
-               if (val & PCI_EXP_DEVCTL2_LTR_EN) {
-                       option->ltr_enabled = true;
-                       option->ltr_active = true;
+               if (option->ltr_enabled)
                        rtsx_set_ltr_latency(pcr, option->ltr_active_latency);
-               } else {
-                       option->ltr_enabled = false;
-               }
        }
-
-       if (rtsx_check_dev_flag(pcr, ASPM_L1_1_EN | ASPM_L1_2_EN
-                               | PM_L1_1_EN | PM_L1_2_EN))
-               option->force_clkreq_0 = false;
-       else
-               option->force_clkreq_0 = true;
-
 }
 
 static int rts5227_extra_init_hw(struct rtsx_pcr *pcr)
@@ -195,7 +152,7 @@ static int rts5227_extra_init_hw(struct rtsx_pcr *pcr)
                }
        }
 
-       if (option->force_clkreq_0 && pcr->aspm_mode == ASPM_MODE_CFG)
+       if (option->force_clkreq_0)
                rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG,
                                FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_LOW);
        else
index f4ab094..0c7f10b 100644 (file)
@@ -386,59 +386,25 @@ static void rts5228_process_ocp(struct rtsx_pcr *pcr)
 
 static void rts5228_init_from_cfg(struct rtsx_pcr *pcr)
 {
-       struct pci_dev *pdev = pcr->pci;
-       int l1ss;
-       u32 lval;
        struct rtsx_cr_option *option = &pcr->option;
 
-       l1ss = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_L1SS);
-       if (!l1ss)
-               return;
-
-       pci_read_config_dword(pdev, l1ss + PCI_L1SS_CTL1, &lval);
-
-       if (0 == (lval & 0x0F))
-               rtsx_pci_enable_oobs_polling(pcr);
-       else
+       if (rtsx_check_dev_flag(pcr, ASPM_L1_1_EN | ASPM_L1_2_EN
+                               | PM_L1_1_EN | PM_L1_2_EN))
                rtsx_pci_disable_oobs_polling(pcr);
-
-       if (lval & PCI_L1SS_CTL1_ASPM_L1_1)
-               rtsx_set_dev_flag(pcr, ASPM_L1_1_EN);
-       else
-               rtsx_clear_dev_flag(pcr, ASPM_L1_1_EN);
-
-       if (lval & PCI_L1SS_CTL1_ASPM_L1_2)
-               rtsx_set_dev_flag(pcr, ASPM_L1_2_EN);
-       else
-               rtsx_clear_dev_flag(pcr, ASPM_L1_2_EN);
-
-       if (lval & PCI_L1SS_CTL1_PCIPM_L1_1)
-               rtsx_set_dev_flag(pcr, PM_L1_1_EN);
        else
-               rtsx_clear_dev_flag(pcr, PM_L1_1_EN);
-
-       if (lval & PCI_L1SS_CTL1_PCIPM_L1_2)
-               rtsx_set_dev_flag(pcr, PM_L1_2_EN);
-       else
-               rtsx_clear_dev_flag(pcr, PM_L1_2_EN);
+               rtsx_pci_enable_oobs_polling(pcr);
 
        rtsx_pci_write_register(pcr, ASPM_FORCE_CTL, 0xFF, 0);
-       if (option->ltr_en) {
-               u16 val;
 
-               pcie_capability_read_word(pcr->pci, PCI_EXP_DEVCTL2, &val);
-               if (val & PCI_EXP_DEVCTL2_LTR_EN) {
-                       option->ltr_enabled = true;
-                       option->ltr_active = true;
+       if (option->ltr_en) {
+               if (option->ltr_enabled)
                        rtsx_set_ltr_latency(pcr, option->ltr_active_latency);
-               } else {
-                       option->ltr_enabled = false;
-               }
        }
 }
 
 static int rts5228_extra_init_hw(struct rtsx_pcr *pcr)
 {
+       struct rtsx_cr_option *option = &pcr->option;
 
        rtsx_pci_write_register(pcr, RTS5228_AUTOLOAD_CFG1,
                        CD_RESUME_EN_MASK, CD_RESUME_EN_MASK);
@@ -469,6 +435,17 @@ static int rts5228_extra_init_hw(struct rtsx_pcr *pcr)
        else
                rtsx_pci_write_register(pcr, PETXCFG, 0x30, 0x00);
 
+       /*
+        * If u_force_clkreq_0 is enabled, CLKREQ# PIN will be forced
+        * to drive low, and we forcibly request clock.
+        */
+       if (option->force_clkreq_0)
+               rtsx_pci_write_register(pcr, PETXCFG,
+                                FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_LOW);
+       else
+               rtsx_pci_write_register(pcr, PETXCFG,
+                                FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_HIGH);
+
        rtsx_pci_write_register(pcr, PWD_SUSPEND_EN, 0xFF, 0xFB);
 
        if (pcr->rtd3_en) {
index 47ab72a..6c81040 100644 (file)
@@ -86,64 +86,22 @@ static void rtsx_base_fetch_vendor_settings(struct rtsx_pcr *pcr)
 
 static void rts5249_init_from_cfg(struct rtsx_pcr *pcr)
 {
-       struct pci_dev *pdev = pcr->pci;
-       int l1ss;
        struct rtsx_cr_option *option = &(pcr->option);
-       u32 lval;
-
-       l1ss = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_L1SS);
-       if (!l1ss)
-               return;
-
-       pci_read_config_dword(pdev, l1ss + PCI_L1SS_CTL1, &lval);
 
        if (CHK_PCI_PID(pcr, PID_524A) || CHK_PCI_PID(pcr, PID_525A)) {
-               if (0 == (lval & 0x0F))
-                       rtsx_pci_enable_oobs_polling(pcr);
-               else
+               if (rtsx_check_dev_flag(pcr, ASPM_L1_1_EN | ASPM_L1_2_EN
+                               | PM_L1_1_EN | PM_L1_2_EN))
                        rtsx_pci_disable_oobs_polling(pcr);
+               else
+                       rtsx_pci_enable_oobs_polling(pcr);
        }
 
-
-       if (lval & PCI_L1SS_CTL1_ASPM_L1_1)
-               rtsx_set_dev_flag(pcr, ASPM_L1_1_EN);
-
-       if (lval & PCI_L1SS_CTL1_ASPM_L1_2)
-               rtsx_set_dev_flag(pcr, ASPM_L1_2_EN);
-
-       if (lval & PCI_L1SS_CTL1_PCIPM_L1_1)
-               rtsx_set_dev_flag(pcr, PM_L1_1_EN);
-
-       if (lval & PCI_L1SS_CTL1_PCIPM_L1_2)
-               rtsx_set_dev_flag(pcr, PM_L1_2_EN);
-
        if (option->ltr_en) {
-               u16 val;
-
-               pcie_capability_read_word(pdev, PCI_EXP_DEVCTL2, &val);
-               if (val & PCI_EXP_DEVCTL2_LTR_EN) {
-                       option->ltr_enabled = true;
-                       option->ltr_active = true;
+               if (option->ltr_enabled)
                        rtsx_set_ltr_latency(pcr, option->ltr_active_latency);
-               } else {
-                       option->ltr_enabled = false;
-               }
        }
 }
 
-static int rts5249_init_from_hw(struct rtsx_pcr *pcr)
-{
-       struct rtsx_cr_option *option = &(pcr->option);
-
-       if (rtsx_check_dev_flag(pcr, ASPM_L1_1_EN | ASPM_L1_2_EN
-                               | PM_L1_1_EN | PM_L1_2_EN))
-               option->force_clkreq_0 = false;
-       else
-               option->force_clkreq_0 = true;
-
-       return 0;
-}
-
 static void rts52xa_force_power_down(struct rtsx_pcr *pcr, u8 pm_state, bool runtime)
 {
        /* Set relink_time to 0 */
@@ -276,7 +234,6 @@ static int rts5249_extra_init_hw(struct rtsx_pcr *pcr)
        struct rtsx_cr_option *option = &(pcr->option);
 
        rts5249_init_from_cfg(pcr);
-       rts5249_init_from_hw(pcr);
 
        rtsx_pci_init_cmd(pcr);
 
@@ -327,11 +284,12 @@ static int rts5249_extra_init_hw(struct rtsx_pcr *pcr)
                }
        }
 
+
        /*
         * If u_force_clkreq_0 is enabled, CLKREQ# PIN will be forced
         * to drive low, and we forcibly request clock.
         */
-       if (option->force_clkreq_0 && pcr->aspm_mode == ASPM_MODE_CFG)
+       if (option->force_clkreq_0)
                rtsx_pci_write_register(pcr, PETXCFG,
                        FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_LOW);
        else
index 79b18f6..d2d3a6c 100644 (file)
@@ -480,47 +480,19 @@ static void rts5260_pwr_saving_setting(struct rtsx_pcr *pcr)
 
 static void rts5260_init_from_cfg(struct rtsx_pcr *pcr)
 {
-       struct pci_dev *pdev = pcr->pci;
-       int l1ss;
        struct rtsx_cr_option *option = &pcr->option;
-       u32 lval;
-
-       l1ss = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_L1SS);
-       if (!l1ss)
-               return;
-
-       pci_read_config_dword(pdev, l1ss + PCI_L1SS_CTL1, &lval);
-
-       if (lval & PCI_L1SS_CTL1_ASPM_L1_1)
-               rtsx_set_dev_flag(pcr, ASPM_L1_1_EN);
-
-       if (lval & PCI_L1SS_CTL1_ASPM_L1_2)
-               rtsx_set_dev_flag(pcr, ASPM_L1_2_EN);
-
-       if (lval & PCI_L1SS_CTL1_PCIPM_L1_1)
-               rtsx_set_dev_flag(pcr, PM_L1_1_EN);
-
-       if (lval & PCI_L1SS_CTL1_PCIPM_L1_2)
-               rtsx_set_dev_flag(pcr, PM_L1_2_EN);
 
        rts5260_pwr_saving_setting(pcr);
 
        if (option->ltr_en) {
-               u16 val;
-
-               pcie_capability_read_word(pdev, PCI_EXP_DEVCTL2, &val);
-               if (val & PCI_EXP_DEVCTL2_LTR_EN) {
-                       option->ltr_enabled = true;
-                       option->ltr_active = true;
+               if (option->ltr_enabled)
                        rtsx_set_ltr_latency(pcr, option->ltr_active_latency);
-               } else {
-                       option->ltr_enabled = false;
-               }
        }
 }
 
 static int rts5260_extra_init_hw(struct rtsx_pcr *pcr)
 {
+       struct rtsx_cr_option *option = &pcr->option;
 
        /* Set mcu_cnt to 7 to ensure data can be sampled properly */
        rtsx_pci_write_register(pcr, 0xFC03, 0x7F, 0x07);
@@ -539,6 +511,17 @@ static int rts5260_extra_init_hw(struct rtsx_pcr *pcr)
 
        rts5260_init_hw(pcr);
 
+       /*
+        * If u_force_clkreq_0 is enabled, CLKREQ# PIN will be forced
+        * to drive low, and we forcibly request clock.
+        */
+       if (option->force_clkreq_0)
+               rtsx_pci_write_register(pcr, PETXCFG,
+                                FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_LOW);
+       else
+               rtsx_pci_write_register(pcr, PETXCFG,
+                                FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_HIGH);
+
        rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3, 0x10, 0x00);
 
        return 0;
index 94af6bf..6725251 100644 (file)
@@ -454,54 +454,17 @@ static void rts5261_init_from_hw(struct rtsx_pcr *pcr)
 
 static void rts5261_init_from_cfg(struct rtsx_pcr *pcr)
 {
-       struct pci_dev *pdev = pcr->pci;
-       int l1ss;
-       u32 lval;
        struct rtsx_cr_option *option = &pcr->option;
 
-       l1ss = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_L1SS);
-       if (!l1ss)
-               return;
-
-       pci_read_config_dword(pdev, l1ss + PCI_L1SS_CTL1, &lval);
-
-       if (lval & PCI_L1SS_CTL1_ASPM_L1_1)
-               rtsx_set_dev_flag(pcr, ASPM_L1_1_EN);
-       else
-               rtsx_clear_dev_flag(pcr, ASPM_L1_1_EN);
-
-       if (lval & PCI_L1SS_CTL1_ASPM_L1_2)
-               rtsx_set_dev_flag(pcr, ASPM_L1_2_EN);
-       else
-               rtsx_clear_dev_flag(pcr, ASPM_L1_2_EN);
-
-       if (lval & PCI_L1SS_CTL1_PCIPM_L1_1)
-               rtsx_set_dev_flag(pcr, PM_L1_1_EN);
-       else
-               rtsx_clear_dev_flag(pcr, PM_L1_1_EN);
-
-       if (lval & PCI_L1SS_CTL1_PCIPM_L1_2)
-               rtsx_set_dev_flag(pcr, PM_L1_2_EN);
-       else
-               rtsx_clear_dev_flag(pcr, PM_L1_2_EN);
-
-       rtsx_pci_write_register(pcr, ASPM_FORCE_CTL, 0xFF, 0);
        if (option->ltr_en) {
-               u16 val;
-
-               pcie_capability_read_word(pdev, PCI_EXP_DEVCTL2, &val);
-               if (val & PCI_EXP_DEVCTL2_LTR_EN) {
-                       option->ltr_enabled = true;
-                       option->ltr_active = true;
+               if (option->ltr_enabled)
                        rtsx_set_ltr_latency(pcr, option->ltr_active_latency);
-               } else {
-                       option->ltr_enabled = false;
-               }
        }
 }
 
 static int rts5261_extra_init_hw(struct rtsx_pcr *pcr)
 {
+       struct rtsx_cr_option *option = &pcr->option;
        u32 val;
 
        rtsx_pci_write_register(pcr, RTS5261_AUTOLOAD_CFG1,
@@ -547,6 +510,17 @@ static int rts5261_extra_init_hw(struct rtsx_pcr *pcr)
        else
                rtsx_pci_write_register(pcr, PETXCFG, 0x30, 0x00);
 
+       /*
+        * If u_force_clkreq_0 is enabled, CLKREQ# PIN will be forced
+        * to drive low, and we forcibly request clock.
+        */
+       if (option->force_clkreq_0)
+               rtsx_pci_write_register(pcr, PETXCFG,
+                                FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_LOW);
+       else
+               rtsx_pci_write_register(pcr, PETXCFG,
+                                FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_HIGH);
+
        rtsx_pci_write_register(pcr, PWD_SUSPEND_EN, 0xFF, 0xFB);
 
        if (pcr->rtd3_en) {
index a3f4b52..a30751a 100644 (file)
@@ -1326,11 +1326,8 @@ static int rtsx_pci_init_hw(struct rtsx_pcr *pcr)
                        return err;
        }
 
-       if (pcr->aspm_mode == ASPM_MODE_REG) {
+       if (pcr->aspm_mode == ASPM_MODE_REG)
                rtsx_pci_write_register(pcr, ASPM_FORCE_CTL, 0x30, 0x30);
-               rtsx_pci_write_register(pcr, PETXCFG,
-                               FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_HIGH);
-       }
 
        /* No CD interrupt if probing driver with card inserted.
         * So we need to initialize pcr->card_exist here.
@@ -1345,7 +1342,9 @@ static int rtsx_pci_init_hw(struct rtsx_pcr *pcr)
 
 static int rtsx_pci_init_chip(struct rtsx_pcr *pcr)
 {
-       int err;
+       struct rtsx_cr_option *option = &(pcr->option);
+       int err, l1ss;
+       u32 lval;
        u16 cfg_val;
        u8 val;
 
@@ -1430,6 +1429,48 @@ static int rtsx_pci_init_chip(struct rtsx_pcr *pcr)
                        pcr->aspm_enabled = true;
        }
 
+       l1ss = pci_find_ext_capability(pcr->pci, PCI_EXT_CAP_ID_L1SS);
+       if (l1ss) {
+               pci_read_config_dword(pcr->pci, l1ss + PCI_L1SS_CTL1, &lval);
+
+               if (lval & PCI_L1SS_CTL1_ASPM_L1_1)
+                       rtsx_set_dev_flag(pcr, ASPM_L1_1_EN);
+               else
+                       rtsx_clear_dev_flag(pcr, ASPM_L1_1_EN);
+
+               if (lval & PCI_L1SS_CTL1_ASPM_L1_2)
+                       rtsx_set_dev_flag(pcr, ASPM_L1_2_EN);
+               else
+                       rtsx_clear_dev_flag(pcr, ASPM_L1_2_EN);
+
+               if (lval & PCI_L1SS_CTL1_PCIPM_L1_1)
+                       rtsx_set_dev_flag(pcr, PM_L1_1_EN);
+               else
+                       rtsx_clear_dev_flag(pcr, PM_L1_1_EN);
+
+               if (lval & PCI_L1SS_CTL1_PCIPM_L1_2)
+                       rtsx_set_dev_flag(pcr, PM_L1_2_EN);
+               else
+                       rtsx_clear_dev_flag(pcr, PM_L1_2_EN);
+
+               pcie_capability_read_word(pcr->pci, PCI_EXP_DEVCTL2, &cfg_val);
+               if (cfg_val & PCI_EXP_DEVCTL2_LTR_EN) {
+                       option->ltr_enabled = true;
+                       option->ltr_active = true;
+               } else {
+                       option->ltr_enabled = false;
+               }
+
+               if (rtsx_check_dev_flag(pcr, ASPM_L1_1_EN | ASPM_L1_2_EN
+                               | PM_L1_1_EN | PM_L1_2_EN))
+                       option->force_clkreq_0 = false;
+               else
+                       option->force_clkreq_0 = true;
+       } else {
+               option->ltr_enabled = false;
+               option->force_clkreq_0 = true;
+       }
+
        if (pcr->ops->fetch_vendor_settings)
                pcr->ops->fetch_vendor_settings(pcr);
 
index 8b91a55..8ee51e4 100644 (file)
@@ -894,6 +894,13 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
                return -EINVAL;
        }
 
+       /* UBI cannot work on flashes with zero erasesize. */
+       if (!mtd->erasesize) {
+               pr_err("ubi: refuse attaching mtd%d - zero erasesize flash is not supported\n",
+                       mtd->index);
+               return -EINVAL;
+       }
+
        if (ubi_num == UBI_DEV_NUM_AUTO) {
                /* Search for an empty slot in the @ubi_devices array */
                for (ubi_num = 0; ubi_num < UBI_MAX_DEVICES; ubi_num++)
index 52a99d8..ab434a7 100644 (file)
@@ -2958,14 +2958,16 @@ static void mv88e6xxx_hardware_reset(struct mv88e6xxx_chip *chip)
                 * from the wrong location resulting in the switch booting
                 * to wrong mode and inoperable.
                 */
-               mv88e6xxx_g1_wait_eeprom_done(chip);
+               if (chip->info->ops->get_eeprom)
+                       mv88e6xxx_g2_eeprom_wait(chip);
 
                gpiod_set_value_cansleep(gpiod, 1);
                usleep_range(10000, 20000);
                gpiod_set_value_cansleep(gpiod, 0);
                usleep_range(10000, 20000);
 
-               mv88e6xxx_g1_wait_eeprom_done(chip);
+               if (chip->info->ops->get_eeprom)
+                       mv88e6xxx_g2_eeprom_wait(chip);
        }
 }
 
index 2fa55a6..174c773 100644 (file)
@@ -75,37 +75,6 @@ static int mv88e6xxx_g1_wait_init_ready(struct mv88e6xxx_chip *chip)
        return mv88e6xxx_g1_wait_bit(chip, MV88E6XXX_G1_STS, bit, 1);
 }
 
-void mv88e6xxx_g1_wait_eeprom_done(struct mv88e6xxx_chip *chip)
-{
-       const unsigned long timeout = jiffies + 1 * HZ;
-       u16 val;
-       int err;
-
-       /* Wait up to 1 second for the switch to finish reading the
-        * EEPROM.
-        */
-       while (time_before(jiffies, timeout)) {
-               err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &val);
-               if (err) {
-                       dev_err(chip->dev, "Error reading status");
-                       return;
-               }
-
-               /* If the switch is still resetting, it may not
-                * respond on the bus, and so MDIO read returns
-                * 0xffff. Differentiate between that, and waiting for
-                * the EEPROM to be done by bit 0 being set.
-                */
-               if (val != 0xffff &&
-                   val & BIT(MV88E6XXX_G1_STS_IRQ_EEPROM_DONE))
-                       return;
-
-               usleep_range(1000, 2000);
-       }
-
-       dev_err(chip->dev, "Timeout waiting for EEPROM done");
-}
-
 /* Offset 0x01: Switch MAC Address Register Bytes 0 & 1
  * Offset 0x02: Switch MAC Address Register Bytes 2 & 3
  * Offset 0x03: Switch MAC Address Register Bytes 4 & 5
index c99ddd1..1095261 100644 (file)
@@ -282,7 +282,6 @@ int mv88e6xxx_g1_set_switch_mac(struct mv88e6xxx_chip *chip, u8 *addr);
 int mv88e6185_g1_reset(struct mv88e6xxx_chip *chip);
 int mv88e6352_g1_reset(struct mv88e6xxx_chip *chip);
 int mv88e6250_g1_reset(struct mv88e6xxx_chip *chip);
-void mv88e6xxx_g1_wait_eeprom_done(struct mv88e6xxx_chip *chip);
 
 int mv88e6185_g1_ppu_enable(struct mv88e6xxx_chip *chip);
 int mv88e6185_g1_ppu_disable(struct mv88e6xxx_chip *chip);
index 937a01f..b2b5f6b 100644 (file)
@@ -340,7 +340,7 @@ int mv88e6xxx_g2_pot_clear(struct mv88e6xxx_chip *chip)
  * Offset 0x15: EEPROM Addr (for 8-bit data access)
  */
 
-static int mv88e6xxx_g2_eeprom_wait(struct mv88e6xxx_chip *chip)
+int mv88e6xxx_g2_eeprom_wait(struct mv88e6xxx_chip *chip)
 {
        int bit = __bf_shf(MV88E6XXX_G2_EEPROM_CMD_BUSY);
        int err;
index 7e09196..d9434f7 100644 (file)
@@ -365,6 +365,7 @@ int mv88e6xxx_g2_trunk_clear(struct mv88e6xxx_chip *chip);
 
 int mv88e6xxx_g2_device_mapping_write(struct mv88e6xxx_chip *chip, int target,
                                      int port);
+int mv88e6xxx_g2_eeprom_wait(struct mv88e6xxx_chip *chip);
 
 extern const struct mv88e6xxx_irq_ops mv88e6097_watchdog_ops;
 extern const struct mv88e6xxx_irq_ops mv88e6250_watchdog_ops;
index ad32ca8..f955bde 100644 (file)
@@ -1833,6 +1833,9 @@ static int ena_clean_rx_irq(struct ena_ring *rx_ring, struct napi_struct *napi,
        return work_done;
 
 error:
+       if (xdp_flags & ENA_XDP_REDIRECT)
+               xdp_do_flush();
+
        adapter = netdev_priv(rx_ring->netdev);
 
        if (rc == -ENOSPC) {
index 5cc0dbe..7551aa8 100644 (file)
@@ -2614,6 +2614,7 @@ static int bnxt_poll_nitroa0(struct napi_struct *napi, int budget)
        struct rx_cmp_ext *rxcmp1;
        u32 cp_cons, tmp_raw_cons;
        u32 raw_cons = cpr->cp_raw_cons;
+       bool flush_xdp = false;
        u32 rx_pkts = 0;
        u8 event = 0;
 
@@ -2648,6 +2649,8 @@ static int bnxt_poll_nitroa0(struct napi_struct *napi, int budget)
                                rx_pkts++;
                        else if (rc == -EBUSY)  /* partial completion */
                                break;
+                       if (event & BNXT_REDIRECT_EVENT)
+                               flush_xdp = true;
                } else if (unlikely(TX_CMP_TYPE(txcmp) ==
                                    CMPL_BASE_TYPE_HWRM_DONE)) {
                        bnxt_hwrm_handler(bp, txcmp);
@@ -2667,6 +2670,8 @@ static int bnxt_poll_nitroa0(struct napi_struct *napi, int budget)
 
        if (event & BNXT_AGG_EVENT)
                bnxt_db_write(bp, &rxr->rx_agg_db, rxr->rx_agg_prod);
+       if (flush_xdp)
+               xdp_do_flush();
 
        if (!bnxt_has_work(bp, cpr) && rx_pkts < budget) {
                napi_complete_done(napi, rx_pkts);
index 716815d..65ec1ab 100644 (file)
@@ -300,10 +300,8 @@ static void tsnep_ethtool_get_channels(struct net_device *netdev,
 {
        struct tsnep_adapter *adapter = netdev_priv(netdev);
 
-       ch->max_rx = adapter->num_rx_queues;
-       ch->max_tx = adapter->num_tx_queues;
-       ch->rx_count = adapter->num_rx_queues;
-       ch->tx_count = adapter->num_tx_queues;
+       ch->max_combined = adapter->num_queues;
+       ch->combined_count = adapter->num_queues;
 }
 
 static int tsnep_ethtool_get_ts_info(struct net_device *netdev,
index f61bd89..8b992dc 100644 (file)
@@ -87,8 +87,11 @@ static irqreturn_t tsnep_irq(int irq, void *arg)
 
        /* handle TX/RX queue 0 interrupt */
        if ((active & adapter->queue[0].irq_mask) != 0) {
-               tsnep_disable_irq(adapter, adapter->queue[0].irq_mask);
-               napi_schedule(&adapter->queue[0].napi);
+               if (napi_schedule_prep(&adapter->queue[0].napi)) {
+                       tsnep_disable_irq(adapter, adapter->queue[0].irq_mask);
+                       /* schedule after masking to avoid races */
+                       __napi_schedule(&adapter->queue[0].napi);
+               }
        }
 
        return IRQ_HANDLED;
@@ -99,8 +102,11 @@ static irqreturn_t tsnep_irq_txrx(int irq, void *arg)
        struct tsnep_queue *queue = arg;
 
        /* handle TX/RX queue interrupt */
-       tsnep_disable_irq(queue->adapter, queue->irq_mask);
-       napi_schedule(&queue->napi);
+       if (napi_schedule_prep(&queue->napi)) {
+               tsnep_disable_irq(queue->adapter, queue->irq_mask);
+               /* schedule after masking to avoid races */
+               __napi_schedule(&queue->napi);
+       }
 
        return IRQ_HANDLED;
 }
@@ -1728,6 +1734,10 @@ static int tsnep_poll(struct napi_struct *napi, int budget)
        if (queue->tx)
                complete = tsnep_tx_poll(queue->tx, budget);
 
+       /* handle case where we are called by netpoll with a budget of 0 */
+       if (unlikely(budget <= 0))
+               return budget;
+
        if (queue->rx) {
                done = queue->rx->xsk_pool ?
                       tsnep_rx_poll_zc(queue->rx, napi, budget) :
index b4895c7..cf50368 100644 (file)
@@ -3353,6 +3353,15 @@ static void hns3_set_default_feature(struct net_device *netdev)
                  NETIF_F_HW_TC);
 
        netdev->hw_enc_features |= netdev->vlan_features | NETIF_F_TSO_MANGLEID;
+
+       /* The device_version V3 hardware can't offload the checksum for IP in
+        * GRE packets, but can do it for NvGRE. So default to disable the
+        * checksum and GSO offload for GRE.
+        */
+       if (ae_dev->dev_version > HNAE3_DEVICE_VERSION_V2) {
+               netdev->features &= ~NETIF_F_GSO_GRE;
+               netdev->features &= ~NETIF_F_GSO_GRE_CSUM;
+       }
 }
 
 static int hns3_alloc_buffer(struct hns3_enet_ring *ring,
index 8ca3684..c42574e 100644 (file)
@@ -3564,9 +3564,14 @@ static u32 hclge_check_event_cause(struct hclge_dev *hdev, u32 *clearval)
 static void hclge_clear_event_cause(struct hclge_dev *hdev, u32 event_type,
                                    u32 regclr)
 {
+#define HCLGE_IMP_RESET_DELAY          5
+
        switch (event_type) {
        case HCLGE_VECTOR0_EVENT_PTP:
        case HCLGE_VECTOR0_EVENT_RST:
+               if (regclr == BIT(HCLGE_VECTOR0_IMPRESET_INT_B))
+                       mdelay(HCLGE_IMP_RESET_DELAY);
+
                hclge_write_dev(&hdev->hw, HCLGE_MISC_RESET_STS_REG, regclr);
                break;
        case HCLGE_VECTOR0_EVENT_MBX:
@@ -7348,6 +7353,12 @@ static int hclge_del_cls_flower(struct hnae3_handle *handle,
        ret = hclge_fd_tcam_config(hdev, HCLGE_FD_STAGE_1, true, rule->location,
                                   NULL, false);
        if (ret) {
+               /* if tcam config fail, set rule state to TO_DEL,
+                * so the rule will be deleted when periodic
+                * task being scheduled.
+                */
+               hclge_update_fd_list(hdev, HCLGE_FD_TO_DEL, rule->location, NULL);
+               set_bit(HCLGE_STATE_FD_TBL_CHANGED, &hdev->state);
                spin_unlock_bh(&hdev->fd_rule_lock);
                return ret;
        }
@@ -8824,7 +8835,7 @@ static void hclge_update_overflow_flags(struct hclge_vport *vport,
        if (mac_type == HCLGE_MAC_ADDR_UC) {
                if (is_all_added)
                        vport->overflow_promisc_flags &= ~HNAE3_OVERFLOW_UPE;
-               else
+               else if (hclge_is_umv_space_full(vport, true))
                        vport->overflow_promisc_flags |= HNAE3_OVERFLOW_UPE;
        } else {
                if (is_all_added)
index 7a2f923..a4d68fb 100644 (file)
@@ -1855,7 +1855,8 @@ static void hclgevf_periodic_service_task(struct hclgevf_dev *hdev)
        unsigned long delta = round_jiffies_relative(HZ);
        struct hnae3_handle *handle = &hdev->nic;
 
-       if (test_bit(HCLGEVF_STATE_RST_FAIL, &hdev->state))
+       if (test_bit(HCLGEVF_STATE_RST_FAIL, &hdev->state) ||
+           test_bit(HCLGE_COMM_STATE_CMD_DISABLE, &hdev->hw.hw.comm_state))
                return;
 
        if (time_is_after_jiffies(hdev->last_serv_processed + HZ)) {
index 9406237..f81a43d 100644 (file)
@@ -456,9 +456,6 @@ int hinic_set_vlan_fliter(struct hinic_dev *nic_dev, u32 en)
        u16 out_size = sizeof(vlan_filter);
        int err;
 
-       if (!hwdev)
-               return -EINVAL;
-
        vlan_filter.func_idx = HINIC_HWIF_FUNC_IDX(hwif);
        vlan_filter.enable = en;
 
index 832a2ae..a8d79ee 100644 (file)
@@ -1303,24 +1303,23 @@ static void ibmveth_rx_csum_helper(struct sk_buff *skb,
         * the user space for finding a flow. During this process, OVS computes
         * checksum on the first packet when CHECKSUM_PARTIAL flag is set.
         *
-        * So, re-compute TCP pseudo header checksum when configured for
-        * trunk mode.
+        * So, re-compute TCP pseudo header checksum.
         */
+
        if (iph_proto == IPPROTO_TCP) {
                struct tcphdr *tcph = (struct tcphdr *)(skb->data + iphlen);
+
                if (tcph->check == 0x0000) {
                        /* Recompute TCP pseudo header checksum  */
-                       if (adapter->is_active_trunk) {
-                               tcphdrlen = skb->len - iphlen;
-                               if (skb_proto == ETH_P_IP)
-                                       tcph->check =
-                                        ~csum_tcpudp_magic(iph->saddr,
-                                       iph->daddr, tcphdrlen, iph_proto, 0);
-                               else if (skb_proto == ETH_P_IPV6)
-                                       tcph->check =
-                                        ~csum_ipv6_magic(&iph6->saddr,
-                                       &iph6->daddr, tcphdrlen, iph_proto, 0);
-                       }
+                       tcphdrlen = skb->len - iphlen;
+                       if (skb_proto == ETH_P_IP)
+                               tcph->check =
+                                ~csum_tcpudp_magic(iph->saddr,
+                               iph->daddr, tcphdrlen, iph_proto, 0);
+                       else if (skb_proto == ETH_P_IPV6)
+                               tcph->check =
+                                ~csum_ipv6_magic(&iph6->saddr,
+                               &iph6->daddr, tcphdrlen, iph_proto, 0);
                        /* Setup SKB fields for checksum offload */
                        skb_partial_csum_set(skb, iphlen,
                                             offsetof(struct tcphdr, check));
index 8ea1a23..d3d6415 100644 (file)
@@ -4475,9 +4475,7 @@ int i40e_ndo_set_vf_port_vlan(struct net_device *netdev, int vf_id,
                goto error_pvid;
 
        i40e_vlan_stripping_enable(vsi);
-       i40e_vc_reset_vf(vf, true);
-       /* During reset the VF got a new VSI, so refresh a pointer. */
-       vsi = pf->vsi[vf->lan_vsi_idx];
+
        /* Locked once because multiple functions below iterate list */
        spin_lock_bh(&vsi->mac_filter_hash_lock);
 
@@ -4563,6 +4561,10 @@ int i40e_ndo_set_vf_port_vlan(struct net_device *netdev, int vf_id,
         */
        vf->port_vlan_id = le16_to_cpu(vsi->info.pvid);
 
+       i40e_vc_reset_vf(vf, true);
+       /* During reset the VF got a new VSI, so refresh a pointer. */
+       vsi = pf->vsi[vf->lan_vsi_idx];
+
        ret = i40e_config_vf_promiscuous_mode(vf, vsi->id, allmulti, alluni);
        if (ret) {
                dev_err(&pf->pdev->dev, "Unable to config vf promiscuous mode\n");
index 85fba85..e110ba3 100644 (file)
@@ -521,7 +521,7 @@ void iavf_down(struct iavf_adapter *adapter);
 int iavf_process_config(struct iavf_adapter *adapter);
 int iavf_parse_vf_resource_msg(struct iavf_adapter *adapter);
 void iavf_schedule_reset(struct iavf_adapter *adapter, u64 flags);
-void iavf_schedule_request_stats(struct iavf_adapter *adapter);
+void iavf_schedule_aq_request(struct iavf_adapter *adapter, u64 flags);
 void iavf_schedule_finish_config(struct iavf_adapter *adapter);
 void iavf_reset(struct iavf_adapter *adapter);
 void iavf_set_ethtool_ops(struct net_device *netdev);
index a34303a..9039729 100644 (file)
@@ -362,7 +362,7 @@ static void iavf_get_ethtool_stats(struct net_device *netdev,
        unsigned int i;
 
        /* Explicitly request stats refresh */
-       iavf_schedule_request_stats(adapter);
+       iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_REQUEST_STATS);
 
        iavf_add_ethtool_stats(&data, adapter, iavf_gstrings_stats);
 
index 7b300c8..6a2e6d6 100644 (file)
@@ -314,15 +314,13 @@ void iavf_schedule_reset(struct iavf_adapter *adapter, u64 flags)
 }
 
 /**
- * iavf_schedule_request_stats - Set the flags and schedule statistics request
+ * iavf_schedule_aq_request - Set the flags and schedule aq request
  * @adapter: board private structure
- *
- * Sets IAVF_FLAG_AQ_REQUEST_STATS flag so iavf_watchdog_task() will explicitly
- * request and refresh ethtool stats
+ * @flags: requested aq flags
  **/
-void iavf_schedule_request_stats(struct iavf_adapter *adapter)
+void iavf_schedule_aq_request(struct iavf_adapter *adapter, u64 flags)
 {
-       adapter->aq_required |= IAVF_FLAG_AQ_REQUEST_STATS;
+       adapter->aq_required |= flags;
        mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0);
 }
 
@@ -823,7 +821,7 @@ iavf_vlan_filter *iavf_add_vlan(struct iavf_adapter *adapter,
                list_add_tail(&f->list, &adapter->vlan_filter_list);
                f->state = IAVF_VLAN_ADD;
                adapter->num_vlan_filters++;
-               adapter->aq_required |= IAVF_FLAG_AQ_ADD_VLAN_FILTER;
+               iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_ADD_VLAN_FILTER);
        }
 
 clearout:
@@ -845,7 +843,7 @@ static void iavf_del_vlan(struct iavf_adapter *adapter, struct iavf_vlan vlan)
        f = iavf_find_vlan(adapter, vlan);
        if (f) {
                f->state = IAVF_VLAN_REMOVE;
-               adapter->aq_required |= IAVF_FLAG_AQ_DEL_VLAN_FILTER;
+               iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_DEL_VLAN_FILTER);
        }
 
        spin_unlock_bh(&adapter->mac_vlan_list_lock);
@@ -1421,7 +1419,8 @@ void iavf_down(struct iavf_adapter *adapter)
        iavf_clear_fdir_filters(adapter);
        iavf_clear_adv_rss_conf(adapter);
 
-       if (!(adapter->flags & IAVF_FLAG_PF_COMMS_FAILED)) {
+       if (!(adapter->flags & IAVF_FLAG_PF_COMMS_FAILED) &&
+           !(test_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section))) {
                /* cancel any current operation */
                adapter->current_op = VIRTCHNL_OP_UNKNOWN;
                /* Schedule operations to close down the HW. Don't wait
index b03426a..db97353 100644 (file)
@@ -2617,12 +2617,14 @@ static int ice_vc_query_rxdid(struct ice_vf *vf)
                goto err;
        }
 
-       /* Read flexiflag registers to determine whether the
-        * corresponding RXDID is configured and supported or not.
-        * Since Legacy 16byte descriptor format is not supported,
-        * start from Legacy 32byte descriptor.
+       /* RXDIDs supported by DDP package can be read from the register
+        * to get the supported RXDID bitmap. But the legacy 32byte RXDID
+        * is not listed in DDP package, add it in the bitmap manually.
+        * Legacy 16byte descriptor is not supported.
         */
-       for (i = ICE_RXDID_LEGACY_1; i < ICE_FLEX_DESC_RXDID_MAX_NUM; i++) {
+       rxdid->supported_rxdids |= BIT(ICE_RXDID_LEGACY_1);
+
+       for (i = ICE_RXDID_FLEX_NIC; i < ICE_FLEX_DESC_RXDID_MAX_NUM; i++) {
                regval = rd32(hw, GLFLXP_RXDID_FLAGS(i, 0));
                if ((regval >> GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_S)
                        & GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_M)
index 93bce72..7ab6dd5 100644 (file)
@@ -868,6 +868,18 @@ static void igc_ethtool_get_stats(struct net_device *netdev,
        spin_unlock(&adapter->stats64_lock);
 }
 
+static int igc_ethtool_get_previous_rx_coalesce(struct igc_adapter *adapter)
+{
+       return (adapter->rx_itr_setting <= 3) ?
+               adapter->rx_itr_setting : adapter->rx_itr_setting >> 2;
+}
+
+static int igc_ethtool_get_previous_tx_coalesce(struct igc_adapter *adapter)
+{
+       return (adapter->tx_itr_setting <= 3) ?
+               adapter->tx_itr_setting : adapter->tx_itr_setting >> 2;
+}
+
 static int igc_ethtool_get_coalesce(struct net_device *netdev,
                                    struct ethtool_coalesce *ec,
                                    struct kernel_ethtool_coalesce *kernel_coal,
@@ -875,17 +887,8 @@ static int igc_ethtool_get_coalesce(struct net_device *netdev,
 {
        struct igc_adapter *adapter = netdev_priv(netdev);
 
-       if (adapter->rx_itr_setting <= 3)
-               ec->rx_coalesce_usecs = adapter->rx_itr_setting;
-       else
-               ec->rx_coalesce_usecs = adapter->rx_itr_setting >> 2;
-
-       if (!(adapter->flags & IGC_FLAG_QUEUE_PAIRS)) {
-               if (adapter->tx_itr_setting <= 3)
-                       ec->tx_coalesce_usecs = adapter->tx_itr_setting;
-               else
-                       ec->tx_coalesce_usecs = adapter->tx_itr_setting >> 2;
-       }
+       ec->rx_coalesce_usecs = igc_ethtool_get_previous_rx_coalesce(adapter);
+       ec->tx_coalesce_usecs = igc_ethtool_get_previous_tx_coalesce(adapter);
 
        return 0;
 }
@@ -910,8 +913,12 @@ static int igc_ethtool_set_coalesce(struct net_device *netdev,
            ec->tx_coalesce_usecs == 2)
                return -EINVAL;
 
-       if ((adapter->flags & IGC_FLAG_QUEUE_PAIRS) && ec->tx_coalesce_usecs)
+       if ((adapter->flags & IGC_FLAG_QUEUE_PAIRS) &&
+           ec->tx_coalesce_usecs != igc_ethtool_get_previous_tx_coalesce(adapter)) {
+               NL_SET_ERR_MSG_MOD(extack,
+                                  "Queue Pair mode enabled, both Rx and Tx coalescing controlled by rx-usecs");
                return -EINVAL;
+       }
 
        /* If ITR is disabled, disable DMAC */
        if (ec->rx_coalesce_usecs == 0) {
index 293b457..98de34d 100644 (file)
@@ -6491,7 +6491,7 @@ static int igc_xdp_xmit(struct net_device *dev, int num_frames,
        struct igc_ring *ring;
        int i, drops;
 
-       if (unlikely(test_bit(__IGC_DOWN, &adapter->state)))
+       if (unlikely(!netif_carrier_ok(dev)))
                return -ENETDOWN;
 
        if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK))
index 4424de2..dbc518f 100644 (file)
@@ -734,13 +734,13 @@ static netdev_tx_t octep_start_xmit(struct sk_buff *skb,
 dma_map_sg_err:
        if (si > 0) {
                dma_unmap_single(iq->dev, sglist[0].dma_ptr[0],
-                                sglist[0].len[0], DMA_TO_DEVICE);
-               sglist[0].len[0] = 0;
+                                sglist[0].len[3], DMA_TO_DEVICE);
+               sglist[0].len[3] = 0;
        }
        while (si > 1) {
                dma_unmap_page(iq->dev, sglist[si >> 2].dma_ptr[si & 3],
-                              sglist[si >> 2].len[si & 3], DMA_TO_DEVICE);
-               sglist[si >> 2].len[si & 3] = 0;
+                              sglist[si >> 2].len[3 - (si & 3)], DMA_TO_DEVICE);
+               sglist[si >> 2].len[3 - (si & 3)] = 0;
                si--;
        }
        tx_buffer->gather = 0;
index 5a520d3..d0adb82 100644 (file)
@@ -69,12 +69,12 @@ int octep_iq_process_completions(struct octep_iq *iq, u16 budget)
                compl_sg++;
 
                dma_unmap_single(iq->dev, tx_buffer->sglist[0].dma_ptr[0],
-                                tx_buffer->sglist[0].len[0], DMA_TO_DEVICE);
+                                tx_buffer->sglist[0].len[3], DMA_TO_DEVICE);
 
                i = 1; /* entry 0 is main skb, unmapped above */
                while (frags--) {
                        dma_unmap_page(iq->dev, tx_buffer->sglist[i >> 2].dma_ptr[i & 3],
-                                      tx_buffer->sglist[i >> 2].len[i & 3], DMA_TO_DEVICE);
+                                      tx_buffer->sglist[i >> 2].len[3 - (i & 3)], DMA_TO_DEVICE);
                        i++;
                }
 
@@ -131,13 +131,13 @@ static void octep_iq_free_pending(struct octep_iq *iq)
 
                dma_unmap_single(iq->dev,
                                 tx_buffer->sglist[0].dma_ptr[0],
-                                tx_buffer->sglist[0].len[0],
+                                tx_buffer->sglist[0].len[3],
                                 DMA_TO_DEVICE);
 
                i = 1; /* entry 0 is main skb, unmapped above */
                while (frags--) {
                        dma_unmap_page(iq->dev, tx_buffer->sglist[i >> 2].dma_ptr[i & 3],
-                                      tx_buffer->sglist[i >> 2].len[i & 3], DMA_TO_DEVICE);
+                                      tx_buffer->sglist[i >> 2].len[3 - (i & 3)], DMA_TO_DEVICE);
                        i++;
                }
 
index 2ef5798..21e75ff 100644 (file)
 #define TX_BUFTYPE_NET_SG        2
 #define NUM_TX_BUFTYPES          3
 
-/* Hardware format for Scatter/Gather list */
+/* Hardware format for Scatter/Gather list
+ *
+ * 63      48|47     32|31     16|15       0
+ * -----------------------------------------
+ * |  Len 0  |  Len 1  |  Len 2  |  Len 3  |
+ * -----------------------------------------
+ * |                Ptr 0                  |
+ * -----------------------------------------
+ * |                Ptr 1                  |
+ * -----------------------------------------
+ * |                Ptr 2                  |
+ * -----------------------------------------
+ * |                Ptr 3                  |
+ * -----------------------------------------
+ */
 struct octep_tx_sglist_desc {
        u16 len[4];
        dma_addr_t dma_ptr[4];
index e77d438..53b2a4e 100644 (file)
@@ -29,7 +29,8 @@
 static bool otx2_xdp_rcv_pkt_handler(struct otx2_nic *pfvf,
                                     struct bpf_prog *prog,
                                     struct nix_cqe_rx_s *cqe,
-                                    struct otx2_cq_queue *cq);
+                                    struct otx2_cq_queue *cq,
+                                    bool *need_xdp_flush);
 
 static int otx2_nix_cq_op_status(struct otx2_nic *pfvf,
                                 struct otx2_cq_queue *cq)
@@ -337,7 +338,7 @@ static bool otx2_check_rcv_errors(struct otx2_nic *pfvf,
 static void otx2_rcv_pkt_handler(struct otx2_nic *pfvf,
                                 struct napi_struct *napi,
                                 struct otx2_cq_queue *cq,
-                                struct nix_cqe_rx_s *cqe)
+                                struct nix_cqe_rx_s *cqe, bool *need_xdp_flush)
 {
        struct nix_rx_parse_s *parse = &cqe->parse;
        struct nix_rx_sg_s *sg = &cqe->sg;
@@ -353,7 +354,7 @@ static void otx2_rcv_pkt_handler(struct otx2_nic *pfvf,
        }
 
        if (pfvf->xdp_prog)
-               if (otx2_xdp_rcv_pkt_handler(pfvf, pfvf->xdp_prog, cqe, cq))
+               if (otx2_xdp_rcv_pkt_handler(pfvf, pfvf->xdp_prog, cqe, cq, need_xdp_flush))
                        return;
 
        skb = napi_get_frags(napi);
@@ -388,6 +389,7 @@ static int otx2_rx_napi_handler(struct otx2_nic *pfvf,
                                struct napi_struct *napi,
                                struct otx2_cq_queue *cq, int budget)
 {
+       bool need_xdp_flush = false;
        struct nix_cqe_rx_s *cqe;
        int processed_cqe = 0;
 
@@ -409,13 +411,15 @@ process_cqe:
                cq->cq_head++;
                cq->cq_head &= (cq->cqe_cnt - 1);
 
-               otx2_rcv_pkt_handler(pfvf, napi, cq, cqe);
+               otx2_rcv_pkt_handler(pfvf, napi, cq, cqe, &need_xdp_flush);
 
                cqe->hdr.cqe_type = NIX_XQE_TYPE_INVALID;
                cqe->sg.seg_addr = 0x00;
                processed_cqe++;
                cq->pend_cqe--;
        }
+       if (need_xdp_flush)
+               xdp_do_flush();
 
        /* Free CQEs to HW */
        otx2_write64(pfvf, NIX_LF_CQ_OP_DOOR,
@@ -1354,7 +1358,8 @@ bool otx2_xdp_sq_append_pkt(struct otx2_nic *pfvf, u64 iova, int len, u16 qidx)
 static bool otx2_xdp_rcv_pkt_handler(struct otx2_nic *pfvf,
                                     struct bpf_prog *prog,
                                     struct nix_cqe_rx_s *cqe,
-                                    struct otx2_cq_queue *cq)
+                                    struct otx2_cq_queue *cq,
+                                    bool *need_xdp_flush)
 {
        unsigned char *hard_start, *data;
        int qidx = cq->cq_idx;
@@ -1391,8 +1396,10 @@ static bool otx2_xdp_rcv_pkt_handler(struct otx2_nic *pfvf,
 
                otx2_dma_unmap_page(pfvf, iova, pfvf->rbsize,
                                    DMA_FROM_DEVICE);
-               if (!err)
+               if (!err) {
+                       *need_xdp_flush = true;
                        return true;
+               }
                put_page(page);
                break;
        default:
index ddec162..8d0bacf 100644 (file)
@@ -2195,7 +2195,7 @@ struct rx_ring_info {
        struct sk_buff  *skb;
        dma_addr_t      data_addr;
        DEFINE_DMA_UNMAP_LEN(data_size);
-       dma_addr_t      frag_addr[ETH_JUMBO_MTU >> PAGE_SHIFT];
+       dma_addr_t      frag_addr[ETH_JUMBO_MTU >> PAGE_SHIFT ?: 1];
 };
 
 enum flow_control {
index 3cffd1b..20afe79 100644 (file)
@@ -3171,8 +3171,8 @@ static irqreturn_t mtk_handle_irq_rx(int irq, void *_eth)
 
        eth->rx_events++;
        if (likely(napi_schedule_prep(&eth->rx_napi))) {
-               __napi_schedule(&eth->rx_napi);
                mtk_rx_irq_disable(eth, eth->soc->txrx.rx_irq_done_mask);
+               __napi_schedule(&eth->rx_napi);
        }
 
        return IRQ_HANDLED;
@@ -3184,8 +3184,8 @@ static irqreturn_t mtk_handle_irq_tx(int irq, void *_eth)
 
        eth->tx_events++;
        if (likely(napi_schedule_prep(&eth->tx_napi))) {
-               __napi_schedule(&eth->tx_napi);
                mtk_tx_irq_disable(eth, MTK_TX_DONE_INT);
+               __napi_schedule(&eth->tx_napi);
        }
 
        return IRQ_HANDLED;
index 329e374..43ba71e 100644 (file)
@@ -46,6 +46,7 @@ config LAN743X
        tristate "LAN743x support"
        depends on PCI
        depends on PTP_1588_CLOCK_OPTIONAL
+       select PHYLIB
        select FIXED_PHY
        select CRC16
        select CRC32
index c07f25e..fe4e166 100644 (file)
@@ -243,10 +243,9 @@ static void vcap_test_api_init(struct vcap_admin *admin)
 }
 
 /* Helper function to create a rule of a specific size */
-static struct vcap_rule *
-test_vcap_xn_rule_creator(struct kunit *test, int cid, enum vcap_user user,
-                         u16 priority,
-                         int id, int size, int expected_addr)
+static void test_vcap_xn_rule_creator(struct kunit *test, int cid,
+                                     enum vcap_user user, u16 priority,
+                                     int id, int size, int expected_addr)
 {
        struct vcap_rule *rule;
        struct vcap_rule_internal *ri;
@@ -311,7 +310,7 @@ test_vcap_xn_rule_creator(struct kunit *test, int cid, enum vcap_user user,
        ret = vcap_add_rule(rule);
        KUNIT_EXPECT_EQ(test, 0, ret);
        KUNIT_EXPECT_EQ(test, expected_addr, ri->addr);
-       return rule;
+       vcap_free_rule(rule);
 }
 
 /* Prepare testing rule deletion */
@@ -995,6 +994,16 @@ static void vcap_api_encode_rule_actionset_test(struct kunit *test)
        KUNIT_EXPECT_EQ(test, (u32)0x00000000, actwords[11]);
 }
 
+static void vcap_free_ckf(struct vcap_rule *rule)
+{
+       struct vcap_client_keyfield *ckf, *next_ckf;
+
+       list_for_each_entry_safe(ckf, next_ckf, &rule->keyfields, ctrl.list) {
+               list_del(&ckf->ctrl.list);
+               kfree(ckf);
+       }
+}
+
 static void vcap_api_rule_add_keyvalue_test(struct kunit *test)
 {
        struct vcap_admin admin = {
@@ -1027,6 +1036,7 @@ static void vcap_api_rule_add_keyvalue_test(struct kunit *test)
        KUNIT_EXPECT_EQ(test, VCAP_FIELD_BIT, kf->ctrl.type);
        KUNIT_EXPECT_EQ(test, 0x0, kf->data.u1.value);
        KUNIT_EXPECT_EQ(test, 0x1, kf->data.u1.mask);
+       vcap_free_ckf(rule);
 
        INIT_LIST_HEAD(&rule->keyfields);
        ret = vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS, VCAP_BIT_1);
@@ -1039,6 +1049,7 @@ static void vcap_api_rule_add_keyvalue_test(struct kunit *test)
        KUNIT_EXPECT_EQ(test, VCAP_FIELD_BIT, kf->ctrl.type);
        KUNIT_EXPECT_EQ(test, 0x1, kf->data.u1.value);
        KUNIT_EXPECT_EQ(test, 0x1, kf->data.u1.mask);
+       vcap_free_ckf(rule);
 
        INIT_LIST_HEAD(&rule->keyfields);
        ret = vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS,
@@ -1052,6 +1063,7 @@ static void vcap_api_rule_add_keyvalue_test(struct kunit *test)
        KUNIT_EXPECT_EQ(test, VCAP_FIELD_BIT, kf->ctrl.type);
        KUNIT_EXPECT_EQ(test, 0x0, kf->data.u1.value);
        KUNIT_EXPECT_EQ(test, 0x0, kf->data.u1.mask);
+       vcap_free_ckf(rule);
 
        INIT_LIST_HEAD(&rule->keyfields);
        ret = vcap_rule_add_key_u32(rule, VCAP_KF_TYPE, 0x98765432, 0xff00ffab);
@@ -1064,6 +1076,7 @@ static void vcap_api_rule_add_keyvalue_test(struct kunit *test)
        KUNIT_EXPECT_EQ(test, VCAP_FIELD_U32, kf->ctrl.type);
        KUNIT_EXPECT_EQ(test, 0x98765432, kf->data.u32.value);
        KUNIT_EXPECT_EQ(test, 0xff00ffab, kf->data.u32.mask);
+       vcap_free_ckf(rule);
 
        INIT_LIST_HEAD(&rule->keyfields);
        ret = vcap_rule_add_key_u128(rule, VCAP_KF_L3_IP6_SIP, &dip);
@@ -1078,6 +1091,18 @@ static void vcap_api_rule_add_keyvalue_test(struct kunit *test)
                KUNIT_EXPECT_EQ(test, dip.value[idx], kf->data.u128.value[idx]);
        for (idx = 0; idx < ARRAY_SIZE(dip.mask); ++idx)
                KUNIT_EXPECT_EQ(test, dip.mask[idx], kf->data.u128.mask[idx]);
+       vcap_free_ckf(rule);
+}
+
+static void vcap_free_caf(struct vcap_rule *rule)
+{
+       struct vcap_client_actionfield *caf, *next_caf;
+
+       list_for_each_entry_safe(caf, next_caf,
+                                &rule->actionfields, ctrl.list) {
+               list_del(&caf->ctrl.list);
+               kfree(caf);
+       }
 }
 
 static void vcap_api_rule_add_actionvalue_test(struct kunit *test)
@@ -1105,6 +1130,7 @@ static void vcap_api_rule_add_actionvalue_test(struct kunit *test)
        KUNIT_EXPECT_EQ(test, VCAP_AF_POLICE_ENA, af->ctrl.action);
        KUNIT_EXPECT_EQ(test, VCAP_FIELD_BIT, af->ctrl.type);
        KUNIT_EXPECT_EQ(test, 0x0, af->data.u1.value);
+       vcap_free_caf(rule);
 
        INIT_LIST_HEAD(&rule->actionfields);
        ret = vcap_rule_add_action_bit(rule, VCAP_AF_POLICE_ENA, VCAP_BIT_1);
@@ -1116,6 +1142,7 @@ static void vcap_api_rule_add_actionvalue_test(struct kunit *test)
        KUNIT_EXPECT_EQ(test, VCAP_AF_POLICE_ENA, af->ctrl.action);
        KUNIT_EXPECT_EQ(test, VCAP_FIELD_BIT, af->ctrl.type);
        KUNIT_EXPECT_EQ(test, 0x1, af->data.u1.value);
+       vcap_free_caf(rule);
 
        INIT_LIST_HEAD(&rule->actionfields);
        ret = vcap_rule_add_action_bit(rule, VCAP_AF_POLICE_ENA, VCAP_BIT_ANY);
@@ -1127,6 +1154,7 @@ static void vcap_api_rule_add_actionvalue_test(struct kunit *test)
        KUNIT_EXPECT_EQ(test, VCAP_AF_POLICE_ENA, af->ctrl.action);
        KUNIT_EXPECT_EQ(test, VCAP_FIELD_BIT, af->ctrl.type);
        KUNIT_EXPECT_EQ(test, 0x0, af->data.u1.value);
+       vcap_free_caf(rule);
 
        INIT_LIST_HEAD(&rule->actionfields);
        ret = vcap_rule_add_action_u32(rule, VCAP_AF_TYPE, 0x98765432);
@@ -1138,6 +1166,7 @@ static void vcap_api_rule_add_actionvalue_test(struct kunit *test)
        KUNIT_EXPECT_EQ(test, VCAP_AF_TYPE, af->ctrl.action);
        KUNIT_EXPECT_EQ(test, VCAP_FIELD_U32, af->ctrl.type);
        KUNIT_EXPECT_EQ(test, 0x98765432, af->data.u32.value);
+       vcap_free_caf(rule);
 
        INIT_LIST_HEAD(&rule->actionfields);
        ret = vcap_rule_add_action_u32(rule, VCAP_AF_MASK_MODE, 0xaabbccdd);
@@ -1149,6 +1178,7 @@ static void vcap_api_rule_add_actionvalue_test(struct kunit *test)
        KUNIT_EXPECT_EQ(test, VCAP_AF_MASK_MODE, af->ctrl.action);
        KUNIT_EXPECT_EQ(test, VCAP_FIELD_U32, af->ctrl.type);
        KUNIT_EXPECT_EQ(test, 0xaabbccdd, af->data.u32.value);
+       vcap_free_caf(rule);
 }
 
 static void vcap_api_rule_find_keyset_basic_test(struct kunit *test)
@@ -1408,6 +1438,10 @@ static void vcap_api_encode_rule_test(struct kunit *test)
        ret = list_empty(&is2_admin.rules);
        KUNIT_EXPECT_EQ(test, false, ret);
        KUNIT_EXPECT_EQ(test, 0, ret);
+
+       vcap_enable_lookups(&test_vctrl, &test_netdev, 0, 0,
+                           rule->cookie, false);
+
        vcap_free_rule(rule);
 
        /* Check that the rule has been freed: tricky to access since this
@@ -1418,6 +1452,8 @@ static void vcap_api_encode_rule_test(struct kunit *test)
        KUNIT_EXPECT_EQ(test, true, ret);
        ret = list_empty(&rule->actionfields);
        KUNIT_EXPECT_EQ(test, true, ret);
+
+       vcap_del_rule(&test_vctrl, &test_netdev, id);
 }
 
 static void vcap_api_set_rule_counter_test(struct kunit *test)
@@ -1561,6 +1597,11 @@ static void vcap_api_rule_insert_in_order_test(struct kunit *test)
        test_vcap_xn_rule_creator(test, 10000, VCAP_USER_QOS, 20, 400, 6, 774);
        test_vcap_xn_rule_creator(test, 10000, VCAP_USER_QOS, 30, 300, 3, 771);
        test_vcap_xn_rule_creator(test, 10000, VCAP_USER_QOS, 40, 200, 2, 768);
+
+       vcap_del_rule(&test_vctrl, &test_netdev, 200);
+       vcap_del_rule(&test_vctrl, &test_netdev, 300);
+       vcap_del_rule(&test_vctrl, &test_netdev, 400);
+       vcap_del_rule(&test_vctrl, &test_netdev, 500);
 }
 
 static void vcap_api_rule_insert_reverse_order_test(struct kunit *test)
@@ -1619,6 +1660,11 @@ static void vcap_api_rule_insert_reverse_order_test(struct kunit *test)
                ++idx;
        }
        KUNIT_EXPECT_EQ(test, 768, admin.last_used_addr);
+
+       vcap_del_rule(&test_vctrl, &test_netdev, 500);
+       vcap_del_rule(&test_vctrl, &test_netdev, 400);
+       vcap_del_rule(&test_vctrl, &test_netdev, 300);
+       vcap_del_rule(&test_vctrl, &test_netdev, 200);
 }
 
 static void vcap_api_rule_remove_at_end_test(struct kunit *test)
@@ -1819,6 +1865,9 @@ static void vcap_api_rule_remove_in_front_test(struct kunit *test)
        KUNIT_EXPECT_EQ(test, 786, test_init_start);
        KUNIT_EXPECT_EQ(test, 8, test_init_count);
        KUNIT_EXPECT_EQ(test, 794, admin.last_used_addr);
+
+       vcap_del_rule(&test_vctrl, &test_netdev, 200);
+       vcap_del_rule(&test_vctrl, &test_netdev, 300);
 }
 
 static struct kunit_case vcap_api_rule_remove_test_cases[] = {
index 4a16ebf..48ea4ae 100644 (file)
@@ -91,63 +91,137 @@ static unsigned int mana_checksum_info(struct sk_buff *skb)
        return 0;
 }
 
+static void mana_add_sge(struct mana_tx_package *tp, struct mana_skb_head *ash,
+                        int sg_i, dma_addr_t da, int sge_len, u32 gpa_mkey)
+{
+       ash->dma_handle[sg_i] = da;
+       ash->size[sg_i] = sge_len;
+
+       tp->wqe_req.sgl[sg_i].address = da;
+       tp->wqe_req.sgl[sg_i].mem_key = gpa_mkey;
+       tp->wqe_req.sgl[sg_i].size = sge_len;
+}
+
 static int mana_map_skb(struct sk_buff *skb, struct mana_port_context *apc,
-                       struct mana_tx_package *tp)
+                       struct mana_tx_package *tp, int gso_hs)
 {
        struct mana_skb_head *ash = (struct mana_skb_head *)skb->head;
+       int hsg = 1; /* num of SGEs of linear part */
        struct gdma_dev *gd = apc->ac->gdma_dev;
+       int skb_hlen = skb_headlen(skb);
+       int sge0_len, sge1_len = 0;
        struct gdma_context *gc;
        struct device *dev;
        skb_frag_t *frag;
        dma_addr_t da;
+       int sg_i;
        int i;
 
        gc = gd->gdma_context;
        dev = gc->dev;
-       da = dma_map_single(dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE);
 
+       if (gso_hs && gso_hs < skb_hlen) {
+               sge0_len = gso_hs;
+               sge1_len = skb_hlen - gso_hs;
+       } else {
+               sge0_len = skb_hlen;
+       }
+
+       da = dma_map_single(dev, skb->data, sge0_len, DMA_TO_DEVICE);
        if (dma_mapping_error(dev, da))
                return -ENOMEM;
 
-       ash->dma_handle[0] = da;
-       ash->size[0] = skb_headlen(skb);
+       mana_add_sge(tp, ash, 0, da, sge0_len, gd->gpa_mkey);
 
-       tp->wqe_req.sgl[0].address = ash->dma_handle[0];
-       tp->wqe_req.sgl[0].mem_key = gd->gpa_mkey;
-       tp->wqe_req.sgl[0].size = ash->size[0];
+       if (sge1_len) {
+               sg_i = 1;
+               da = dma_map_single(dev, skb->data + sge0_len, sge1_len,
+                                   DMA_TO_DEVICE);
+               if (dma_mapping_error(dev, da))
+                       goto frag_err;
+
+               mana_add_sge(tp, ash, sg_i, da, sge1_len, gd->gpa_mkey);
+               hsg = 2;
+       }
 
        for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+               sg_i = hsg + i;
+
                frag = &skb_shinfo(skb)->frags[i];
                da = skb_frag_dma_map(dev, frag, 0, skb_frag_size(frag),
                                      DMA_TO_DEVICE);
-
                if (dma_mapping_error(dev, da))
                        goto frag_err;
 
-               ash->dma_handle[i + 1] = da;
-               ash->size[i + 1] = skb_frag_size(frag);
-
-               tp->wqe_req.sgl[i + 1].address = ash->dma_handle[i + 1];
-               tp->wqe_req.sgl[i + 1].mem_key = gd->gpa_mkey;
-               tp->wqe_req.sgl[i + 1].size = ash->size[i + 1];
+               mana_add_sge(tp, ash, sg_i, da, skb_frag_size(frag),
+                            gd->gpa_mkey);
        }
 
        return 0;
 
 frag_err:
-       for (i = i - 1; i >= 0; i--)
-               dma_unmap_page(dev, ash->dma_handle[i + 1], ash->size[i + 1],
+       for (i = sg_i - 1; i >= hsg; i--)
+               dma_unmap_page(dev, ash->dma_handle[i], ash->size[i],
                               DMA_TO_DEVICE);
 
-       dma_unmap_single(dev, ash->dma_handle[0], ash->size[0], DMA_TO_DEVICE);
+       for (i = hsg - 1; i >= 0; i--)
+               dma_unmap_single(dev, ash->dma_handle[i], ash->size[i],
+                                DMA_TO_DEVICE);
 
        return -ENOMEM;
 }
 
+/* Handle the case when GSO SKB linear length is too large.
+ * MANA NIC requires GSO packets to put only the packet header to SGE0.
+ * So, we need 2 SGEs for the skb linear part which contains more than the
+ * header.
+ * Return a positive value for the number of SGEs, or a negative value
+ * for an error.
+ */
+static int mana_fix_skb_head(struct net_device *ndev, struct sk_buff *skb,
+                            int gso_hs)
+{
+       int num_sge = 1 + skb_shinfo(skb)->nr_frags;
+       int skb_hlen = skb_headlen(skb);
+
+       if (gso_hs < skb_hlen) {
+               num_sge++;
+       } else if (gso_hs > skb_hlen) {
+               if (net_ratelimit())
+                       netdev_err(ndev,
+                                  "TX nonlinear head: hs:%d, skb_hlen:%d\n",
+                                  gso_hs, skb_hlen);
+
+               return -EINVAL;
+       }
+
+       return num_sge;
+}
+
+/* Get the GSO packet's header size */
+static int mana_get_gso_hs(struct sk_buff *skb)
+{
+       int gso_hs;
+
+       if (skb->encapsulation) {
+               gso_hs = skb_inner_tcp_all_headers(skb);
+       } else {
+               if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) {
+                       gso_hs = skb_transport_offset(skb) +
+                                sizeof(struct udphdr);
+               } else {
+                       gso_hs = skb_tcp_all_headers(skb);
+               }
+       }
+
+       return gso_hs;
+}
+
 netdev_tx_t mana_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 {
        enum mana_tx_pkt_format pkt_fmt = MANA_SHORT_PKT_FMT;
        struct mana_port_context *apc = netdev_priv(ndev);
+       int gso_hs = 0; /* zero for non-GSO pkts */
        u16 txq_idx = skb_get_queue_mapping(skb);
        struct gdma_dev *gd = apc->ac->gdma_dev;
        bool ipv4 = false, ipv6 = false;
@@ -159,7 +233,6 @@ netdev_tx_t mana_start_xmit(struct sk_buff *skb, struct net_device *ndev)
        struct mana_txq *txq;
        struct mana_cq *cq;
        int err, len;
-       u16 ihs;
 
        if (unlikely(!apc->port_is_up))
                goto tx_drop;
@@ -209,19 +282,6 @@ netdev_tx_t mana_start_xmit(struct sk_buff *skb, struct net_device *ndev)
        pkg.wqe_req.client_data_unit = 0;
 
        pkg.wqe_req.num_sge = 1 + skb_shinfo(skb)->nr_frags;
-       WARN_ON_ONCE(pkg.wqe_req.num_sge > MAX_TX_WQE_SGL_ENTRIES);
-
-       if (pkg.wqe_req.num_sge <= ARRAY_SIZE(pkg.sgl_array)) {
-               pkg.wqe_req.sgl = pkg.sgl_array;
-       } else {
-               pkg.sgl_ptr = kmalloc_array(pkg.wqe_req.num_sge,
-                                           sizeof(struct gdma_sge),
-                                           GFP_ATOMIC);
-               if (!pkg.sgl_ptr)
-                       goto tx_drop_count;
-
-               pkg.wqe_req.sgl = pkg.sgl_ptr;
-       }
 
        if (skb->protocol == htons(ETH_P_IP))
                ipv4 = true;
@@ -229,6 +289,26 @@ netdev_tx_t mana_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                ipv6 = true;
 
        if (skb_is_gso(skb)) {
+               int num_sge;
+
+               gso_hs = mana_get_gso_hs(skb);
+
+               num_sge = mana_fix_skb_head(ndev, skb, gso_hs);
+               if (num_sge > 0)
+                       pkg.wqe_req.num_sge = num_sge;
+               else
+                       goto tx_drop_count;
+
+               u64_stats_update_begin(&tx_stats->syncp);
+               if (skb->encapsulation) {
+                       tx_stats->tso_inner_packets++;
+                       tx_stats->tso_inner_bytes += skb->len - gso_hs;
+               } else {
+                       tx_stats->tso_packets++;
+                       tx_stats->tso_bytes += skb->len - gso_hs;
+               }
+               u64_stats_update_end(&tx_stats->syncp);
+
                pkg.tx_oob.s_oob.is_outer_ipv4 = ipv4;
                pkg.tx_oob.s_oob.is_outer_ipv6 = ipv6;
 
@@ -252,28 +332,6 @@ netdev_tx_t mana_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                                                 &ipv6_hdr(skb)->daddr, 0,
                                                 IPPROTO_TCP, 0);
                }
-
-               if (skb->encapsulation) {
-                       ihs = skb_inner_tcp_all_headers(skb);
-                       u64_stats_update_begin(&tx_stats->syncp);
-                       tx_stats->tso_inner_packets++;
-                       tx_stats->tso_inner_bytes += skb->len - ihs;
-                       u64_stats_update_end(&tx_stats->syncp);
-               } else {
-                       if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) {
-                               ihs = skb_transport_offset(skb) + sizeof(struct udphdr);
-                       } else {
-                               ihs = skb_tcp_all_headers(skb);
-                               if (ipv6_has_hopopt_jumbo(skb))
-                                       ihs -= sizeof(struct hop_jumbo_hdr);
-                       }
-
-                       u64_stats_update_begin(&tx_stats->syncp);
-                       tx_stats->tso_packets++;
-                       tx_stats->tso_bytes += skb->len - ihs;
-                       u64_stats_update_end(&tx_stats->syncp);
-               }
-
        } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
                csum_type = mana_checksum_info(skb);
 
@@ -296,11 +354,25 @@ netdev_tx_t mana_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                } else {
                        /* Can't do offload of this type of checksum */
                        if (skb_checksum_help(skb))
-                               goto free_sgl_ptr;
+                               goto tx_drop_count;
                }
        }
 
-       if (mana_map_skb(skb, apc, &pkg)) {
+       WARN_ON_ONCE(pkg.wqe_req.num_sge > MAX_TX_WQE_SGL_ENTRIES);
+
+       if (pkg.wqe_req.num_sge <= ARRAY_SIZE(pkg.sgl_array)) {
+               pkg.wqe_req.sgl = pkg.sgl_array;
+       } else {
+               pkg.sgl_ptr = kmalloc_array(pkg.wqe_req.num_sge,
+                                           sizeof(struct gdma_sge),
+                                           GFP_ATOMIC);
+               if (!pkg.sgl_ptr)
+                       goto tx_drop_count;
+
+               pkg.wqe_req.sgl = pkg.sgl_ptr;
+       }
+
+       if (mana_map_skb(skb, apc, &pkg, gso_hs)) {
                u64_stats_update_begin(&tx_stats->syncp);
                tx_stats->mana_map_err++;
                u64_stats_update_end(&tx_stats->syncp);
@@ -1258,11 +1330,16 @@ static void mana_unmap_skb(struct sk_buff *skb, struct mana_port_context *apc)
        struct mana_skb_head *ash = (struct mana_skb_head *)skb->head;
        struct gdma_context *gc = apc->ac->gdma_dev->gdma_context;
        struct device *dev = gc->dev;
-       int i;
+       int hsg, i;
 
-       dma_unmap_single(dev, ash->dma_handle[0], ash->size[0], DMA_TO_DEVICE);
+       /* Number of SGEs of linear part */
+       hsg = (skb_is_gso(skb) && skb_headlen(skb) > ash->size[0]) ? 2 : 1;
 
-       for (i = 1; i < skb_shinfo(skb)->nr_frags + 1; i++)
+       for (i = 0; i < hsg; i++)
+               dma_unmap_single(dev, ash->dma_handle[i], ash->size[i],
+                                DMA_TO_DEVICE);
+
+       for (i = hsg; i < skb_shinfo(skb)->nr_frags + hsg; i++)
                dma_unmap_page(dev, ash->dma_handle[i], ash->size[i],
                               DMA_TO_DEVICE);
 }
@@ -1317,19 +1394,23 @@ static void mana_poll_tx_cq(struct mana_cq *cq)
                case CQE_TX_VPORT_IDX_OUT_OF_RANGE:
                case CQE_TX_VPORT_DISABLED:
                case CQE_TX_VLAN_TAGGING_VIOLATION:
-                       WARN_ONCE(1, "TX: CQE error %d: ignored.\n",
-                                 cqe_oob->cqe_hdr.cqe_type);
+                       if (net_ratelimit())
+                               netdev_err(ndev, "TX: CQE error %d\n",
+                                          cqe_oob->cqe_hdr.cqe_type);
+
                        apc->eth_stats.tx_cqe_err++;
                        break;
 
                default:
-                       /* If the CQE type is unexpected, log an error, assert,
-                        * and go through the error path.
+                       /* If the CQE type is unknown, log an error,
+                        * and still free the SKB, update tail, etc.
                         */
-                       WARN_ONCE(1, "TX: Unexpected CQE type %d: HW BUG?\n",
-                                 cqe_oob->cqe_hdr.cqe_type);
+                       if (net_ratelimit())
+                               netdev_err(ndev, "TX: unknown CQE type %d\n",
+                                          cqe_oob->cqe_hdr.cqe_type);
+
                        apc->eth_stats.tx_cqe_unknown_type++;
-                       return;
+                       break;
                }
 
                if (WARN_ON_ONCE(txq->gdma_txq_id != completions[i].wq_num))
index 6aac98b..aae4131 100644 (file)
@@ -187,6 +187,7 @@ typedef void (*ionic_desc_cb)(struct ionic_queue *q,
                              struct ionic_desc_info *desc_info,
                              struct ionic_cq_info *cq_info, void *cb_arg);
 
+#define IONIC_MAX_BUF_LEN                      ((u16)-1)
 #define IONIC_PAGE_SIZE                                PAGE_SIZE
 #define IONIC_PAGE_SPLIT_SZ                    (PAGE_SIZE / 2)
 #define IONIC_PAGE_GFP_MASK                    (GFP_ATOMIC | __GFP_NOWARN |\
index 26798fc..44466e8 100644 (file)
@@ -207,7 +207,8 @@ static struct sk_buff *ionic_rx_frags(struct ionic_queue *q,
                        return NULL;
                }
 
-               frag_len = min_t(u16, len, IONIC_PAGE_SIZE - buf_info->page_offset);
+               frag_len = min_t(u16, len, min_t(u32, IONIC_MAX_BUF_LEN,
+                                                IONIC_PAGE_SIZE - buf_info->page_offset));
                len -= frag_len;
 
                dma_sync_single_for_cpu(dev,
@@ -452,7 +453,8 @@ void ionic_rx_fill(struct ionic_queue *q)
 
                /* fill main descriptor - buf[0] */
                desc->addr = cpu_to_le64(buf_info->dma_addr + buf_info->page_offset);
-               frag_len = min_t(u16, len, IONIC_PAGE_SIZE - buf_info->page_offset);
+               frag_len = min_t(u16, len, min_t(u32, IONIC_MAX_BUF_LEN,
+                                                IONIC_PAGE_SIZE - buf_info->page_offset));
                desc->len = cpu_to_le16(frag_len);
                remain_len -= frag_len;
                buf_info++;
@@ -471,7 +473,9 @@ void ionic_rx_fill(struct ionic_queue *q)
                        }
 
                        sg_elem->addr = cpu_to_le64(buf_info->dma_addr + buf_info->page_offset);
-                       frag_len = min_t(u16, remain_len, IONIC_PAGE_SIZE - buf_info->page_offset);
+                       frag_len = min_t(u16, remain_len, min_t(u32, IONIC_MAX_BUF_LEN,
+                                                               IONIC_PAGE_SIZE -
+                                                               buf_info->page_offset));
                        sg_elem->len = cpu_to_le16(frag_len);
                        remain_len -= frag_len;
                        buf_info++;
index 0bfc375..a174c6f 100644 (file)
@@ -110,9 +110,9 @@ struct qed_ll2_info {
        enum core_tx_dest tx_dest;
        u8 tx_stats_en;
        bool main_func_queue;
+       struct qed_ll2_cbs cbs;
        struct qed_ll2_rx_queue rx_queue;
        struct qed_ll2_tx_queue tx_queue;
-       struct qed_ll2_cbs cbs;
 };
 
 extern const struct qed_ll2_ops qed_ll2_ops_pass;
index ea91861..fc01ad3 100644 (file)
@@ -4,6 +4,7 @@
  * Copyright (C) 2022 Renesas Electronics Corporation
  */
 
+#include <linux/clk.h>
 #include <linux/dma-mapping.h>
 #include <linux/err.h>
 #include <linux/etherdevice.h>
@@ -1049,7 +1050,7 @@ static void rswitch_rmac_setting(struct rswitch_etha *etha, const u8 *mac)
 static void rswitch_etha_enable_mii(struct rswitch_etha *etha)
 {
        rswitch_modify(etha->addr, MPIC, MPIC_PSMCS_MASK | MPIC_PSMHT_MASK,
-                      MPIC_PSMCS(0x05) | MPIC_PSMHT(0x06));
+                      MPIC_PSMCS(etha->psmcs) | MPIC_PSMHT(0x06));
        rswitch_modify(etha->addr, MPSM, 0, MPSM_MFF_C45);
 }
 
@@ -1693,6 +1694,12 @@ static void rswitch_etha_init(struct rswitch_private *priv, int index)
        etha->index = index;
        etha->addr = priv->addr + RSWITCH_ETHA_OFFSET + index * RSWITCH_ETHA_SIZE;
        etha->coma_addr = priv->addr;
+
+       /* MPIC.PSMCS = (clk [MHz] / (MDC frequency [MHz] * 2) - 1.
+        * Calculating PSMCS value as MDC frequency = 2.5MHz. So, multiply
+        * both the numerator and the denominator by 10.
+        */
+       etha->psmcs = clk_get_rate(priv->clk) / 100000 / (25 * 2) - 1;
 }
 
 static int rswitch_device_alloc(struct rswitch_private *priv, int index)
@@ -1900,6 +1907,10 @@ static int renesas_eth_sw_probe(struct platform_device *pdev)
                return -ENOMEM;
        spin_lock_init(&priv->lock);
 
+       priv->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(priv->clk))
+               return PTR_ERR(priv->clk);
+
        attr = soc_device_match(rswitch_soc_no_speed_change);
        if (attr)
                priv->etha_no_runtime_change = true;
index f0c16a3..04f49a7 100644 (file)
@@ -915,6 +915,7 @@ struct rswitch_etha {
        bool external_phy;
        struct mii_bus *mii;
        phy_interface_t phy_interface;
+       u32 psmcs;
        u8 mac_addr[MAX_ADDR_LEN];
        int link;
        int speed;
@@ -1012,6 +1013,7 @@ struct rswitch_private {
        struct rswitch_mfwd mfwd;
 
        spinlock_t lock;        /* lock interrupt registers' control */
+       struct clk *clk;
 
        bool etha_no_runtime_change;
        bool gwca_halt;
index 047322b..834f000 100644 (file)
@@ -136,6 +136,8 @@ static struct efx_tc_mac_pedit_action *efx_tc_flower_get_mac(struct efx_nic *efx
        if (old) {
                /* don't need our new entry */
                kfree(ped);
+               if (IS_ERR(old)) /* oh dear, it's actually an error */
+                       return ERR_CAST(old);
                if (!refcount_inc_not_zero(&old->ref))
                        return ERR_PTR(-EAGAIN);
                /* existing entry found, ref taken */
@@ -602,6 +604,8 @@ static int efx_tc_flower_record_encap_match(struct efx_nic *efx,
                kfree(encap);
                if (pseudo) /* don't need our new pseudo either */
                        efx_tc_flower_release_encap_match(efx, pseudo);
+               if (IS_ERR(old)) /* oh dear, it's actually an error */
+                       return PTR_ERR(old);
                /* check old and new em_types are compatible */
                switch (old->type) {
                case EFX_TC_EM_DIRECT:
@@ -700,6 +704,8 @@ static struct efx_tc_recirc_id *efx_tc_get_recirc_id(struct efx_nic *efx,
        if (old) {
                /* don't need our new entry */
                kfree(rid);
+               if (IS_ERR(old)) /* oh dear, it's actually an error */
+                       return ERR_CAST(old);
                if (!refcount_inc_not_zero(&old->ref))
                        return ERR_PTR(-EAGAIN);
                /* existing entry found */
@@ -1482,7 +1488,10 @@ static int efx_tc_flower_replace_foreign(struct efx_nic *efx,
        old = rhashtable_lookup_get_insert_fast(&efx->tc->match_action_ht,
                                                &rule->linkage,
                                                efx_tc_match_action_ht_params);
-       if (old) {
+       if (IS_ERR(old)) {
+               rc = PTR_ERR(old);
+               goto release;
+       } else if (old) {
                netif_dbg(efx, drv, efx->net_dev,
                          "Ignoring already-offloaded rule (cookie %lx)\n",
                          tc->cookie);
@@ -1697,7 +1706,10 @@ static int efx_tc_flower_replace_lhs(struct efx_nic *efx,
        old = rhashtable_lookup_get_insert_fast(&efx->tc->lhs_rule_ht,
                                                &rule->linkage,
                                                efx_tc_lhs_rule_ht_params);
-       if (old) {
+       if (IS_ERR(old)) {
+               rc = PTR_ERR(old);
+               goto release;
+       } else if (old) {
                netif_dbg(efx, drv, efx->net_dev,
                          "Already offloaded rule (cookie %lx)\n", tc->cookie);
                rc = -EEXIST;
@@ -1858,7 +1870,10 @@ static int efx_tc_flower_replace(struct efx_nic *efx,
        old = rhashtable_lookup_get_insert_fast(&efx->tc->match_action_ht,
                                                &rule->linkage,
                                                efx_tc_match_action_ht_params);
-       if (old) {
+       if (IS_ERR(old)) {
+               rc = PTR_ERR(old);
+               goto release;
+       } else if (old) {
                netif_dbg(efx, drv, efx->net_dev,
                          "Already offloaded rule (cookie %lx)\n", tc->cookie);
                NL_SET_ERR_MSG_MOD(extack, "Rule already offloaded");
index 8e06bfb..44bb576 100644 (file)
@@ -298,7 +298,10 @@ static int efx_tc_ct_replace(struct efx_tc_ct_zone *ct_zone,
        old = rhashtable_lookup_get_insert_fast(&efx->tc->ct_ht,
                                                &conn->linkage,
                                                efx_tc_ct_ht_params);
-       if (old) {
+       if (IS_ERR(old)) {
+               rc = PTR_ERR(old);
+               goto release;
+       } else if (old) {
                netif_dbg(efx, drv, efx->net_dev,
                          "Already offloaded conntrack (cookie %lx)\n", tc->cookie);
                rc = -EEXIST;
@@ -482,6 +485,8 @@ struct efx_tc_ct_zone *efx_tc_ct_register_zone(struct efx_nic *efx, u16 zone,
        if (old) {
                /* don't need our new entry */
                kfree(ct_zone);
+               if (IS_ERR(old)) /* oh dear, it's actually an error */
+                       return ERR_CAST(old);
                if (!refcount_inc_not_zero(&old->ref))
                        return ERR_PTR(-EAGAIN);
                /* existing entry found */
index 0fafb47..c440884 100644 (file)
@@ -236,6 +236,8 @@ struct efx_tc_counter_index *efx_tc_flower_get_counter_index(
        if (old) {
                /* don't need our new entry */
                kfree(ctr);
+               if (IS_ERR(old)) /* oh dear, it's actually an error */
+                       return ERR_CAST(old);
                if (!refcount_inc_not_zero(&old->ref))
                        return ERR_PTR(-EAGAIN);
                /* existing entry found */
index 7e8bcdb..87443f9 100644 (file)
@@ -132,6 +132,8 @@ static int efx_bind_neigh(struct efx_nic *efx,
                /* don't need our new entry */
                put_net_track(neigh->net, &neigh->ns_tracker);
                kfree(neigh);
+               if (IS_ERR(old)) /* oh dear, it's actually an error */
+                       return PTR_ERR(old);
                if (!refcount_inc_not_zero(&old->ref))
                        return -EAGAIN;
                /* existing entry found, ref taken */
@@ -640,6 +642,8 @@ struct efx_tc_encap_action *efx_tc_flower_create_encap_md(
        if (old) {
                /* don't need our new entry */
                kfree(encap);
+               if (IS_ERR(old)) /* oh dear, it's actually an error */
+                       return ERR_CAST(old);
                if (!refcount_inc_not_zero(&old->ref))
                        return ERR_PTR(-EAGAIN);
                /* existing entry found, ref taken */
index 403cb39..1e996c2 100644 (file)
@@ -70,7 +70,7 @@ struct stmmac_txq_stats {
        u64 tx_tso_frames;
        u64 tx_tso_nfrags;
        struct u64_stats_sync syncp;
-};
+} ____cacheline_aligned_in_smp;
 
 struct stmmac_rxq_stats {
        u64 rx_bytes;
@@ -79,7 +79,7 @@ struct stmmac_rxq_stats {
        u64 rx_normal_irq_n;
        u64 napi_poll;
        struct u64_stats_sync syncp;
-};
+} ____cacheline_aligned_in_smp;
 
 /* Extra statistic and debug information exposed by ethtool */
 struct stmmac_extra_stats {
@@ -202,6 +202,9 @@ struct stmmac_extra_stats {
        unsigned long mtl_est_hlbf;
        unsigned long mtl_est_btre;
        unsigned long mtl_est_btrlm;
+       /* per queue statistics */
+       struct stmmac_txq_stats txq_stats[MTL_MAX_TX_QUEUES];
+       struct stmmac_rxq_stats rxq_stats[MTL_MAX_RX_QUEUES];
        unsigned long rx_dropped;
        unsigned long rx_errors;
        unsigned long tx_dropped;
index 26ea8c6..a0e2767 100644 (file)
@@ -104,6 +104,7 @@ struct stm32_ops {
        int (*parse_data)(struct stm32_dwmac *dwmac,
                          struct device *dev);
        u32 syscfg_eth_mask;
+       bool clk_rx_enable_in_suspend;
 };
 
 static int stm32_dwmac_init(struct plat_stmmacenet_data *plat_dat)
@@ -121,7 +122,8 @@ static int stm32_dwmac_init(struct plat_stmmacenet_data *plat_dat)
        if (ret)
                return ret;
 
-       if (!dwmac->dev->power.is_suspended) {
+       if (!dwmac->ops->clk_rx_enable_in_suspend ||
+           !dwmac->dev->power.is_suspended) {
                ret = clk_prepare_enable(dwmac->clk_rx);
                if (ret) {
                        clk_disable_unprepare(dwmac->clk_tx);
@@ -513,7 +515,8 @@ static struct stm32_ops stm32mp1_dwmac_data = {
        .suspend = stm32mp1_suspend,
        .resume = stm32mp1_resume,
        .parse_data = stm32mp1_parse_data,
-       .syscfg_eth_mask = SYSCFG_MP1_ETH_MASK
+       .syscfg_eth_mask = SYSCFG_MP1_ETH_MASK,
+       .clk_rx_enable_in_suspend = true
 };
 
 static const struct of_device_id stm32_dwmac_match[] = {
index 01e7736..465ff1f 100644 (file)
@@ -441,8 +441,8 @@ static int sun8i_dwmac_dma_interrupt(struct stmmac_priv *priv,
                                     struct stmmac_extra_stats *x, u32 chan,
                                     u32 dir)
 {
-       struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[chan];
-       struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[chan];
+       struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[chan];
+       struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[chan];
        int ret = 0;
        u32 v;
 
@@ -455,9 +455,9 @@ static int sun8i_dwmac_dma_interrupt(struct stmmac_priv *priv,
 
        if (v & EMAC_TX_INT) {
                ret |= handle_tx;
-               u64_stats_update_begin(&tx_q->txq_stats.syncp);
-               tx_q->txq_stats.tx_normal_irq_n++;
-               u64_stats_update_end(&tx_q->txq_stats.syncp);
+               u64_stats_update_begin(&txq_stats->syncp);
+               txq_stats->tx_normal_irq_n++;
+               u64_stats_update_end(&txq_stats->syncp);
        }
 
        if (v & EMAC_TX_DMA_STOP_INT)
@@ -479,9 +479,9 @@ static int sun8i_dwmac_dma_interrupt(struct stmmac_priv *priv,
 
        if (v & EMAC_RX_INT) {
                ret |= handle_rx;
-               u64_stats_update_begin(&rx_q->rxq_stats.syncp);
-               rx_q->rxq_stats.rx_normal_irq_n++;
-               u64_stats_update_end(&rx_q->rxq_stats.syncp);
+               u64_stats_update_begin(&rxq_stats->syncp);
+               rxq_stats->rx_normal_irq_n++;
+               u64_stats_update_end(&rxq_stats->syncp);
        }
 
        if (v & EMAC_RX_BUF_UA_INT)
index 980e5f8..9470d3f 100644 (file)
@@ -171,8 +171,8 @@ int dwmac4_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr,
        const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
        u32 intr_status = readl(ioaddr + DMA_CHAN_STATUS(dwmac4_addrs, chan));
        u32 intr_en = readl(ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan));
-       struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[chan];
-       struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[chan];
+       struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[chan];
+       struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[chan];
        int ret = 0;
 
        if (dir == DMA_DIR_RX)
@@ -201,15 +201,15 @@ int dwmac4_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr,
        }
        /* TX/RX NORMAL interrupts */
        if (likely(intr_status & DMA_CHAN_STATUS_RI)) {
-               u64_stats_update_begin(&rx_q->rxq_stats.syncp);
-               rx_q->rxq_stats.rx_normal_irq_n++;
-               u64_stats_update_end(&rx_q->rxq_stats.syncp);
+               u64_stats_update_begin(&rxq_stats->syncp);
+               rxq_stats->rx_normal_irq_n++;
+               u64_stats_update_end(&rxq_stats->syncp);
                ret |= handle_rx;
        }
        if (likely(intr_status & DMA_CHAN_STATUS_TI)) {
-               u64_stats_update_begin(&tx_q->txq_stats.syncp);
-               tx_q->txq_stats.tx_normal_irq_n++;
-               u64_stats_update_end(&tx_q->txq_stats.syncp);
+               u64_stats_update_begin(&txq_stats->syncp);
+               txq_stats->tx_normal_irq_n++;
+               u64_stats_update_end(&txq_stats->syncp);
                ret |= handle_tx;
        }
 
index aaa09b1..7907d62 100644 (file)
@@ -162,8 +162,8 @@ static void show_rx_process_state(unsigned int status)
 int dwmac_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr,
                        struct stmmac_extra_stats *x, u32 chan, u32 dir)
 {
-       struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[chan];
-       struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[chan];
+       struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[chan];
+       struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[chan];
        int ret = 0;
        /* read the status register (CSR5) */
        u32 intr_status = readl(ioaddr + DMA_STATUS);
@@ -215,16 +215,16 @@ int dwmac_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr,
                        u32 value = readl(ioaddr + DMA_INTR_ENA);
                        /* to schedule NAPI on real RIE event. */
                        if (likely(value & DMA_INTR_ENA_RIE)) {
-                               u64_stats_update_begin(&rx_q->rxq_stats.syncp);
-                               rx_q->rxq_stats.rx_normal_irq_n++;
-                               u64_stats_update_end(&rx_q->rxq_stats.syncp);
+                               u64_stats_update_begin(&rxq_stats->syncp);
+                               rxq_stats->rx_normal_irq_n++;
+                               u64_stats_update_end(&rxq_stats->syncp);
                                ret |= handle_rx;
                        }
                }
                if (likely(intr_status & DMA_STATUS_TI)) {
-                       u64_stats_update_begin(&tx_q->txq_stats.syncp);
-                       tx_q->txq_stats.tx_normal_irq_n++;
-                       u64_stats_update_end(&tx_q->txq_stats.syncp);
+                       u64_stats_update_begin(&txq_stats->syncp);
+                       txq_stats->tx_normal_irq_n++;
+                       u64_stats_update_end(&txq_stats->syncp);
                        ret |= handle_tx;
                }
                if (unlikely(intr_status & DMA_STATUS_ERI))
index fa69d64..3cde695 100644 (file)
@@ -337,8 +337,8 @@ static int dwxgmac2_dma_interrupt(struct stmmac_priv *priv,
                                  struct stmmac_extra_stats *x, u32 chan,
                                  u32 dir)
 {
-       struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[chan];
-       struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[chan];
+       struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[chan];
+       struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[chan];
        u32 intr_status = readl(ioaddr + XGMAC_DMA_CH_STATUS(chan));
        u32 intr_en = readl(ioaddr + XGMAC_DMA_CH_INT_EN(chan));
        int ret = 0;
@@ -367,15 +367,15 @@ static int dwxgmac2_dma_interrupt(struct stmmac_priv *priv,
        /* TX/RX NORMAL interrupts */
        if (likely(intr_status & XGMAC_NIS)) {
                if (likely(intr_status & XGMAC_RI)) {
-                       u64_stats_update_begin(&rx_q->rxq_stats.syncp);
-                       rx_q->rxq_stats.rx_normal_irq_n++;
-                       u64_stats_update_end(&rx_q->rxq_stats.syncp);
+                       u64_stats_update_begin(&rxq_stats->syncp);
+                       rxq_stats->rx_normal_irq_n++;
+                       u64_stats_update_end(&rxq_stats->syncp);
                        ret |= handle_rx;
                }
                if (likely(intr_status & (XGMAC_TI | XGMAC_TBU))) {
-                       u64_stats_update_begin(&tx_q->txq_stats.syncp);
-                       tx_q->txq_stats.tx_normal_irq_n++;
-                       u64_stats_update_end(&tx_q->txq_stats.syncp);
+                       u64_stats_update_begin(&txq_stats->syncp);
+                       txq_stats->tx_normal_irq_n++;
+                       u64_stats_update_end(&txq_stats->syncp);
                        ret |= handle_tx;
                }
        }
index 3401e88..cd7a976 100644 (file)
@@ -78,7 +78,6 @@ struct stmmac_tx_queue {
        dma_addr_t dma_tx_phy;
        dma_addr_t tx_tail_addr;
        u32 mss;
-       struct stmmac_txq_stats txq_stats;
 };
 
 struct stmmac_rx_buffer {
@@ -123,7 +122,6 @@ struct stmmac_rx_queue {
                unsigned int len;
                unsigned int error;
        } state;
-       struct stmmac_rxq_stats rxq_stats;
 };
 
 struct stmmac_channel {
index b7ac7ab..6aa5c05 100644 (file)
@@ -548,14 +548,14 @@ static void stmmac_get_per_qstats(struct stmmac_priv *priv, u64 *data)
 
        pos = data;
        for (q = 0; q < tx_cnt; q++) {
-               struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[q];
+               struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[q];
                struct stmmac_txq_stats snapshot;
 
                data = pos;
                do {
-                       start = u64_stats_fetch_begin(&tx_q->txq_stats.syncp);
-                       snapshot = tx_q->txq_stats;
-               } while (u64_stats_fetch_retry(&tx_q->txq_stats.syncp, start));
+                       start = u64_stats_fetch_begin(&txq_stats->syncp);
+                       snapshot = *txq_stats;
+               } while (u64_stats_fetch_retry(&txq_stats->syncp, start));
 
                p = (char *)&snapshot + offsetof(struct stmmac_txq_stats, tx_pkt_n);
                for (stat = 0; stat < STMMAC_TXQ_STATS; stat++) {
@@ -566,14 +566,14 @@ static void stmmac_get_per_qstats(struct stmmac_priv *priv, u64 *data)
 
        pos = data;
        for (q = 0; q < rx_cnt; q++) {
-               struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[q];
+               struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[q];
                struct stmmac_rxq_stats snapshot;
 
                data = pos;
                do {
-                       start = u64_stats_fetch_begin(&rx_q->rxq_stats.syncp);
-                       snapshot = rx_q->rxq_stats;
-               } while (u64_stats_fetch_retry(&rx_q->rxq_stats.syncp, start));
+                       start = u64_stats_fetch_begin(&rxq_stats->syncp);
+                       snapshot = *rxq_stats;
+               } while (u64_stats_fetch_retry(&rxq_stats->syncp, start));
 
                p = (char *)&snapshot + offsetof(struct stmmac_rxq_stats, rx_pkt_n);
                for (stat = 0; stat < STMMAC_RXQ_STATS; stat++) {
@@ -637,14 +637,14 @@ static void stmmac_get_ethtool_stats(struct net_device *dev,
 
        pos = j;
        for (i = 0; i < rx_queues_count; i++) {
-               struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[i];
+               struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[i];
                struct stmmac_rxq_stats snapshot;
 
                j = pos;
                do {
-                       start = u64_stats_fetch_begin(&rx_q->rxq_stats.syncp);
-                       snapshot = rx_q->rxq_stats;
-               } while (u64_stats_fetch_retry(&rx_q->rxq_stats.syncp, start));
+                       start = u64_stats_fetch_begin(&rxq_stats->syncp);
+                       snapshot = *rxq_stats;
+               } while (u64_stats_fetch_retry(&rxq_stats->syncp, start));
 
                data[j++] += snapshot.rx_pkt_n;
                data[j++] += snapshot.rx_normal_irq_n;
@@ -654,14 +654,14 @@ static void stmmac_get_ethtool_stats(struct net_device *dev,
 
        pos = j;
        for (i = 0; i < tx_queues_count; i++) {
-               struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[i];
+               struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[i];
                struct stmmac_txq_stats snapshot;
 
                j = pos;
                do {
-                       start = u64_stats_fetch_begin(&tx_q->txq_stats.syncp);
-                       snapshot = tx_q->txq_stats;
-               } while (u64_stats_fetch_retry(&tx_q->txq_stats.syncp, start));
+                       start = u64_stats_fetch_begin(&txq_stats->syncp);
+                       snapshot = *txq_stats;
+               } while (u64_stats_fetch_retry(&txq_stats->syncp, start));
 
                data[j++] += snapshot.tx_pkt_n;
                data[j++] += snapshot.tx_normal_irq_n;
index 2206789..ed1a5a3 100644 (file)
@@ -2426,6 +2426,7 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget)
 {
        struct netdev_queue *nq = netdev_get_tx_queue(priv->dev, queue);
        struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue];
+       struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[queue];
        struct xsk_buff_pool *pool = tx_q->xsk_pool;
        unsigned int entry = tx_q->cur_tx;
        struct dma_desc *tx_desc = NULL;
@@ -2505,9 +2506,9 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget)
                tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx, priv->dma_conf.dma_tx_size);
                entry = tx_q->cur_tx;
        }
-       flags = u64_stats_update_begin_irqsave(&tx_q->txq_stats.syncp);
-       tx_q->txq_stats.tx_set_ic_bit += tx_set_ic_bit;
-       u64_stats_update_end_irqrestore(&tx_q->txq_stats.syncp, flags);
+       flags = u64_stats_update_begin_irqsave(&txq_stats->syncp);
+       txq_stats->tx_set_ic_bit += tx_set_ic_bit;
+       u64_stats_update_end_irqrestore(&txq_stats->syncp, flags);
 
        if (tx_desc) {
                stmmac_flush_tx_descriptors(priv, queue);
@@ -2547,6 +2548,7 @@ static void stmmac_bump_dma_threshold(struct stmmac_priv *priv, u32 chan)
 static int stmmac_tx_clean(struct stmmac_priv *priv, int budget, u32 queue)
 {
        struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue];
+       struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[queue];
        unsigned int bytes_compl = 0, pkts_compl = 0;
        unsigned int entry, xmits = 0, count = 0;
        u32 tx_packets = 0, tx_errors = 0;
@@ -2706,11 +2708,11 @@ static int stmmac_tx_clean(struct stmmac_priv *priv, int budget, u32 queue)
        if (tx_q->dirty_tx != tx_q->cur_tx)
                stmmac_tx_timer_arm(priv, queue);
 
-       flags = u64_stats_update_begin_irqsave(&tx_q->txq_stats.syncp);
-       tx_q->txq_stats.tx_packets += tx_packets;
-       tx_q->txq_stats.tx_pkt_n += tx_packets;
-       tx_q->txq_stats.tx_clean++;
-       u64_stats_update_end_irqrestore(&tx_q->txq_stats.syncp, flags);
+       flags = u64_stats_update_begin_irqsave(&txq_stats->syncp);
+       txq_stats->tx_packets += tx_packets;
+       txq_stats->tx_pkt_n += tx_packets;
+       txq_stats->tx_clean++;
+       u64_stats_update_end_irqrestore(&txq_stats->syncp, flags);
 
        priv->xstats.tx_errors += tx_errors;
 
@@ -4114,6 +4116,7 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
        int nfrags = skb_shinfo(skb)->nr_frags;
        u32 queue = skb_get_queue_mapping(skb);
        unsigned int first_entry, tx_packets;
+       struct stmmac_txq_stats *txq_stats;
        int tmp_pay_len = 0, first_tx;
        struct stmmac_tx_queue *tx_q;
        bool has_vlan, set_ic;
@@ -4124,6 +4127,7 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
        int i;
 
        tx_q = &priv->dma_conf.tx_queue[queue];
+       txq_stats = &priv->xstats.txq_stats[queue];
        first_tx = tx_q->cur_tx;
 
        /* Compute header lengths */
@@ -4282,13 +4286,13 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
                netif_tx_stop_queue(netdev_get_tx_queue(priv->dev, queue));
        }
 
-       flags = u64_stats_update_begin_irqsave(&tx_q->txq_stats.syncp);
-       tx_q->txq_stats.tx_bytes += skb->len;
-       tx_q->txq_stats.tx_tso_frames++;
-       tx_q->txq_stats.tx_tso_nfrags += nfrags;
+       flags = u64_stats_update_begin_irqsave(&txq_stats->syncp);
+       txq_stats->tx_bytes += skb->len;
+       txq_stats->tx_tso_frames++;
+       txq_stats->tx_tso_nfrags += nfrags;
        if (set_ic)
-               tx_q->txq_stats.tx_set_ic_bit++;
-       u64_stats_update_end_irqrestore(&tx_q->txq_stats.syncp, flags);
+               txq_stats->tx_set_ic_bit++;
+       u64_stats_update_end_irqrestore(&txq_stats->syncp, flags);
 
        if (priv->sarc_type)
                stmmac_set_desc_sarc(priv, first, priv->sarc_type);
@@ -4359,6 +4363,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
        u32 queue = skb_get_queue_mapping(skb);
        int nfrags = skb_shinfo(skb)->nr_frags;
        int gso = skb_shinfo(skb)->gso_type;
+       struct stmmac_txq_stats *txq_stats;
        struct dma_edesc *tbs_desc = NULL;
        struct dma_desc *desc, *first;
        struct stmmac_tx_queue *tx_q;
@@ -4368,6 +4373,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
        dma_addr_t des;
 
        tx_q = &priv->dma_conf.tx_queue[queue];
+       txq_stats = &priv->xstats.txq_stats[queue];
        first_tx = tx_q->cur_tx;
 
        if (priv->tx_path_in_lpi_mode && priv->eee_sw_timer_en)
@@ -4519,11 +4525,11 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
                netif_tx_stop_queue(netdev_get_tx_queue(priv->dev, queue));
        }
 
-       flags = u64_stats_update_begin_irqsave(&tx_q->txq_stats.syncp);
-       tx_q->txq_stats.tx_bytes += skb->len;
+       flags = u64_stats_update_begin_irqsave(&txq_stats->syncp);
+       txq_stats->tx_bytes += skb->len;
        if (set_ic)
-               tx_q->txq_stats.tx_set_ic_bit++;
-       u64_stats_update_end_irqrestore(&tx_q->txq_stats.syncp, flags);
+               txq_stats->tx_set_ic_bit++;
+       u64_stats_update_end_irqrestore(&txq_stats->syncp, flags);
 
        if (priv->sarc_type)
                stmmac_set_desc_sarc(priv, first, priv->sarc_type);
@@ -4730,6 +4736,7 @@ static unsigned int stmmac_rx_buf2_len(struct stmmac_priv *priv,
 static int stmmac_xdp_xmit_xdpf(struct stmmac_priv *priv, int queue,
                                struct xdp_frame *xdpf, bool dma_map)
 {
+       struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[queue];
        struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue];
        unsigned int entry = tx_q->cur_tx;
        struct dma_desc *tx_desc;
@@ -4789,9 +4796,9 @@ static int stmmac_xdp_xmit_xdpf(struct stmmac_priv *priv, int queue,
                unsigned long flags;
                tx_q->tx_count_frames = 0;
                stmmac_set_tx_ic(priv, tx_desc);
-               flags = u64_stats_update_begin_irqsave(&tx_q->txq_stats.syncp);
-               tx_q->txq_stats.tx_set_ic_bit++;
-               u64_stats_update_end_irqrestore(&tx_q->txq_stats.syncp, flags);
+               flags = u64_stats_update_begin_irqsave(&txq_stats->syncp);
+               txq_stats->tx_set_ic_bit++;
+               u64_stats_update_end_irqrestore(&txq_stats->syncp, flags);
        }
 
        stmmac_enable_dma_transmission(priv, priv->ioaddr);
@@ -4936,7 +4943,7 @@ static void stmmac_dispatch_skb_zc(struct stmmac_priv *priv, u32 queue,
                                   struct dma_desc *p, struct dma_desc *np,
                                   struct xdp_buff *xdp)
 {
-       struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue];
+       struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[queue];
        struct stmmac_channel *ch = &priv->channel[queue];
        unsigned int len = xdp->data_end - xdp->data;
        enum pkt_hash_types hash_type;
@@ -4966,10 +4973,10 @@ static void stmmac_dispatch_skb_zc(struct stmmac_priv *priv, u32 queue,
        skb_record_rx_queue(skb, queue);
        napi_gro_receive(&ch->rxtx_napi, skb);
 
-       flags = u64_stats_update_begin_irqsave(&rx_q->rxq_stats.syncp);
-       rx_q->rxq_stats.rx_pkt_n++;
-       rx_q->rxq_stats.rx_bytes += len;
-       u64_stats_update_end_irqrestore(&rx_q->rxq_stats.syncp, flags);
+       flags = u64_stats_update_begin_irqsave(&rxq_stats->syncp);
+       rxq_stats->rx_pkt_n++;
+       rxq_stats->rx_bytes += len;
+       u64_stats_update_end_irqrestore(&rxq_stats->syncp, flags);
 }
 
 static bool stmmac_rx_refill_zc(struct stmmac_priv *priv, u32 queue, u32 budget)
@@ -5042,6 +5049,7 @@ static struct stmmac_xdp_buff *xsk_buff_to_stmmac_ctx(struct xdp_buff *xdp)
 
 static int stmmac_rx_zc(struct stmmac_priv *priv, int limit, u32 queue)
 {
+       struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[queue];
        struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue];
        unsigned int count = 0, error = 0, len = 0;
        int dirty = stmmac_rx_dirty(priv, queue);
@@ -5205,9 +5213,9 @@ read_again:
 
        stmmac_finalize_xdp_rx(priv, xdp_status);
 
-       flags = u64_stats_update_begin_irqsave(&rx_q->rxq_stats.syncp);
-       rx_q->rxq_stats.rx_pkt_n += count;
-       u64_stats_update_end_irqrestore(&rx_q->rxq_stats.syncp, flags);
+       flags = u64_stats_update_begin_irqsave(&rxq_stats->syncp);
+       rxq_stats->rx_pkt_n += count;
+       u64_stats_update_end_irqrestore(&rxq_stats->syncp, flags);
 
        priv->xstats.rx_dropped += rx_dropped;
        priv->xstats.rx_errors += rx_errors;
@@ -5235,6 +5243,7 @@ read_again:
 static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
 {
        u32 rx_errors = 0, rx_dropped = 0, rx_bytes = 0, rx_packets = 0;
+       struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[queue];
        struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue];
        struct stmmac_channel *ch = &priv->channel[queue];
        unsigned int count = 0, error = 0, len = 0;
@@ -5496,11 +5505,11 @@ drain_data:
 
        stmmac_rx_refill(priv, queue);
 
-       flags = u64_stats_update_begin_irqsave(&rx_q->rxq_stats.syncp);
-       rx_q->rxq_stats.rx_packets += rx_packets;
-       rx_q->rxq_stats.rx_bytes += rx_bytes;
-       rx_q->rxq_stats.rx_pkt_n += count;
-       u64_stats_update_end_irqrestore(&rx_q->rxq_stats.syncp, flags);
+       flags = u64_stats_update_begin_irqsave(&rxq_stats->syncp);
+       rxq_stats->rx_packets += rx_packets;
+       rxq_stats->rx_bytes += rx_bytes;
+       rxq_stats->rx_pkt_n += count;
+       u64_stats_update_end_irqrestore(&rxq_stats->syncp, flags);
 
        priv->xstats.rx_dropped += rx_dropped;
        priv->xstats.rx_errors += rx_errors;
@@ -5513,15 +5522,15 @@ static int stmmac_napi_poll_rx(struct napi_struct *napi, int budget)
        struct stmmac_channel *ch =
                container_of(napi, struct stmmac_channel, rx_napi);
        struct stmmac_priv *priv = ch->priv_data;
-       struct stmmac_rx_queue *rx_q;
+       struct stmmac_rxq_stats *rxq_stats;
        u32 chan = ch->index;
        unsigned long flags;
        int work_done;
 
-       rx_q = &priv->dma_conf.rx_queue[chan];
-       flags = u64_stats_update_begin_irqsave(&rx_q->rxq_stats.syncp);
-       rx_q->rxq_stats.napi_poll++;
-       u64_stats_update_end_irqrestore(&rx_q->rxq_stats.syncp, flags);
+       rxq_stats = &priv->xstats.rxq_stats[chan];
+       flags = u64_stats_update_begin_irqsave(&rxq_stats->syncp);
+       rxq_stats->napi_poll++;
+       u64_stats_update_end_irqrestore(&rxq_stats->syncp, flags);
 
        work_done = stmmac_rx(priv, budget, chan);
        if (work_done < budget && napi_complete_done(napi, work_done)) {
@@ -5540,15 +5549,15 @@ static int stmmac_napi_poll_tx(struct napi_struct *napi, int budget)
        struct stmmac_channel *ch =
                container_of(napi, struct stmmac_channel, tx_napi);
        struct stmmac_priv *priv = ch->priv_data;
-       struct stmmac_tx_queue *tx_q;
+       struct stmmac_txq_stats *txq_stats;
        u32 chan = ch->index;
        unsigned long flags;
        int work_done;
 
-       tx_q = &priv->dma_conf.tx_queue[chan];
-       flags = u64_stats_update_begin_irqsave(&tx_q->txq_stats.syncp);
-       tx_q->txq_stats.napi_poll++;
-       u64_stats_update_end_irqrestore(&tx_q->txq_stats.syncp, flags);
+       txq_stats = &priv->xstats.txq_stats[chan];
+       flags = u64_stats_update_begin_irqsave(&txq_stats->syncp);
+       txq_stats->napi_poll++;
+       u64_stats_update_end_irqrestore(&txq_stats->syncp, flags);
 
        work_done = stmmac_tx_clean(priv, budget, chan);
        work_done = min(work_done, budget);
@@ -5570,20 +5579,20 @@ static int stmmac_napi_poll_rxtx(struct napi_struct *napi, int budget)
                container_of(napi, struct stmmac_channel, rxtx_napi);
        struct stmmac_priv *priv = ch->priv_data;
        int rx_done, tx_done, rxtx_done;
-       struct stmmac_rx_queue *rx_q;
-       struct stmmac_tx_queue *tx_q;
+       struct stmmac_rxq_stats *rxq_stats;
+       struct stmmac_txq_stats *txq_stats;
        u32 chan = ch->index;
        unsigned long flags;
 
-       rx_q = &priv->dma_conf.rx_queue[chan];
-       flags = u64_stats_update_begin_irqsave(&rx_q->rxq_stats.syncp);
-       rx_q->rxq_stats.napi_poll++;
-       u64_stats_update_end_irqrestore(&rx_q->rxq_stats.syncp, flags);
+       rxq_stats = &priv->xstats.rxq_stats[chan];
+       flags = u64_stats_update_begin_irqsave(&rxq_stats->syncp);
+       rxq_stats->napi_poll++;
+       u64_stats_update_end_irqrestore(&rxq_stats->syncp, flags);
 
-       tx_q = &priv->dma_conf.tx_queue[chan];
-       flags = u64_stats_update_begin_irqsave(&tx_q->txq_stats.syncp);
-       tx_q->txq_stats.napi_poll++;
-       u64_stats_update_end_irqrestore(&tx_q->txq_stats.syncp, flags);
+       txq_stats = &priv->xstats.txq_stats[chan];
+       flags = u64_stats_update_begin_irqsave(&txq_stats->syncp);
+       txq_stats->napi_poll++;
+       u64_stats_update_end_irqrestore(&txq_stats->syncp, flags);
 
        tx_done = stmmac_tx_clean(priv, budget, chan);
        tx_done = min(tx_done, budget);
@@ -5993,33 +6002,6 @@ static irqreturn_t stmmac_msi_intr_rx(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-#ifdef CONFIG_NET_POLL_CONTROLLER
-/* Polling receive - used by NETCONSOLE and other diagnostic tools
- * to allow network I/O with interrupts disabled.
- */
-static void stmmac_poll_controller(struct net_device *dev)
-{
-       struct stmmac_priv *priv = netdev_priv(dev);
-       int i;
-
-       /* If adapter is down, do nothing */
-       if (test_bit(STMMAC_DOWN, &priv->state))
-               return;
-
-       if (priv->plat->flags & STMMAC_FLAG_MULTI_MSI_EN) {
-               for (i = 0; i < priv->plat->rx_queues_to_use; i++)
-                       stmmac_msi_intr_rx(0, &priv->dma_conf.rx_queue[i]);
-
-               for (i = 0; i < priv->plat->tx_queues_to_use; i++)
-                       stmmac_msi_intr_tx(0, &priv->dma_conf.tx_queue[i]);
-       } else {
-               disable_irq(dev->irq);
-               stmmac_interrupt(dev->irq, dev);
-               enable_irq(dev->irq);
-       }
-}
-#endif
-
 /**
  *  stmmac_ioctl - Entry point for the Ioctl
  *  @dev: Device pointer.
@@ -6926,7 +6908,7 @@ static void stmmac_get_stats64(struct net_device *dev, struct rtnl_link_stats64
        int q;
 
        for (q = 0; q < tx_cnt; q++) {
-               struct stmmac_txq_stats *txq_stats = &priv->dma_conf.tx_queue[q].txq_stats;
+               struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[q];
                u64 tx_packets;
                u64 tx_bytes;
 
@@ -6941,7 +6923,7 @@ static void stmmac_get_stats64(struct net_device *dev, struct rtnl_link_stats64
        }
 
        for (q = 0; q < rx_cnt; q++) {
-               struct stmmac_rxq_stats *rxq_stats = &priv->dma_conf.rx_queue[q].rxq_stats;
+               struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[q];
                u64 rx_packets;
                u64 rx_bytes;
 
@@ -6980,9 +6962,6 @@ static const struct net_device_ops stmmac_netdev_ops = {
        .ndo_get_stats64 = stmmac_get_stats64,
        .ndo_setup_tc = stmmac_setup_tc,
        .ndo_select_queue = stmmac_select_queue,
-#ifdef CONFIG_NET_POLL_CONTROLLER
-       .ndo_poll_controller = stmmac_poll_controller,
-#endif
        .ndo_set_mac_address = stmmac_set_mac_address,
        .ndo_vlan_rx_add_vid = stmmac_vlan_rx_add_vid,
        .ndo_vlan_rx_kill_vid = stmmac_vlan_rx_kill_vid,
@@ -7342,9 +7321,9 @@ int stmmac_dvr_probe(struct device *device,
        priv->dev = ndev;
 
        for (i = 0; i < MTL_MAX_RX_QUEUES; i++)
-               u64_stats_init(&priv->dma_conf.rx_queue[i].rxq_stats.syncp);
+               u64_stats_init(&priv->xstats.rxq_stats[i].syncp);
        for (i = 0; i < MTL_MAX_TX_QUEUES; i++)
-               u64_stats_init(&priv->dma_conf.tx_queue[i].txq_stats.syncp);
+               u64_stats_init(&priv->xstats.txq_stats[i].syncp);
 
        stmmac_set_ethtool_ops(ndev);
        priv->pause = pause;
index 0f28795..2f0678f 100644 (file)
@@ -901,7 +901,7 @@ static int __maybe_unused stmmac_pltfr_resume(struct device *dev)
        struct platform_device *pdev = to_platform_device(dev);
        int ret;
 
-       ret = stmmac_pltfr_init(pdev, priv->plat->bsp_priv);
+       ret = stmmac_pltfr_init(pdev, priv->plat);
        if (ret)
                return ret;
 
index 88b5b1b..0a33466 100644 (file)
@@ -199,6 +199,7 @@ config TI_ICSSG_PRUETH
 
 config TI_ICSS_IEP
        tristate "TI PRU ICSS IEP driver"
+       depends on PTP_1588_CLOCK_OPTIONAL
        depends on TI_PRUSS
        default TI_PRUSS
        help
index bea6fc0..2412060 100644 (file)
@@ -1747,9 +1747,10 @@ static int am65_cpsw_nuss_init_tx_chns(struct am65_cpsw_common *common)
                }
 
                tx_chn->irq = k3_udma_glue_tx_get_irq(tx_chn->tx_chn);
-               if (tx_chn->irq <= 0) {
+               if (tx_chn->irq < 0) {
                        dev_err(dev, "Failed to get tx dma irq %d\n",
                                tx_chn->irq);
+                       ret = tx_chn->irq;
                        goto err;
                }
 
index 410612f..4914d0e 100644 (file)
@@ -316,12 +316,12 @@ static int prueth_init_tx_chns(struct prueth_emac *emac)
                        goto fail;
                }
 
-               tx_chn->irq = k3_udma_glue_tx_get_irq(tx_chn->tx_chn);
-               if (tx_chn->irq <= 0) {
-                       ret = -EINVAL;
+               ret = k3_udma_glue_tx_get_irq(tx_chn->tx_chn);
+               if (ret < 0) {
                        netdev_err(ndev, "failed to get tx irq\n");
                        goto fail;
                }
+               tx_chn->irq = ret;
 
                snprintf(tx_chn->name, sizeof(tx_chn->name), "%s-tx%d",
                         dev_name(dev), tx_chn->id);
index e8b9458..508d9a3 100644 (file)
@@ -2115,7 +2115,12 @@ static const struct ethtool_ops team_ethtool_ops = {
 static void team_setup_by_port(struct net_device *dev,
                               struct net_device *port_dev)
 {
-       dev->header_ops = port_dev->header_ops;
+       struct team *team = netdev_priv(dev);
+
+       if (port_dev->type == ARPHRD_ETHER)
+               dev->header_ops = team->header_ops_cache;
+       else
+               dev->header_ops = port_dev->header_ops;
        dev->type = port_dev->type;
        dev->hard_header_len = port_dev->hard_header_len;
        dev->needed_headroom = port_dev->needed_headroom;
@@ -2162,8 +2167,11 @@ static int team_dev_type_check_change(struct net_device *dev,
 
 static void team_setup(struct net_device *dev)
 {
+       struct team *team = netdev_priv(dev);
+
        ether_setup(dev);
        dev->max_mtu = ETH_MAX_MTU;
+       team->header_ops_cache = dev->header_ops;
 
        dev->netdev_ops = &team_netdev_ops;
        dev->ethtool_ops = &team_ethtool_ops;
index 0c1e897..0a53ec2 100644 (file)
@@ -1049,12 +1049,11 @@ static bool tbnet_xmit_csum_and_map(struct tbnet *net, struct sk_buff *skb,
                *tucso = ~csum_tcpudp_magic(ip_hdr(skb)->saddr,
                                            ip_hdr(skb)->daddr, 0,
                                            ip_hdr(skb)->protocol, 0);
-       } else if (skb_is_gso_v6(skb)) {
+       } else if (skb_is_gso(skb) && skb_is_gso_v6(skb)) {
                tucso = dest + ((void *)&(tcp_hdr(skb)->check) - data);
                *tucso = ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
                                          &ipv6_hdr(skb)->daddr, 0,
                                          IPPROTO_TCP, 0);
-               return false;
        } else if (protocol == htons(ETH_P_IPV6)) {
                tucso = dest + skb_checksum_start_offset(skb) + skb->csum_offset;
                *tucso = ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
index 5d6454f..78ad2da 100644 (file)
@@ -90,7 +90,9 @@ static int __must_check __smsc75xx_read_reg(struct usbnet *dev, u32 index,
        ret = fn(dev, USB_VENDOR_REQUEST_READ_REGISTER, USB_DIR_IN
                 | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                 0, index, &buf, 4);
-       if (unlikely(ret < 0)) {
+       if (unlikely(ret < 4)) {
+               ret = ret < 0 ? ret : -ENODATA;
+
                netdev_warn(dev->net, "Failed to read reg index 0x%08x: %d\n",
                            index, ret);
                return ret;
index e463f59..5b55970 100644 (file)
@@ -4331,6 +4331,10 @@ static size_t vxlan_get_size(const struct net_device *dev)
                nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_REMCSUM_TX */
                nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_REMCSUM_RX */
                nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_LOCALBYPASS */
+               nla_total_size(0) + /* IFLA_VXLAN_GBP */
+               nla_total_size(0) + /* IFLA_VXLAN_GPE */
+               nla_total_size(0) + /* IFLA_VXLAN_REMCSUM_NOPARTIAL */
+               nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_VNIFILTER */
                0;
 }
 
index 47c2ad7..fd50bb3 100644 (file)
@@ -34,6 +34,8 @@
 #define TDM_PPPOHT_SLIC_MAXIN
 #define RX_BD_ERRORS (R_CD_S | R_OV_S | R_CR_S | R_AB_S | R_NO_S | R_LG_S)
 
+static int uhdlc_close(struct net_device *dev);
+
 static struct ucc_tdm_info utdm_primary_info = {
        .uf_info = {
                .tsa = 0,
@@ -708,6 +710,7 @@ static int uhdlc_open(struct net_device *dev)
        hdlc_device *hdlc = dev_to_hdlc(dev);
        struct ucc_hdlc_private *priv = hdlc->priv;
        struct ucc_tdm *utdm = priv->utdm;
+       int rc = 0;
 
        if (priv->hdlc_busy != 1) {
                if (request_irq(priv->ut_info->uf_info.irq,
@@ -731,10 +734,13 @@ static int uhdlc_open(struct net_device *dev)
                napi_enable(&priv->napi);
                netdev_reset_queue(dev);
                netif_start_queue(dev);
-               hdlc_open(dev);
+
+               rc = hdlc_open(dev);
+               if (rc)
+                       uhdlc_close(dev);
        }
 
-       return 0;
+       return rc;
 }
 
 static void uhdlc_memclean(struct ucc_hdlc_private *priv)
@@ -824,6 +830,8 @@ static int uhdlc_close(struct net_device *dev)
        netdev_reset_queue(dev);
        priv->hdlc_busy = 0;
 
+       hdlc_close(dev);
+
        return 0;
 }
 
index bece267..611d1a6 100644 (file)
@@ -442,7 +442,12 @@ struct brcmf_scan_params_v2_le {
                                 * fixed parameter portion is assumed, otherwise
                                 * ssid in the fixed portion is ignored
                                 */
-       __le16 channel_list[1]; /* list of chanspecs */
+       union {
+               __le16 padding; /* Reserve space for at least 1 entry for abort
+                                * which uses an on stack brcmf_scan_params_v2_le
+                                */
+               DECLARE_FLEX_ARRAY(__le16, channel_list);       /* chanspecs */
+       };
 };
 
 struct brcmf_scan_results {
@@ -702,7 +707,7 @@ struct brcmf_sta_info_le {
 
 struct brcmf_chanspec_list {
        __le32  count;          /* # of entries */
-       __le32  element[1];     /* variable length uint32 list */
+       __le32  element[];      /* variable length uint32 list */
 };
 
 /*
index f5e0898..06d6f7f 100644 (file)
@@ -310,9 +310,9 @@ struct iwl_fw_ini_fifo_hdr {
 struct iwl_fw_ini_error_dump_range {
        __le32 range_data_size;
        union {
-               __le32 internal_base_addr;
-               __le64 dram_base_addr;
-               __le32 page_num;
+               __le32 internal_base_addr __packed;
+               __le64 dram_base_addr __packed;
+               __le32 page_num __packed;
                struct iwl_fw_ini_fifo_hdr fifo_hdr;
                struct iwl_cmd_header fw_pkt_hdr;
        };
index 1f5db65..1d5ee43 100644 (file)
@@ -802,7 +802,7 @@ out:
                mvm->nvm_data->bands[0].n_channels = 1;
                mvm->nvm_data->bands[0].n_bitrates = 1;
                mvm->nvm_data->bands[0].bitrates =
-                       (void *)((u8 *)mvm->nvm_data->channels + 1);
+                       (void *)(mvm->nvm_data->channels + 1);
                mvm->nvm_data->bands[0].bitrates->hw_value = 10;
        }
 
index 8b6c641..b719843 100644 (file)
@@ -731,73 +731,78 @@ static void iwl_mvm_mld_vif_cfg_changed_station(struct iwl_mvm *mvm,
 
        mvmvif->associated = vif->cfg.assoc;
 
-       if (!(changes & BSS_CHANGED_ASSOC))
-               return;
-
-       if (vif->cfg.assoc) {
-               /* clear statistics to get clean beacon counter */
-               iwl_mvm_request_statistics(mvm, true);
-               iwl_mvm_sf_update(mvm, vif, false);
-               iwl_mvm_power_vif_assoc(mvm, vif);
-
-               for_each_mvm_vif_valid_link(mvmvif, i) {
-                       memset(&mvmvif->link[i]->beacon_stats, 0,
-                              sizeof(mvmvif->link[i]->beacon_stats));
+       if (changes & BSS_CHANGED_ASSOC) {
+               if (vif->cfg.assoc) {
+                       /* clear statistics to get clean beacon counter */
+                       iwl_mvm_request_statistics(mvm, true);
+                       iwl_mvm_sf_update(mvm, vif, false);
+                       iwl_mvm_power_vif_assoc(mvm, vif);
+
+                       for_each_mvm_vif_valid_link(mvmvif, i) {
+                               memset(&mvmvif->link[i]->beacon_stats, 0,
+                                      sizeof(mvmvif->link[i]->beacon_stats));
+
+                               if (vif->p2p) {
+                                       iwl_mvm_update_smps(mvm, vif,
+                                                           IWL_MVM_SMPS_REQ_PROT,
+                                                           IEEE80211_SMPS_DYNAMIC, i);
+                               }
+
+                               rcu_read_lock();
+                               link_conf = rcu_dereference(vif->link_conf[i]);
+                               if (link_conf && !link_conf->dtim_period)
+                                       protect = true;
+                               rcu_read_unlock();
+                       }
 
-                       if (vif->p2p) {
-                               iwl_mvm_update_smps(mvm, vif,
-                                                   IWL_MVM_SMPS_REQ_PROT,
-                                                   IEEE80211_SMPS_DYNAMIC, i);
+                       if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) &&
+                           protect) {
+                               /* If we're not restarting and still haven't
+                                * heard a beacon (dtim period unknown) then
+                                * make sure we still have enough minimum time
+                                * remaining in the time event, since the auth
+                                * might actually have taken quite a while
+                                * (especially for SAE) and so the remaining
+                                * time could be small without us having heard
+                                * a beacon yet.
+                                */
+                               iwl_mvm_protect_assoc(mvm, vif, 0);
                        }
 
-                       rcu_read_lock();
-                       link_conf = rcu_dereference(vif->link_conf[i]);
-                       if (link_conf && !link_conf->dtim_period)
-                               protect = true;
-                       rcu_read_unlock();
-               }
+                       iwl_mvm_sf_update(mvm, vif, false);
+
+                       /* FIXME: need to decide about misbehaving AP handling */
+                       iwl_mvm_power_vif_assoc(mvm, vif);
+               } else if (iwl_mvm_mld_vif_have_valid_ap_sta(mvmvif)) {
+                       iwl_mvm_mei_host_disassociated(mvm);
 
-               if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) &&
-                   protect) {
-                       /* If we're not restarting and still haven't
-                        * heard a beacon (dtim period unknown) then
-                        * make sure we still have enough minimum time
-                        * remaining in the time event, since the auth
-                        * might actually have taken quite a while
-                        * (especially for SAE) and so the remaining
-                        * time could be small without us having heard
-                        * a beacon yet.
+                       /* If update fails - SF might be running in associated
+                        * mode while disassociated - which is forbidden.
                         */
-                       iwl_mvm_protect_assoc(mvm, vif, 0);
+                       ret = iwl_mvm_sf_update(mvm, vif, false);
+                       WARN_ONCE(ret &&
+                                 !test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED,
+                                           &mvm->status),
+                                 "Failed to update SF upon disassociation\n");
+
+                       /* If we get an assert during the connection (after the
+                        * station has been added, but before the vif is set
+                        * to associated), mac80211 will re-add the station and
+                        * then configure the vif. Since the vif is not
+                        * associated, we would remove the station here and
+                        * this would fail the recovery.
+                        */
+                       iwl_mvm_mld_vif_delete_all_stas(mvm, vif);
                }
 
-               iwl_mvm_sf_update(mvm, vif, false);
-
-               /* FIXME: need to decide about misbehaving AP handling */
-               iwl_mvm_power_vif_assoc(mvm, vif);
-       } else if (iwl_mvm_mld_vif_have_valid_ap_sta(mvmvif)) {
-               iwl_mvm_mei_host_disassociated(mvm);
-
-               /* If update fails - SF might be running in associated
-                * mode while disassociated - which is forbidden.
-                */
-               ret = iwl_mvm_sf_update(mvm, vif, false);
-               WARN_ONCE(ret &&
-                         !test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED,
-                                   &mvm->status),
-                         "Failed to update SF upon disassociation\n");
-
-               /* If we get an assert during the connection (after the
-                * station has been added, but before the vif is set
-                * to associated), mac80211 will re-add the station and
-                * then configure the vif. Since the vif is not
-                * associated, we would remove the station here and
-                * this would fail the recovery.
-                */
-               iwl_mvm_mld_vif_delete_all_stas(mvm, vif);
+               iwl_mvm_bss_info_changed_station_assoc(mvm, vif, changes);
        }
 
-       iwl_mvm_bss_info_changed_station_assoc(mvm, vif, changes);
+       if (changes & BSS_CHANGED_PS) {
+               ret = iwl_mvm_power_update_mac(mvm);
+               if (ret)
+                       IWL_ERR(mvm, "failed to update power mode\n");
+       }
 }
 
 static void
index c1d9ce7..3cbe2c0 100644 (file)
@@ -2342,7 +2342,7 @@ iwl_mvm_scan_umac_fill_general_p_v12(struct iwl_mvm *mvm,
        if (gen_flags & IWL_UMAC_SCAN_GEN_FLAGS_V2_FRAGMENTED_LMAC2)
                gp->num_of_fragments[SCAN_HB_LMAC_IDX] = IWL_SCAN_NUM_OF_FRAGS;
 
-       if (version < 12) {
+       if (version < 16) {
                gp->scan_start_mac_or_link_id = scan_vif->id;
        } else {
                struct iwl_mvm_vif_link_info *link_info;
index 36d70d5..898dca3 100644 (file)
@@ -1612,6 +1612,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
                iwl_trans_free_tx_cmd(mvm->trans, info->driver_data[1]);
 
                memset(&info->status, 0, sizeof(info->status));
+               info->flags &= ~(IEEE80211_TX_STAT_ACK | IEEE80211_TX_STAT_TX_FILTERED);
 
                /* inform mac80211 about what happened with the frame */
                switch (status & TX_STATUS_MSK) {
@@ -1964,6 +1965,8 @@ static void iwl_mvm_tx_reclaim(struct iwl_mvm *mvm, int sta_id, int tid,
                 */
                if (!is_flush)
                        info->flags |= IEEE80211_TX_STAT_ACK;
+               else
+                       info->flags &= ~IEEE80211_TX_STAT_ACK;
        }
 
        /*
index 391793a..10690e8 100644 (file)
@@ -918,9 +918,17 @@ void mwifiex_11n_rxba_sync_event(struct mwifiex_private *priv,
 
        mwifiex_dbg_dump(priv->adapter, EVT_D, "RXBA_SYNC event:",
                         event_buf, len);
-       while (tlv_buf_left >= sizeof(*tlv_rxba)) {
+       while (tlv_buf_left > sizeof(*tlv_rxba)) {
                tlv_type = le16_to_cpu(tlv_rxba->header.type);
                tlv_len  = le16_to_cpu(tlv_rxba->header.len);
+               if (size_add(sizeof(tlv_rxba->header), tlv_len) > tlv_buf_left) {
+                       mwifiex_dbg(priv->adapter, WARN,
+                                   "TLV size (%zu) overflows event_buf buf_left=%d\n",
+                                   size_add(sizeof(tlv_rxba->header), tlv_len),
+                                   tlv_buf_left);
+                       return;
+               }
+
                if (tlv_type != TLV_TYPE_RXBA_SYNC) {
                        mwifiex_dbg(priv->adapter, ERROR,
                                    "Wrong TLV id=0x%x\n", tlv_type);
@@ -929,6 +937,14 @@ void mwifiex_11n_rxba_sync_event(struct mwifiex_private *priv,
 
                tlv_seq_num = le16_to_cpu(tlv_rxba->seq_num);
                tlv_bitmap_len = le16_to_cpu(tlv_rxba->bitmap_len);
+               if (size_add(sizeof(*tlv_rxba), tlv_bitmap_len) > tlv_buf_left) {
+                       mwifiex_dbg(priv->adapter, WARN,
+                                   "TLV size (%zu) overflows event_buf buf_left=%d\n",
+                                   size_add(sizeof(*tlv_rxba), tlv_bitmap_len),
+                                   tlv_buf_left);
+                       return;
+               }
+
                mwifiex_dbg(priv->adapter, INFO,
                            "%pM tid=%d seq_num=%d bitmap_len=%d\n",
                            tlv_rxba->mac, tlv_rxba->tid, tlv_seq_num,
@@ -965,8 +981,8 @@ void mwifiex_11n_rxba_sync_event(struct mwifiex_private *priv,
                        }
                }
 
-               tlv_buf_left -= (sizeof(*tlv_rxba) + tlv_len);
-               tmp = (u8 *)tlv_rxba + tlv_len + sizeof(*tlv_rxba);
+               tlv_buf_left -= (sizeof(tlv_rxba->header) + tlv_len);
+               tmp = (u8 *)tlv_rxba  + sizeof(tlv_rxba->header) + tlv_len;
                tlv_rxba = (struct mwifiex_ie_types_rxba_sync *)tmp;
        }
 }
index f2168fa..8e6db90 100644 (file)
@@ -779,7 +779,7 @@ struct mwifiex_ie_types_rxba_sync {
        u8 reserved;
        __le16 seq_num;
        __le16 bitmap_len;
-       u8 bitmap[1];
+       u8 bitmap[];
 } __packed;
 
 struct chan_band_param_set {
index 65420ad..2577371 100644 (file)
@@ -86,7 +86,8 @@ int mwifiex_process_rx_packet(struct mwifiex_private *priv,
        rx_pkt_len = le16_to_cpu(local_rx_pd->rx_pkt_length);
        rx_pkt_hdr = (void *)local_rx_pd + rx_pkt_off;
 
-       if (sizeof(*rx_pkt_hdr) + rx_pkt_off > skb->len) {
+       if (sizeof(rx_pkt_hdr->eth803_hdr) + sizeof(rfc1042_header) +
+           rx_pkt_off > skb->len) {
                mwifiex_dbg(priv->adapter, ERROR,
                            "wrong rx packet offset: len=%d, rx_pkt_off=%d\n",
                            skb->len, rx_pkt_off);
@@ -95,12 +96,13 @@ int mwifiex_process_rx_packet(struct mwifiex_private *priv,
                return -1;
        }
 
-       if ((!memcmp(&rx_pkt_hdr->rfc1042_hdr, bridge_tunnel_header,
-                    sizeof(bridge_tunnel_header))) ||
-           (!memcmp(&rx_pkt_hdr->rfc1042_hdr, rfc1042_header,
-                    sizeof(rfc1042_header)) &&
-            ntohs(rx_pkt_hdr->rfc1042_hdr.snap_type) != ETH_P_AARP &&
-            ntohs(rx_pkt_hdr->rfc1042_hdr.snap_type) != ETH_P_IPX)) {
+       if (sizeof(*rx_pkt_hdr) + rx_pkt_off <= skb->len &&
+           ((!memcmp(&rx_pkt_hdr->rfc1042_hdr, bridge_tunnel_header,
+                     sizeof(bridge_tunnel_header))) ||
+            (!memcmp(&rx_pkt_hdr->rfc1042_hdr, rfc1042_header,
+                     sizeof(rfc1042_header)) &&
+             ntohs(rx_pkt_hdr->rfc1042_hdr.snap_type) != ETH_P_AARP &&
+             ntohs(rx_pkt_hdr->rfc1042_hdr.snap_type) != ETH_P_IPX))) {
                /*
                 *  Replace the 803 header and rfc1042 header (llc/snap) with an
                 *    EthernetII header, keep the src/dst and snap_type
index 05d9ab3..dc8f4e1 100644 (file)
@@ -93,13 +93,13 @@ __mt76_get_rxwi(struct mt76_dev *dev)
 {
        struct mt76_txwi_cache *t = NULL;
 
-       spin_lock(&dev->wed_lock);
+       spin_lock_bh(&dev->wed_lock);
        if (!list_empty(&dev->rxwi_cache)) {
                t = list_first_entry(&dev->rxwi_cache, struct mt76_txwi_cache,
                                     list);
                list_del(&t->list);
        }
-       spin_unlock(&dev->wed_lock);
+       spin_unlock_bh(&dev->wed_lock);
 
        return t;
 }
@@ -145,9 +145,9 @@ mt76_put_rxwi(struct mt76_dev *dev, struct mt76_txwi_cache *t)
        if (!t)
                return;
 
-       spin_lock(&dev->wed_lock);
+       spin_lock_bh(&dev->wed_lock);
        list_add(&t->list, &dev->rxwi_cache);
-       spin_unlock(&dev->wed_lock);
+       spin_unlock_bh(&dev->wed_lock);
 }
 EXPORT_SYMBOL_GPL(mt76_put_rxwi);
 
index 0acabba..5d402cf 100644 (file)
@@ -131,15 +131,8 @@ u8 mt76x02_get_lna_gain(struct mt76x02_dev *dev,
                        s8 *lna_2g, s8 *lna_5g,
                        struct ieee80211_channel *chan)
 {
-       u16 val;
        u8 lna;
 
-       val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_1);
-       if (val & MT_EE_NIC_CONF_1_LNA_EXT_2G)
-               *lna_2g = 0;
-       if (val & MT_EE_NIC_CONF_1_LNA_EXT_5G)
-               memset(lna_5g, 0, sizeof(s8) * 3);
-
        if (chan->band == NL80211_BAND_2GHZ)
                lna = *lna_2g;
        else if (chan->hw_value <= 64)
index d580940..8c01855 100644 (file)
@@ -256,7 +256,8 @@ void mt76x2_read_rx_gain(struct mt76x02_dev *dev)
        struct ieee80211_channel *chan = dev->mphy.chandef.chan;
        int channel = chan->hw_value;
        s8 lna_5g[3], lna_2g;
-       u8 lna;
+       bool use_lna;
+       u8 lna = 0;
        u16 val;
 
        if (chan->band == NL80211_BAND_2GHZ)
@@ -275,7 +276,15 @@ void mt76x2_read_rx_gain(struct mt76x02_dev *dev)
        dev->cal.rx.mcu_gain |= (lna_5g[1] & 0xff) << 16;
        dev->cal.rx.mcu_gain |= (lna_5g[2] & 0xff) << 24;
 
-       lna = mt76x02_get_lna_gain(dev, &lna_2g, lna_5g, chan);
+       val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_1);
+       if (chan->band == NL80211_BAND_2GHZ)
+               use_lna = !(val & MT_EE_NIC_CONF_1_LNA_EXT_2G);
+       else
+               use_lna = !(val & MT_EE_NIC_CONF_1_LNA_EXT_5G);
+
+       if (use_lna)
+               lna = mt76x02_get_lna_gain(dev, &lna_2g, lna_5g, chan);
+
        dev->cal.rx.lna_gain = mt76x02_sign_extend(lna, 8);
 }
 EXPORT_SYMBOL_GPL(mt76x2_read_rx_gain);
index 3642a2c..2434e24 100644 (file)
@@ -46,6 +46,7 @@ struct rtw8723du_efuse {
        u8 vender_id[2];                /* 0x100 */
        u8 product_id[2];               /* 0x102 */
        u8 usb_option;                  /* 0x104 */
+       u8 res5[2];                     /* 0x105 */
        u8 mac_addr[ETH_ALEN];          /* 0x107 */
 };
 
index 0a3483e..f63250c 100644 (file)
@@ -890,13 +890,13 @@ int of_changeset_action(struct of_changeset *ocs, unsigned long action,
 {
        struct of_changeset_entry *ce;
 
+       if (WARN_ON(action >= ARRAY_SIZE(action_names)))
+               return -EINVAL;
+
        ce = kzalloc(sizeof(*ce), GFP_KERNEL);
        if (!ce)
                return -ENOMEM;
 
-       if (WARN_ON(action >= ARRAY_SIZE(action_names)))
-               return -EINVAL;
-
        /* get a reference to the node */
        ce->action = action;
        ce->np = of_node_get(np);
index dfb6fb9..a9a292d 100644 (file)
@@ -45,8 +45,8 @@ struct target {
 
 /**
  * struct fragment - info about fragment nodes in overlay expanded device tree
- * @target:    target of the overlay operation
  * @overlay:   pointer to the __overlay__ node
+ * @target:    target of the overlay operation
  */
 struct fragment {
        struct device_node *overlay;
index e2f2940..64420ec 100644 (file)
@@ -43,7 +43,6 @@
 #define PARF_PHY_REFCLK                                0x4c
 #define PARF_CONFIG_BITS                       0x50
 #define PARF_DBI_BASE_ADDR                     0x168
-#define PARF_SLV_ADDR_SPACE_SIZE_2_3_3         0x16c /* Register offset specific to IP ver 2.3.3 */
 #define PARF_MHI_CLOCK_RESET_CTRL              0x174
 #define PARF_AXI_MSTR_WR_ADDR_HALT             0x178
 #define PARF_AXI_MSTR_WR_ADDR_HALT_V2          0x1a8
@@ -797,8 +796,7 @@ static int qcom_pcie_post_init_2_3_3(struct qcom_pcie *pcie)
        u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
        u32 val;
 
-       writel(SLV_ADDR_SPACE_SZ,
-               pcie->parf + PARF_SLV_ADDR_SPACE_SIZE_2_3_3);
+       writel(SLV_ADDR_SPACE_SZ, pcie->parf + PARF_SLV_ADDR_SPACE_SIZE);
 
        val = readl(pcie->parf + PARF_PHY_CTRL);
        val &= ~PHY_TEST_PWR_DOWN;
index 2af64bc..51e3dd0 100644 (file)
@@ -657,30 +657,33 @@ void of_pci_make_dev_node(struct pci_dev *pdev)
 
        cset = kmalloc(sizeof(*cset), GFP_KERNEL);
        if (!cset)
-               goto failed;
+               goto out_free_name;
        of_changeset_init(cset);
 
        np = of_changeset_create_node(cset, ppnode, name);
        if (!np)
-               goto failed;
-       np->data = cset;
+               goto out_destroy_cset;
 
        ret = of_pci_add_properties(pdev, cset, np);
        if (ret)
-               goto failed;
+               goto out_free_node;
 
        ret = of_changeset_apply(cset);
        if (ret)
-               goto failed;
+               goto out_free_node;
 
+       np->data = cset;
        pdev->dev.of_node = np;
        kfree(name);
 
        return;
 
-failed:
-       if (np)
-               of_node_put(np);
+out_free_node:
+       of_node_put(np);
+out_destroy_cset:
+       of_changeset_destroy(cset);
+       kfree(cset);
+out_free_name:
        kfree(name);
 }
 #endif
index 710ec35..c2c7334 100644 (file)
@@ -186,8 +186,8 @@ static int of_pci_prop_interrupts(struct pci_dev *pdev,
 static int of_pci_prop_intr_map(struct pci_dev *pdev, struct of_changeset *ocs,
                                struct device_node *np)
 {
+       u32 i, addr_sz[OF_PCI_MAX_INT_PIN] = { 0 }, map_sz = 0;
        struct of_phandle_args out_irq[OF_PCI_MAX_INT_PIN];
-       u32 i, addr_sz[OF_PCI_MAX_INT_PIN], map_sz = 0;
        __be32 laddr[OF_PCI_ADDRESS_CELLS] = { 0 };
        u32 int_map_mask[] = { 0xffff00, 0, 0, 7 };
        struct device_node *pnode;
@@ -213,33 +213,44 @@ static int of_pci_prop_intr_map(struct pci_dev *pdev, struct of_changeset *ocs,
                out_irq[i].args[0] = pin;
                ret = of_irq_parse_raw(laddr, &out_irq[i]);
                if (ret) {
-                       pci_err(pdev, "parse irq %d failed, ret %d", pin, ret);
+                       out_irq[i].np = NULL;
+                       pci_dbg(pdev, "parse irq %d failed, ret %d", pin, ret);
                        continue;
                }
-               ret = of_property_read_u32(out_irq[i].np, "#address-cells",
-                                          &addr_sz[i]);
-               if (ret)
-                       addr_sz[i] = 0;
+               of_property_read_u32(out_irq[i].np, "#address-cells",
+                                    &addr_sz[i]);
        }
 
        list_for_each_entry(child, &pdev->subordinate->devices, bus_list) {
                for (pin = 1; pin <= OF_PCI_MAX_INT_PIN; pin++) {
                        i = pci_swizzle_interrupt_pin(child, pin) - 1;
+                       if (!out_irq[i].np)
+                               continue;
                        map_sz += 5 + addr_sz[i] + out_irq[i].args_count;
                }
        }
 
+       /*
+        * Parsing interrupt failed for all pins. In this case, it does not
+        * need to generate interrupt-map property.
+        */
+       if (!map_sz)
+               return 0;
+
        int_map = kcalloc(map_sz, sizeof(u32), GFP_KERNEL);
        mapp = int_map;
 
        list_for_each_entry(child, &pdev->subordinate->devices, bus_list) {
                for (pin = 1; pin <= OF_PCI_MAX_INT_PIN; pin++) {
+                       i = pci_swizzle_interrupt_pin(child, pin) - 1;
+                       if (!out_irq[i].np)
+                               continue;
+
                        *mapp = (child->bus->number << 16) |
                                (child->devfn << 8);
                        mapp += OF_PCI_ADDRESS_CELLS;
                        *mapp = pin;
                        mapp++;
-                       i = pci_swizzle_interrupt_pin(child, pin) - 1;
                        *mapp = out_irq[i].np->phandle;
                        mapp++;
                        if (addr_sz[i]) {
index a79c110..51ec9e7 100644 (file)
@@ -572,7 +572,19 @@ static void pci_pm_default_resume_early(struct pci_dev *pci_dev)
 
 static void pci_pm_bridge_power_up_actions(struct pci_dev *pci_dev)
 {
-       pci_bridge_wait_for_secondary_bus(pci_dev, "resume");
+       int ret;
+
+       ret = pci_bridge_wait_for_secondary_bus(pci_dev, "resume");
+       if (ret) {
+               /*
+                * The downstream link failed to come up, so mark the
+                * devices below as disconnected to make sure we don't
+                * attempt to resume them.
+                */
+               pci_walk_bus(pci_dev->subordinate, pci_dev_set_disconnected,
+                            NULL);
+               return;
+       }
 
        /*
         * When powering on a bridge from D3cold, the whole hierarchy may be
index e85ff94..9c8fd69 100644 (file)
@@ -229,6 +229,7 @@ int pcie_aer_is_native(struct pci_dev *dev)
 
        return pcie_ports_native || host->native_aer;
 }
+EXPORT_SYMBOL_NS_GPL(pcie_aer_is_native, CXL);
 
 static int pci_enable_pcie_error_reporting(struct pci_dev *dev)
 {
index 58a2b1a..1f3803b 100644 (file)
@@ -29,10 +29,8 @@ extern bool pcie_ports_dpc_native;
 
 #ifdef CONFIG_PCIEAER
 int pcie_aer_init(void);
-int pcie_aer_is_native(struct pci_dev *dev);
 #else
 static inline int pcie_aer_init(void) { return 0; }
-static inline int pcie_aer_is_native(struct pci_dev *dev) { return 0; }
 #endif
 
 #ifdef CONFIG_HOTPLUG_PCI_PCIE
index 913dc04..6b50bc5 100644 (file)
@@ -1972,7 +1972,7 @@ static irqreturn_t arm_cmn_handle_irq(int irq, void *dev_id)
                u64 delta;
                int i;
 
-               for (i = 0; i < CMN_DTM_NUM_COUNTERS; i++) {
+               for (i = 0; i < CMN_DT_NUM_COUNTERS; i++) {
                        if (status & (1U << i)) {
                                ret = IRQ_HANDLED;
                                if (WARN_ON(!dtc->counters[i]))
index f3696a5..fd38d8c 100644 (file)
@@ -53,7 +53,7 @@
 struct mlxbf_tmfifo;
 
 /**
- * mlxbf_tmfifo_vring - Structure of the TmFifo virtual ring
+ * struct mlxbf_tmfifo_vring - Structure of the TmFifo virtual ring
  * @va: virtual address of the ring
  * @dma: dma address of the ring
  * @vq: pointer to the virtio virtqueue
@@ -113,12 +113,13 @@ enum {
 };
 
 /**
- * mlxbf_tmfifo_vdev - Structure of the TmFifo virtual device
+ * struct mlxbf_tmfifo_vdev - Structure of the TmFifo virtual device
  * @vdev: virtio device, in which the vdev.id.device field has the
  *        VIRTIO_ID_xxx id to distinguish the virtual device.
  * @status: status of the device
  * @features: supported features of the device
  * @vrings: array of tmfifo vrings of this device
+ * @config: non-anonymous union for cons and net
  * @config.cons: virtual console config -
  *               select if vdev.id.device is VIRTIO_ID_CONSOLE
  * @config.net: virtual network config -
@@ -138,7 +139,7 @@ struct mlxbf_tmfifo_vdev {
 };
 
 /**
- * mlxbf_tmfifo_irq_info - Structure of the interrupt information
+ * struct mlxbf_tmfifo_irq_info - Structure of the interrupt information
  * @fifo: pointer to the tmfifo structure
  * @irq: interrupt number
  * @index: index into the interrupt array
@@ -150,7 +151,7 @@ struct mlxbf_tmfifo_irq_info {
 };
 
 /**
- * mlxbf_tmfifo_io - Structure of the TmFifo IO resource (for both rx & tx)
+ * struct mlxbf_tmfifo_io - Structure of the TmFifo IO resource (for both rx & tx)
  * @ctl: control register offset (TMFIFO_RX_CTL / TMFIFO_TX_CTL)
  * @sts: status register offset (TMFIFO_RX_STS / TMFIFO_TX_STS)
  * @data: data register offset (TMFIFO_RX_DATA / TMFIFO_TX_DATA)
@@ -162,7 +163,7 @@ struct mlxbf_tmfifo_io {
 };
 
 /**
- * mlxbf_tmfifo - Structure of the TmFifo
+ * struct mlxbf_tmfifo - Structure of the TmFifo
  * @vdev: array of the virtual devices running over the TmFifo
  * @lock: lock to protect the TmFifo access
  * @res0: mapped resource block 0
@@ -198,7 +199,7 @@ struct mlxbf_tmfifo {
 };
 
 /**
- * mlxbf_tmfifo_msg_hdr - Structure of the TmFifo message header
+ * struct mlxbf_tmfifo_msg_hdr - Structure of the TmFifo message header
  * @type: message type
  * @len: payload length in network byte order. Messages sent into the FIFO
  *       will be read by the other side as data stream in the same byte order.
@@ -208,6 +209,7 @@ struct mlxbf_tmfifo {
 struct mlxbf_tmfifo_msg_hdr {
        u8 type;
        __be16 len;
+       /* private: */
        u8 unused[5];
 } __packed __aligned(sizeof(u64));
 
index 8c4f9e1..5798b49 100644 (file)
@@ -659,7 +659,7 @@ static int hp_init_bios_package_attribute(enum hp_wmi_data_type attr_type,
                                          const char *guid, int min_elements,
                                          int instance_id)
 {
-       struct kobject *attr_name_kobj;
+       struct kobject *attr_name_kobj, *duplicate;
        union acpi_object *elements;
        struct kset *temp_kset;
 
@@ -704,8 +704,11 @@ static int hp_init_bios_package_attribute(enum hp_wmi_data_type attr_type,
        }
 
        /* All duplicate attributes found are ignored */
-       if (kset_find_obj(temp_kset, str_value)) {
+       duplicate = kset_find_obj(temp_kset, str_value);
+       if (duplicate) {
                pr_debug("Duplicate attribute name found - %s\n", str_value);
+               /* kset_find_obj() returns a reference */
+               kobject_put(duplicate);
                goto pack_attr_exit;
        }
 
@@ -768,7 +771,7 @@ static int hp_init_bios_buffer_attribute(enum hp_wmi_data_type attr_type,
                                         const char *guid, int min_elements,
                                         int instance_id)
 {
-       struct kobject *attr_name_kobj;
+       struct kobject *attr_name_kobj, *duplicate;
        struct kset *temp_kset;
        char str[MAX_BUFF_SIZE];
 
@@ -794,8 +797,11 @@ static int hp_init_bios_buffer_attribute(enum hp_wmi_data_type attr_type,
                temp_kset = bioscfg_drv.main_dir_kset;
 
        /* All duplicate attributes found are ignored */
-       if (kset_find_obj(temp_kset, str)) {
+       duplicate = kset_find_obj(temp_kset, str);
+       if (duplicate) {
                pr_debug("Duplicate attribute name found - %s\n", str);
+               /* kset_find_obj() returns a reference */
+               kobject_put(duplicate);
                goto buff_attr_exit;
        }
 
index e76e545..8ebb7be 100644 (file)
@@ -1548,7 +1548,13 @@ static const struct dev_pm_ops hp_wmi_pm_ops = {
        .restore  = hp_wmi_resume_handler,
 };
 
-static struct platform_driver hp_wmi_driver = {
+/*
+ * hp_wmi_bios_remove() lives in .exit.text. For drivers registered via
+ * module_platform_driver_probe() this is ok because they cannot get unbound at
+ * runtime. So mark the driver struct with __refdata to prevent modpost
+ * triggering a section mismatch warning.
+ */
+static struct platform_driver hp_wmi_driver __refdata = {
        .driver = {
                .name = "hp-wmi",
                .pm = &hp_wmi_pm_ops,
index 1061eb7..43c864a 100644 (file)
@@ -331,14 +331,15 @@ int do_core_test(int cpu, struct device *dev)
        switch (test->test_num) {
        case IFS_TYPE_SAF:
                if (!ifsd->loaded)
-                       return -EPERM;
-               ifs_test_core(cpu, dev);
+                       ret = -EPERM;
+               else
+                       ifs_test_core(cpu, dev);
                break;
        case IFS_TYPE_ARRAY_BIST:
                ifs_array_test_core(cpu, dev);
                break;
        default:
-               return -EINVAL;
+               ret = -EINVAL;
        }
 out:
        cpus_read_unlock();
index 6851d10..a68df41 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
+#include <linux/iopoll.h>
 #include <linux/module.h>
 #include <linux/slab.h>
 
@@ -231,19 +232,15 @@ static inline u32 ipc_data_readl(struct intel_scu_ipc_dev *scu, u32 offset)
 /* Wait till scu status is busy */
 static inline int busy_loop(struct intel_scu_ipc_dev *scu)
 {
-       unsigned long end = jiffies + IPC_TIMEOUT;
-
-       do {
-               u32 status;
-
-               status = ipc_read_status(scu);
-               if (!(status & IPC_STATUS_BUSY))
-                       return (status & IPC_STATUS_ERR) ? -EIO : 0;
+       u8 status;
+       int err;
 
-               usleep_range(50, 100);
-       } while (time_before(jiffies, end));
+       err = readx_poll_timeout(ipc_read_status, scu, status, !(status & IPC_STATUS_BUSY),
+                                100, jiffies_to_usecs(IPC_TIMEOUT));
+       if (err)
+               return err;
 
-       return -ETIMEDOUT;
+       return (status & IPC_STATUS_ERR) ? -EIO : 0;
 }
 
 /* Wait till ipc ioc interrupt is received or timeout in 10 HZ */
@@ -251,10 +248,12 @@ static inline int ipc_wait_for_interrupt(struct intel_scu_ipc_dev *scu)
 {
        int status;
 
-       if (!wait_for_completion_timeout(&scu->cmd_complete, IPC_TIMEOUT))
-               return -ETIMEDOUT;
+       wait_for_completion_timeout(&scu->cmd_complete, IPC_TIMEOUT);
 
        status = ipc_read_status(scu);
+       if (status & IPC_STATUS_BUSY)
+               return -ETIMEDOUT;
+
        if (status & IPC_STATUS_ERR)
                return -EIO;
 
@@ -266,6 +265,24 @@ static int intel_scu_ipc_check_status(struct intel_scu_ipc_dev *scu)
        return scu->irq > 0 ? ipc_wait_for_interrupt(scu) : busy_loop(scu);
 }
 
+static struct intel_scu_ipc_dev *intel_scu_ipc_get(struct intel_scu_ipc_dev *scu)
+{
+       u8 status;
+
+       if (!scu)
+               scu = ipcdev;
+       if (!scu)
+               return ERR_PTR(-ENODEV);
+
+       status = ipc_read_status(scu);
+       if (status & IPC_STATUS_BUSY) {
+               dev_dbg(&scu->dev, "device is busy\n");
+               return ERR_PTR(-EBUSY);
+       }
+
+       return scu;
+}
+
 /* Read/Write power control(PMIC in Langwell, MSIC in PenWell) registers */
 static int pwr_reg_rdwr(struct intel_scu_ipc_dev *scu, u16 *addr, u8 *data,
                        u32 count, u32 op, u32 id)
@@ -279,11 +296,10 @@ static int pwr_reg_rdwr(struct intel_scu_ipc_dev *scu, u16 *addr, u8 *data,
        memset(cbuf, 0, sizeof(cbuf));
 
        mutex_lock(&ipclock);
-       if (!scu)
-               scu = ipcdev;
-       if (!scu) {
+       scu = intel_scu_ipc_get(scu);
+       if (IS_ERR(scu)) {
                mutex_unlock(&ipclock);
-               return -ENODEV;
+               return PTR_ERR(scu);
        }
 
        for (nc = 0; nc < count; nc++, offset += 2) {
@@ -438,13 +454,12 @@ int intel_scu_ipc_dev_simple_command(struct intel_scu_ipc_dev *scu, int cmd,
        int err;
 
        mutex_lock(&ipclock);
-       if (!scu)
-               scu = ipcdev;
-       if (!scu) {
+       scu = intel_scu_ipc_get(scu);
+       if (IS_ERR(scu)) {
                mutex_unlock(&ipclock);
-               return -ENODEV;
+               return PTR_ERR(scu);
        }
-       scu = ipcdev;
+
        cmdval = sub << 12 | cmd;
        ipc_command(scu, cmdval);
        err = intel_scu_ipc_check_status(scu);
@@ -484,11 +499,10 @@ int intel_scu_ipc_dev_command_with_size(struct intel_scu_ipc_dev *scu, int cmd,
                return -EINVAL;
 
        mutex_lock(&ipclock);
-       if (!scu)
-               scu = ipcdev;
-       if (!scu) {
+       scu = intel_scu_ipc_get(scu);
+       if (IS_ERR(scu)) {
                mutex_unlock(&ipclock);
-               return -ENODEV;
+               return PTR_ERR(scu);
        }
 
        memcpy(inbuf, in, inlen);
index 7934688..aee8697 100644 (file)
@@ -1248,6 +1248,24 @@ static void tlmi_release_attr(void)
        kset_unregister(tlmi_priv.authentication_kset);
 }
 
+static int tlmi_validate_setting_name(struct kset *attribute_kset, char *name)
+{
+       struct kobject *duplicate;
+
+       if (!strcmp(name, "Reserved"))
+               return -EINVAL;
+
+       duplicate = kset_find_obj(attribute_kset, name);
+       if (duplicate) {
+               pr_debug("Duplicate attribute name found - %s\n", name);
+               /* kset_find_obj() returns a reference */
+               kobject_put(duplicate);
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
 static int tlmi_sysfs_init(void)
 {
        int i, ret;
@@ -1276,10 +1294,8 @@ static int tlmi_sysfs_init(void)
                        continue;
 
                /* check for duplicate or reserved values */
-               if (kset_find_obj(tlmi_priv.attribute_kset, tlmi_priv.setting[i]->display_name) ||
-                   !strcmp(tlmi_priv.setting[i]->display_name, "Reserved")) {
-                       pr_debug("duplicate or reserved attribute name found - %s\n",
-                               tlmi_priv.setting[i]->display_name);
+               if (tlmi_validate_setting_name(tlmi_priv.attribute_kset,
+                                              tlmi_priv.setting[i]->display_name) < 0) {
                        kfree(tlmi_priv.setting[i]->possible_values);
                        kfree(tlmi_priv.setting[i]);
                        tlmi_priv.setting[i] = NULL;
index d70c89d..4158442 100644 (file)
@@ -4116,9 +4116,11 @@ static void hotkey_resume(void)
 {
        tpacpi_disable_brightness_delay();
 
+       mutex_lock(&hotkey_mutex);
        if (hotkey_status_set(true) < 0 ||
            hotkey_mask_set(hotkey_acpi_mask) < 0)
                pr_err("error while attempting to reset the event firmware interface\n");
+       mutex_unlock(&hotkey_mutex);
 
        tpacpi_send_radiosw_update();
        tpacpi_input_send_tabletsw();
index f9301a9..0c67337 100644 (file)
@@ -42,6 +42,21 @@ static const struct ts_dmi_data archos_101_cesium_educ_data = {
        .properties     = archos_101_cesium_educ_props,
 };
 
+static const struct property_entry bush_bush_windows_tablet_props[] = {
+       PROPERTY_ENTRY_U32("touchscreen-size-x", 1850),
+       PROPERTY_ENTRY_U32("touchscreen-size-y", 1280),
+       PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
+       PROPERTY_ENTRY_U32("silead,max-fingers", 10),
+       PROPERTY_ENTRY_BOOL("silead,home-button"),
+       PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-bush-bush-windows-tablet.fw"),
+       { }
+};
+
+static const struct ts_dmi_data bush_bush_windows_tablet_data = {
+       .acpi_name      = "MSSL1680:00",
+       .properties     = bush_bush_windows_tablet_props,
+};
+
 static const struct property_entry chuwi_hi8_props[] = {
        PROPERTY_ENTRY_U32("touchscreen-size-x", 1665),
        PROPERTY_ENTRY_U32("touchscreen-size-y", 1140),
@@ -756,6 +771,21 @@ static const struct ts_dmi_data pipo_w11_data = {
        .properties     = pipo_w11_props,
 };
 
+static const struct property_entry positivo_c4128b_props[] = {
+       PROPERTY_ENTRY_U32("touchscreen-min-x", 4),
+       PROPERTY_ENTRY_U32("touchscreen-min-y", 13),
+       PROPERTY_ENTRY_U32("touchscreen-size-x", 1915),
+       PROPERTY_ENTRY_U32("touchscreen-size-y", 1269),
+       PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-positivo-c4128b.fw"),
+       PROPERTY_ENTRY_U32("silead,max-fingers", 10),
+       { }
+};
+
+static const struct ts_dmi_data positivo_c4128b_data = {
+       .acpi_name      = "MSSL1680:00",
+       .properties     = positivo_c4128b_props,
+};
+
 static const struct property_entry pov_mobii_wintab_p800w_v20_props[] = {
        PROPERTY_ENTRY_U32("touchscreen-min-x", 32),
        PROPERTY_ENTRY_U32("touchscreen-min-y", 16),
@@ -1071,6 +1101,13 @@ const struct dmi_system_id touchscreen_dmi_table[] = {
                },
        },
        {
+               /* Bush Windows tablet */
+               .driver_data = (void *)&bush_bush_windows_tablet_data,
+               .matches = {
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Bush Windows tablet"),
+               },
+       },
+       {
                /* Chuwi Hi8 */
                .driver_data = (void *)&chuwi_hi8_data,
                .matches = {
@@ -1481,6 +1518,14 @@ const struct dmi_system_id touchscreen_dmi_table[] = {
                },
        },
        {
+               /* Positivo C4128B */
+               .driver_data = (void *)&positivo_c4128b_data,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Positivo Tecnologia SA"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "C4128B-1"),
+               },
+       },
+       {
                /* Point of View mobii wintab p800w (v2.0) */
                .driver_data = (void *)&pov_mobii_wintab_p800w_v20_data,
                .matches = {
index 59e1ebb..411e00b 100644 (file)
@@ -300,7 +300,7 @@ config NVMEM_REBOOT_MODE
 
 config POWER_MLXBF
        tristate "Mellanox BlueField power handling driver"
-       depends on (GPIO_MLXBF2 && ACPI)
+       depends on (GPIO_MLXBF2 || GPIO_MLXBF3) && ACPI
        help
          This driver supports reset or low power mode handling for Mellanox BlueField.
 
index 12dedf8..de35d24 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-only or BSD-3-Clause
+// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause
 
 /*
  *  Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES.
index 447ffda..17064d7 100644 (file)
@@ -121,7 +121,7 @@ static int vexpress_reset_probe(struct platform_device *pdev)
                return PTR_ERR(regmap);
        dev_set_drvdata(&pdev->dev, regmap);
 
-       switch ((enum vexpress_reset_func)match->data) {
+       switch ((uintptr_t)match->data) {
        case FUNC_SHUTDOWN:
                vexpress_power_off_device = &pdev->dev;
                pm_power_off = vexpress_power_off;
index 663a1c4..a61bb12 100644 (file)
@@ -769,6 +769,7 @@ config BATTERY_RT5033
 config CHARGER_RT5033
        tristate "RT5033 battery charger support"
        depends on MFD_RT5033
+       depends on EXTCON || !EXTCON
        help
          This adds support for battery charger in Richtek RT5033 PMIC.
          The device supports pre-charge mode, fast charge mode and
index 6f83e99..ce36d6c 100644 (file)
@@ -115,7 +115,6 @@ struct ab8500_btemp {
 static enum power_supply_property ab8500_btemp_props[] = {
        POWER_SUPPLY_PROP_PRESENT,
        POWER_SUPPLY_PROP_ONLINE,
-       POWER_SUPPLY_PROP_TECHNOLOGY,
        POWER_SUPPLY_PROP_TEMP,
 };
 
@@ -532,12 +531,6 @@ static int ab8500_btemp_get_property(struct power_supply *psy,
                else
                        val->intval = 1;
                break;
-       case POWER_SUPPLY_PROP_TECHNOLOGY:
-               if (di->bm->bi)
-                       val->intval = di->bm->bi->technology;
-               else
-                       val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
-               break;
        case POWER_SUPPLY_PROP_TEMP:
                val->intval = ab8500_btemp_get_temp(di);
                break;
@@ -662,7 +655,7 @@ static char *supply_interface[] = {
 
 static const struct power_supply_desc ab8500_btemp_desc = {
        .name                   = "ab8500_btemp",
-       .type                   = POWER_SUPPLY_TYPE_BATTERY,
+       .type                   = POWER_SUPPLY_TYPE_UNKNOWN,
        .properties             = ab8500_btemp_props,
        .num_properties         = ARRAY_SIZE(ab8500_btemp_props),
        .get_property           = ab8500_btemp_get_property,
index ea4ad61..2205ea0 100644 (file)
@@ -1720,7 +1720,7 @@ static char *supply_interface[] = {
 
 static const struct power_supply_desc ab8500_chargalg_desc = {
        .name                   = "ab8500_chargalg",
-       .type                   = POWER_SUPPLY_TYPE_BATTERY,
+       .type                   = POWER_SUPPLY_TYPE_UNKNOWN,
        .properties             = ab8500_chargalg_props,
        .num_properties         = ARRAY_SIZE(ab8500_chargalg_props),
        .get_property           = ab8500_chargalg_get_property,
index f27dae5..a9641bd 100644 (file)
@@ -324,7 +324,7 @@ static int mt6370_chg_toggle_cfo(struct mt6370_priv *priv)
 
        if (fl_strobe) {
                dev_err(priv->dev, "Flash led is still in strobe mode\n");
-               return ret;
+               return -EINVAL;
        }
 
        /* cfo off */
index 06e5b6b..d483a81 100644 (file)
@@ -482,6 +482,13 @@ int power_supply_uevent(const struct device *dev, struct kobj_uevent_env *env)
        if (ret)
                return ret;
 
+       /*
+        * Kernel generates KOBJ_REMOVE uevent in device removal path, after
+        * resources have been freed. Exit early to avoid use-after-free.
+        */
+       if (psy->removing)
+               return 0;
+
        prop_buf = (char *)get_zeroed_page(GFP_KERNEL);
        if (!prop_buf)
                return -ENOMEM;
index 8328bce..f64daf5 100644 (file)
@@ -1045,6 +1045,13 @@ static void rk817_charging_monitor(struct work_struct *work)
        queue_delayed_work(system_wq, &charger->work, msecs_to_jiffies(8000));
 }
 
+static void rk817_cleanup_node(void *data)
+{
+       struct device_node *node = data;
+
+       of_node_put(node);
+}
+
 static int rk817_charger_probe(struct platform_device *pdev)
 {
        struct rk808 *rk808 = dev_get_drvdata(pdev->dev.parent);
@@ -1061,11 +1068,13 @@ static int rk817_charger_probe(struct platform_device *pdev)
        if (!node)
                return -ENODEV;
 
+       ret = devm_add_action_or_reset(&pdev->dev, rk817_cleanup_node, node);
+       if (ret)
+               return ret;
+
        charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL);
-       if (!charger) {
-               of_node_put(node);
+       if (!charger)
                return -ENOMEM;
-       }
 
        charger->rk808 = rk808;
 
@@ -1211,3 +1220,4 @@ MODULE_DESCRIPTION("Battery power supply driver for RK817 PMIC");
 MODULE_AUTHOR("Maya Matuszczyk <maccraft123mc@gmail.com>");
 MODULE_AUTHOR("Chris Morgan <macromorgan@hotmail.com>");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:rk817-charger");
index 683adb1..fdfdc83 100644 (file)
@@ -598,8 +598,8 @@ static int rt9467_run_aicl(struct rt9467_chg_data *data)
 
        reinit_completion(&data->aicl_done);
        ret = wait_for_completion_timeout(&data->aicl_done, msecs_to_jiffies(3500));
-       if (ret)
-               return ret;
+       if (ret == 0)
+               return -ETIMEDOUT;
 
        ret = rt9467_get_value_from_ranges(data, F_IAICR, RT9467_RANGE_IAICR, &aicr_get);
        if (ret) {
index 954feba..7970843 100644 (file)
@@ -384,7 +384,8 @@ static int ucs1002_get_property(struct power_supply *psy,
        case POWER_SUPPLY_PROP_USB_TYPE:
                return ucs1002_get_usb_type(info, val);
        case POWER_SUPPLY_PROP_HEALTH:
-               return val->intval = info->health;
+               val->intval = info->health;
+               return 0;
        case POWER_SUPPLY_PROP_PRESENT:
                val->intval = info->present;
                return 0;
index 20a974c..a7a6947 100644 (file)
@@ -3998,7 +3998,6 @@ ptp_ocp_device_init(struct ptp_ocp *bp, struct pci_dev *pdev)
        return 0;
 
 out:
-       ptp_ocp_dev_release(&bp->dev);
        put_device(&bp->dev);
        return err;
 }
index d8e1caa..3137e40 100644 (file)
@@ -5542,6 +5542,8 @@ regulator_register(struct device *dev,
                goto rinse;
        }
        device_initialize(&rdev->dev);
+       dev_set_drvdata(&rdev->dev, rdev);
+       rdev->dev.class = &regulator_class;
        spin_lock_init(&rdev->err_lock);
 
        /*
@@ -5603,11 +5605,9 @@ regulator_register(struct device *dev,
                rdev->supply_name = regulator_desc->supply_name;
 
        /* register with sysfs */
-       rdev->dev.class = &regulator_class;
        rdev->dev.parent = config->dev;
        dev_set_name(&rdev->dev, "regulator.%lu",
                    (unsigned long) atomic_inc_return(&regulator_no));
-       dev_set_drvdata(&rdev->dev, rdev);
 
        /* set regulator constraints */
        if (init_data)
@@ -5724,15 +5724,11 @@ wash:
        mutex_lock(&regulator_list_mutex);
        regulator_ena_gpio_free(rdev);
        mutex_unlock(&regulator_list_mutex);
-       put_device(&rdev->dev);
-       rdev = NULL;
 clean:
        if (dangling_of_gpiod)
                gpiod_put(config->ena_gpiod);
-       if (rdev && rdev->dev.of_node)
-               of_node_put(rdev->dev.of_node);
-       kfree(rdev);
        kfree(config);
+       put_device(&rdev->dev);
 rinse:
        if (dangling_cfg_gpiod)
                gpiod_put(cfg->ena_gpiod);
index 5ad5f3b..d492683 100644 (file)
@@ -197,7 +197,7 @@ int regulator_set_voltage_sel_pickable_regmap(struct regulator_dev *rdev,
        sel += rdev->desc->linear_ranges[i].min_sel;
 
        range = rdev->desc->linear_range_selectors_bitfield[i];
-       range <<= ffs(rdev->desc->vsel_mask) - 1;
+       range <<= ffs(rdev->desc->vsel_range_mask) - 1;
 
        if (rdev->desc->vsel_reg == rdev->desc->vsel_range_reg) {
                ret = regmap_update_bits(rdev->regmap,
index b9cda22..65fbd95 100644 (file)
@@ -43,7 +43,7 @@ struct mt6358_regulator_info {
        .desc = {       \
                .name = #vreg,  \
                .of_match = of_match_ptr(match),        \
-               .ops = &mt6358_volt_range_ops,  \
+               .ops = &mt6358_buck_ops,        \
                .type = REGULATOR_VOLTAGE,      \
                .id = MT6358_ID_##vreg,         \
                .owner = THIS_MODULE,           \
@@ -139,7 +139,7 @@ struct mt6358_regulator_info {
        .desc = {       \
                .name = #vreg,  \
                .of_match = of_match_ptr(match),        \
-               .ops = &mt6358_volt_range_ops,  \
+               .ops = &mt6358_buck_ops,        \
                .type = REGULATOR_VOLTAGE,      \
                .id = MT6366_ID_##vreg,         \
                .owner = THIS_MODULE,           \
@@ -450,7 +450,7 @@ static unsigned int mt6358_regulator_get_mode(struct regulator_dev *rdev)
        }
 }
 
-static const struct regulator_ops mt6358_volt_range_ops = {
+static const struct regulator_ops mt6358_buck_ops = {
        .list_voltage = regulator_list_voltage_linear,
        .map_voltage = regulator_map_voltage_linear,
        .set_voltage_sel = regulator_set_voltage_sel_regmap,
@@ -464,6 +464,18 @@ static const struct regulator_ops mt6358_volt_range_ops = {
        .get_mode = mt6358_regulator_get_mode,
 };
 
+static const struct regulator_ops mt6358_volt_range_ops = {
+       .list_voltage = regulator_list_voltage_linear,
+       .map_voltage = regulator_map_voltage_linear,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
+       .get_voltage_sel = mt6358_get_buck_voltage_sel,
+       .set_voltage_time_sel = regulator_set_voltage_time_sel,
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .get_status = mt6358_get_status,
+};
+
 static const struct regulator_ops mt6358_volt_table_ops = {
        .list_voltage = regulator_list_voltage_table,
        .map_voltage = regulator_map_voltage_iterate,
index df78264..ab2f35b 100644 (file)
@@ -518,12 +518,12 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn,
        if (port) {
                put_device(&port->dev);
                retval = -EEXIST;
-               goto err_out;
+               goto err_put;
        }
 
        port = kzalloc(sizeof(struct zfcp_port), GFP_KERNEL);
        if (!port)
-               goto err_out;
+               goto err_put;
 
        rwlock_init(&port->unit_list_lock);
        INIT_LIST_HEAD(&port->unit_list);
@@ -546,7 +546,7 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn,
 
        if (dev_set_name(&port->dev, "0x%016llx", (unsigned long long)wwpn)) {
                kfree(port);
-               goto err_out;
+               goto err_put;
        }
        retval = -EINVAL;
 
@@ -563,7 +563,8 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn,
 
        return port;
 
-err_out:
+err_put:
        zfcp_ccw_adapter_put(adapter);
+err_out:
        return ERR_PTR(retval);
 }
index 93c6893..22cef28 100644 (file)
@@ -27,7 +27,7 @@
 
 #define DRV_NAME               "fnic"
 #define DRV_DESCRIPTION                "Cisco FCoE HBA Driver"
-#define DRV_VERSION            "1.6.0.56"
+#define DRV_VERSION            "1.6.0.57"
 #define PFX                    DRV_NAME ": "
 #define DFX                     DRV_NAME "%d: "
 
@@ -237,6 +237,8 @@ struct fnic {
        unsigned int cq_count;
 
        struct mutex sgreset_mutex;
+       spinlock_t sgreset_lock; /* lock for sgreset */
+       struct scsi_cmnd *sgreset_sc;
        struct dentry *fnic_stats_debugfs_host;
        struct dentry *fnic_stats_debugfs_file;
        struct dentry *fnic_reset_debugfs_file;
index f4c8769..5895ead 100644 (file)
@@ -52,6 +52,8 @@ struct fnic_io_req {
        unsigned long start_time; /* in jiffies */
        struct completion *abts_done; /* completion for abts */
        struct completion *dr_done; /* completion for device reset */
+       unsigned int tag;
+       struct scsi_cmnd *sc; /* midlayer's cmd pointer */
 };
 
 enum fnic_port_speeds {
index 984bc5f..f27f931 100644 (file)
@@ -754,6 +754,8 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        for (i = 0; i < FNIC_IO_LOCKS; i++)
                spin_lock_init(&fnic->io_req_lock[i]);
 
+       spin_lock_init(&fnic->sgreset_lock);
+
        err = -ENOMEM;
        fnic->io_req_pool = mempool_create_slab_pool(2, fnic_io_req_cache);
        if (!fnic->io_req_pool)
index 9761b2c..416d819 100644 (file)
@@ -1047,9 +1047,9 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic,
 {
        u8 type;
        u8 hdr_status;
-       struct fcpio_tag tag;
+       struct fcpio_tag ftag;
        u32 id;
-       struct scsi_cmnd *sc;
+       struct scsi_cmnd *sc = NULL;
        struct fnic_io_req *io_req;
        struct fnic_stats *fnic_stats = &fnic->fnic_stats;
        struct abort_stats *abts_stats = &fnic->fnic_stats.abts_stats;
@@ -1058,27 +1058,43 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic,
        unsigned long flags;
        spinlock_t *io_lock;
        unsigned long start_time;
+       unsigned int tag;
 
-       fcpio_header_dec(&desc->hdr, &type, &hdr_status, &tag);
-       fcpio_tag_id_dec(&tag, &id);
+       fcpio_header_dec(&desc->hdr, &type, &hdr_status, &ftag);
+       fcpio_tag_id_dec(&ftag, &id);
 
-       if ((id & FNIC_TAG_MASK) >= fnic->fnic_max_tag_id) {
+       tag = id & FNIC_TAG_MASK;
+       if (tag == fnic->fnic_max_tag_id) {
+               if (!(id & FNIC_TAG_DEV_RST)) {
+                       shost_printk(KERN_ERR, fnic->lport->host,
+                                               "Tag out of range id 0x%x hdr status = %s\n",
+                                               id, fnic_fcpio_status_to_str(hdr_status));
+                       return;
+               }
+       } else if (tag > fnic->fnic_max_tag_id) {
                shost_printk(KERN_ERR, fnic->lport->host,
-               "Tag out of range tag %x hdr status = %s\n",
-               id, fnic_fcpio_status_to_str(hdr_status));
+                                       "Tag out of range tag 0x%x hdr status = %s\n",
+                                       tag, fnic_fcpio_status_to_str(hdr_status));
                return;
        }
 
-       sc = scsi_host_find_tag(fnic->lport->host, id & FNIC_TAG_MASK);
+       if ((tag == fnic->fnic_max_tag_id) && (id & FNIC_TAG_DEV_RST)) {
+               sc = fnic->sgreset_sc;
+               io_lock = &fnic->sgreset_lock;
+       } else {
+               sc = scsi_host_find_tag(fnic->lport->host, id & FNIC_TAG_MASK);
+               io_lock = fnic_io_lock_hash(fnic, sc);
+       }
+
        WARN_ON_ONCE(!sc);
        if (!sc) {
                atomic64_inc(&fnic_stats->io_stats.sc_null);
                shost_printk(KERN_ERR, fnic->lport->host,
                          "itmf_cmpl sc is null - hdr status = %s tag = 0x%x\n",
-                         fnic_fcpio_status_to_str(hdr_status), id);
+                         fnic_fcpio_status_to_str(hdr_status), tag);
                return;
        }
-       io_lock = fnic_io_lock_hash(fnic, sc);
+
        spin_lock_irqsave(io_lock, flags);
        io_req = fnic_priv(sc)->io_req;
        WARN_ON_ONCE(!io_req);
@@ -1089,7 +1105,7 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic,
                shost_printk(KERN_ERR, fnic->lport->host,
                          "itmf_cmpl io_req is null - "
                          "hdr status = %s tag = 0x%x sc 0x%p\n",
-                         fnic_fcpio_status_to_str(hdr_status), id, sc);
+                         fnic_fcpio_status_to_str(hdr_status), tag, sc);
                return;
        }
        start_time = io_req->start_time;
@@ -1938,6 +1954,10 @@ static inline int fnic_queue_dr_io_req(struct fnic *fnic,
        struct scsi_lun fc_lun;
        int ret = 0;
        unsigned long intr_flags;
+       unsigned int tag = scsi_cmd_to_rq(sc)->tag;
+
+       if (tag == SCSI_NO_TAG)
+               tag = io_req->tag;
 
        spin_lock_irqsave(host->host_lock, intr_flags);
        if (unlikely(fnic_chk_state_flags_locked(fnic,
@@ -1964,7 +1984,8 @@ static inline int fnic_queue_dr_io_req(struct fnic *fnic,
        /* fill in the lun info */
        int_to_scsilun(sc->device->lun, &fc_lun);
 
-       fnic_queue_wq_copy_desc_itmf(wq, scsi_cmd_to_rq(sc)->tag | FNIC_TAG_DEV_RST,
+       tag |= FNIC_TAG_DEV_RST;
+       fnic_queue_wq_copy_desc_itmf(wq, tag,
                                     0, FCPIO_ITMF_LUN_RESET, SCSI_NO_TAG,
                                     fc_lun.scsi_lun, io_req->port_id,
                                     fnic->config.ra_tov, fnic->config.ed_tov);
@@ -2146,8 +2167,7 @@ static int fnic_clean_pending_aborts(struct fnic *fnic,
                .ret = SUCCESS,
        };
 
-       if (new_sc)
-               iter_data.lr_sc = lr_sc;
+       iter_data.lr_sc = lr_sc;
 
        scsi_host_busy_iter(fnic->lport->host,
                            fnic_pending_aborts_iter, &iter_data);
@@ -2230,8 +2250,14 @@ int fnic_device_reset(struct scsi_cmnd *sc)
                mutex_lock(&fnic->sgreset_mutex);
                tag = fnic->fnic_max_tag_id;
                new_sc = 1;
-       }
-       io_lock = fnic_io_lock_hash(fnic, sc);
+               fnic->sgreset_sc = sc;
+               io_lock = &fnic->sgreset_lock;
+               FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host,
+                       "fcid: 0x%x lun: 0x%llx flags: 0x%x tag: 0x%x Issuing sgreset\n",
+                       rport->port_id, sc->device->lun, fnic_priv(sc)->flags, tag);
+       } else
+               io_lock = fnic_io_lock_hash(fnic, sc);
+
        spin_lock_irqsave(io_lock, flags);
        io_req = fnic_priv(sc)->io_req;
 
@@ -2247,6 +2273,8 @@ int fnic_device_reset(struct scsi_cmnd *sc)
                }
                memset(io_req, 0, sizeof(*io_req));
                io_req->port_id = rport->port_id;
+               io_req->tag = tag;
+               io_req->sc = sc;
                fnic_priv(sc)->io_req = io_req;
        }
        io_req->dr_done = &tm_done;
@@ -2400,8 +2428,10 @@ fnic_device_reset_end:
                  (u64)sc->cmnd[4] << 8 | sc->cmnd[5]),
                  fnic_flags_and_state(sc));
 
-       if (new_sc)
+       if (new_sc) {
+               fnic->sgreset_sc = NULL;
                mutex_unlock(&fnic->sgreset_mutex);
+       }
 
        FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host,
                      "Returning from device reset %s\n",
index 9ab8555..8e14cea 100644 (file)
@@ -724,6 +724,10 @@ iscsi_sw_tcp_conn_bind(struct iscsi_cls_session *cls_session,
                return -EEXIST;
        }
 
+       err = -EINVAL;
+       if (!sk_is_tcp(sock->sk))
+               goto free_socket;
+
        err = iscsi_conn_bind(cls_session, cls_conn, is_leading);
        if (err)
                goto free_socket;
index d0911bc..89367c4 100644 (file)
@@ -613,6 +613,17 @@ void scsi_cdl_check(struct scsi_device *sdev)
        bool cdl_supported;
        unsigned char *buf;
 
+       /*
+        * Support for CDL was defined in SPC-5. Ignore devices reporting an
+        * lower SPC version. This also avoids problems with old drives choking
+        * on MAINTENANCE_IN / MI_REPORT_SUPPORTED_OPERATION_CODES with a
+        * service action specified, as done in scsi_cdl_check_cmd().
+        */
+       if (sdev->scsi_level < SCSI_SPC_5) {
+               sdev->cdl_supported = 0;
+               return;
+       }
+
        buf = kmalloc(SCSI_CDL_CHECK_BUF_LEN, GFP_KERNEL);
        if (!buf) {
                sdev->cdl_supported = 0;
index 52014b2..44680f6 100644 (file)
@@ -822,7 +822,7 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result,
         * device is attached at LUN 0 (SCSI_SCAN_TARGET_PRESENT) so
         * non-zero LUNs can be scanned.
         */
-       sdev->scsi_level = inq_result[2] & 0x07;
+       sdev->scsi_level = inq_result[2] & 0x0f;
        if (sdev->scsi_level >= 2 ||
            (sdev->scsi_level == 1 && (inq_result[3] & 0x0f) == 1))
                sdev->scsi_level++;
@@ -1619,12 +1619,25 @@ int scsi_add_device(struct Scsi_Host *host, uint channel,
 }
 EXPORT_SYMBOL(scsi_add_device);
 
-void scsi_rescan_device(struct scsi_device *sdev)
+int scsi_rescan_device(struct scsi_device *sdev)
 {
        struct device *dev = &sdev->sdev_gendev;
+       int ret = 0;
 
        device_lock(dev);
 
+       /*
+        * Bail out if the device or its queue are not running. Otherwise,
+        * the rescan may block waiting for commands to be executed, with us
+        * holding the device lock. This can result in a potential deadlock
+        * in the power management core code when system resume is on-going.
+        */
+       if (sdev->sdev_state != SDEV_RUNNING ||
+           blk_queue_pm_only(sdev->request_queue)) {
+               ret = -EWOULDBLOCK;
+               goto unlock;
+       }
+
        scsi_attach_vpd(sdev);
        scsi_cdl_check(sdev);
 
@@ -1638,7 +1651,11 @@ void scsi_rescan_device(struct scsi_device *sdev)
                        drv->rescan(dev);
                module_put(dev->driver->owner);
        }
+
+unlock:
        device_unlock(dev);
+
+       return ret;
 }
 EXPORT_SYMBOL(scsi_rescan_device);
 
index c92a317..83b6a3f 100644 (file)
@@ -201,18 +201,32 @@ cache_type_store(struct device *dev, struct device_attribute *attr,
 }
 
 static ssize_t
-manage_start_stop_show(struct device *dev, struct device_attribute *attr,
-                      char *buf)
+manage_start_stop_show(struct device *dev,
+                      struct device_attribute *attr, char *buf)
 {
        struct scsi_disk *sdkp = to_scsi_disk(dev);
        struct scsi_device *sdp = sdkp->device;
 
-       return sprintf(buf, "%u\n", sdp->manage_start_stop);
+       return sysfs_emit(buf, "%u\n",
+                         sdp->manage_system_start_stop &&
+                         sdp->manage_runtime_start_stop);
 }
+static DEVICE_ATTR_RO(manage_start_stop);
 
 static ssize_t
-manage_start_stop_store(struct device *dev, struct device_attribute *attr,
-                       const char *buf, size_t count)
+manage_system_start_stop_show(struct device *dev,
+                             struct device_attribute *attr, char *buf)
+{
+       struct scsi_disk *sdkp = to_scsi_disk(dev);
+       struct scsi_device *sdp = sdkp->device;
+
+       return sysfs_emit(buf, "%u\n", sdp->manage_system_start_stop);
+}
+
+static ssize_t
+manage_system_start_stop_store(struct device *dev,
+                              struct device_attribute *attr,
+                              const char *buf, size_t count)
 {
        struct scsi_disk *sdkp = to_scsi_disk(dev);
        struct scsi_device *sdp = sdkp->device;
@@ -224,11 +238,42 @@ manage_start_stop_store(struct device *dev, struct device_attribute *attr,
        if (kstrtobool(buf, &v))
                return -EINVAL;
 
-       sdp->manage_start_stop = v;
+       sdp->manage_system_start_stop = v;
 
        return count;
 }
-static DEVICE_ATTR_RW(manage_start_stop);
+static DEVICE_ATTR_RW(manage_system_start_stop);
+
+static ssize_t
+manage_runtime_start_stop_show(struct device *dev,
+                              struct device_attribute *attr, char *buf)
+{
+       struct scsi_disk *sdkp = to_scsi_disk(dev);
+       struct scsi_device *sdp = sdkp->device;
+
+       return sysfs_emit(buf, "%u\n", sdp->manage_runtime_start_stop);
+}
+
+static ssize_t
+manage_runtime_start_stop_store(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf, size_t count)
+{
+       struct scsi_disk *sdkp = to_scsi_disk(dev);
+       struct scsi_device *sdp = sdkp->device;
+       bool v;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EACCES;
+
+       if (kstrtobool(buf, &v))
+               return -EINVAL;
+
+       sdp->manage_runtime_start_stop = v;
+
+       return count;
+}
+static DEVICE_ATTR_RW(manage_runtime_start_stop);
 
 static ssize_t
 allow_restart_show(struct device *dev, struct device_attribute *attr, char *buf)
@@ -560,6 +605,8 @@ static struct attribute *sd_disk_attrs[] = {
        &dev_attr_FUA.attr,
        &dev_attr_allow_restart.attr,
        &dev_attr_manage_start_stop.attr,
+       &dev_attr_manage_system_start_stop.attr,
+       &dev_attr_manage_runtime_start_stop.attr,
        &dev_attr_protection_type.attr,
        &dev_attr_protection_mode.attr,
        &dev_attr_app_tag_own.attr,
@@ -3694,7 +3741,8 @@ static int sd_remove(struct device *dev)
 
        device_del(&sdkp->disk_dev);
        del_gendisk(sdkp->disk);
-       sd_shutdown(dev);
+       if (!sdkp->suspended)
+               sd_shutdown(dev);
 
        put_disk(sdkp->disk);
        return 0;
@@ -3771,13 +3819,20 @@ static void sd_shutdown(struct device *dev)
                sd_sync_cache(sdkp, NULL);
        }
 
-       if (system_state != SYSTEM_RESTART && sdkp->device->manage_start_stop) {
+       if (system_state != SYSTEM_RESTART &&
+           sdkp->device->manage_system_start_stop) {
                sd_printk(KERN_NOTICE, sdkp, "Stopping disk\n");
                sd_start_stop_device(sdkp, 0);
        }
 }
 
-static int sd_suspend_common(struct device *dev, bool ignore_stop_errors)
+static inline bool sd_do_start_stop(struct scsi_device *sdev, bool runtime)
+{
+       return (sdev->manage_system_start_stop && !runtime) ||
+               (sdev->manage_runtime_start_stop && runtime);
+}
+
+static int sd_suspend_common(struct device *dev, bool runtime)
 {
        struct scsi_disk *sdkp = dev_get_drvdata(dev);
        struct scsi_sense_hdr sshdr;
@@ -3809,15 +3864,18 @@ static int sd_suspend_common(struct device *dev, bool ignore_stop_errors)
                }
        }
 
-       if (sdkp->device->manage_start_stop) {
+       if (sd_do_start_stop(sdkp->device, runtime)) {
                if (!sdkp->device->silence_suspend)
                        sd_printk(KERN_NOTICE, sdkp, "Stopping disk\n");
                /* an error is not worth aborting a system sleep */
                ret = sd_start_stop_device(sdkp, 0);
-               if (ignore_stop_errors)
+               if (!runtime)
                        ret = 0;
        }
 
+       if (!ret)
+               sdkp->suspended = true;
+
        return ret;
 }
 
@@ -3826,15 +3884,15 @@ static int sd_suspend_system(struct device *dev)
        if (pm_runtime_suspended(dev))
                return 0;
 
-       return sd_suspend_common(dev, true);
+       return sd_suspend_common(dev, false);
 }
 
 static int sd_suspend_runtime(struct device *dev)
 {
-       return sd_suspend_common(dev, false);
+       return sd_suspend_common(dev, true);
 }
 
-static int sd_resume(struct device *dev)
+static int sd_resume(struct device *dev, bool runtime)
 {
        struct scsi_disk *sdkp = dev_get_drvdata(dev);
        int ret = 0;
@@ -3842,16 +3900,21 @@ static int sd_resume(struct device *dev)
        if (!sdkp)      /* E.g.: runtime resume at the start of sd_probe() */
                return 0;
 
-       if (!sdkp->device->manage_start_stop)
+       if (!sd_do_start_stop(sdkp->device, runtime)) {
+               sdkp->suspended = false;
                return 0;
+       }
 
        if (!sdkp->device->no_start_on_resume) {
                sd_printk(KERN_NOTICE, sdkp, "Starting disk\n");
                ret = sd_start_stop_device(sdkp, 1);
        }
 
-       if (!ret)
+       if (!ret) {
                opal_unlock_from_suspend(sdkp->opal_dev);
+               sdkp->suspended = false;
+       }
+
        return ret;
 }
 
@@ -3860,7 +3923,7 @@ static int sd_resume_system(struct device *dev)
        if (pm_runtime_suspended(dev))
                return 0;
 
-       return sd_resume(dev);
+       return sd_resume(dev, false);
 }
 
 static int sd_resume_runtime(struct device *dev)
@@ -3887,7 +3950,7 @@ static int sd_resume_runtime(struct device *dev)
                                  "Failed to clear sense data\n");
        }
 
-       return sd_resume(dev);
+       return sd_resume(dev, true);
 }
 
 static const struct dev_pm_ops sd_pm_ops = {
index 5eea762..409dda5 100644 (file)
@@ -131,6 +131,7 @@ struct scsi_disk {
        u8              provisioning_mode;
        u8              zeroing_mode;
        u8              nr_actuators;           /* Number of actuators */
+       bool            suspended;      /* Disk is suspended (stopped) */
        unsigned        ATO : 1;        /* state of disk ATO bit */
        unsigned        cache_override : 1; /* temp override of WCE,RCD */
        unsigned        WCE : 1;        /* state of disk WCE bit */
index 1dcd243..ec87d9d 100644 (file)
@@ -100,6 +100,7 @@ static void __init imx8mm_soc_uid(void)
 {
        void __iomem *ocotp_base;
        struct device_node *np;
+       struct clk *clk;
        u32 offset = of_machine_is_compatible("fsl,imx8mp") ?
                     IMX8MP_OCOTP_UID_OFFSET : 0;
 
@@ -109,11 +110,20 @@ static void __init imx8mm_soc_uid(void)
 
        ocotp_base = of_iomap(np, 0);
        WARN_ON(!ocotp_base);
+       clk = of_clk_get_by_name(np, NULL);
+       if (IS_ERR(clk)) {
+               WARN_ON(IS_ERR(clk));
+               return;
+       }
+
+       clk_prepare_enable(clk);
 
        soc_uid = readl_relaxed(ocotp_base + OCOTP_UID_HIGH + offset);
        soc_uid <<= 32;
        soc_uid |= readl_relaxed(ocotp_base + OCOTP_UID_LOW + offset);
 
+       clk_disable_unprepare(clk);
+       clk_put(clk);
        iounmap(ocotp_base);
        of_node_put(np);
 }
index 314e13b..3683449 100644 (file)
@@ -20,6 +20,7 @@ config LOONGSON2_GUTS
 config LOONGSON2_PM
        bool "Loongson-2 SoC Power Management Controller Driver"
        depends on LOONGARCH && OF
+       depends on INPUT=y
        help
          The Loongson-2's power management controller was ACPI, supports ACPI
          S2Idle (Suspend To Idle), ACPI S3 (Suspend To RAM), ACPI S4 (Suspend To
index bace4bc..9a46977 100644 (file)
@@ -70,7 +70,7 @@ static const struct loongson2_soc_die_attr *loongson2_soc_die_match(
                if (matches->svr == (svr & matches->mask))
                        return matches;
                matches++;
-       };
+       }
 
        return NULL;
 }
@@ -94,7 +94,6 @@ static int loongson2_guts_probe(struct platform_device *pdev)
 {
        struct device_node *root, *np = pdev->dev.of_node;
        struct device *dev = &pdev->dev;
-       struct resource *res;
        const struct loongson2_soc_die_attr *soc_die;
        const char *machine;
        u32 svr;
@@ -106,8 +105,7 @@ static int loongson2_guts_probe(struct platform_device *pdev)
 
        guts->little_endian = of_property_read_bool(np, "little-endian");
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       guts->regs = ioremap(res->start, res->end - res->start + 1);
+       guts->regs = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(guts->regs))
                return PTR_ERR(guts->regs);
 
index 796add6..b8e5e1e 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/input.h>
 #include <linux/suspend.h>
 #include <linux/interrupt.h>
+#include <linux/of_platform.h>
 #include <linux/pm_wakeirq.h>
 #include <linux/platform_device.h>
 #include <asm/bootinfo.h>
@@ -192,12 +193,16 @@ static int loongson2_pm_probe(struct platform_device *pdev)
        if (loongson_sysconf.suspend_addr)
                suspend_set_ops(&loongson2_suspend_ops);
 
+       /* Populate children */
+       retval = devm_of_platform_populate(dev);
+       if (retval)
+               dev_err(dev, "Error populating children, reboot and poweroff might not work properly\n");
+
        return 0;
 }
 
 static const struct of_device_id loongson2_pm_match[] = {
        { .compatible = "loongson,ls2k0500-pmc", },
-       { .compatible = "loongson,ls2k1000-pmc", },
        {},
 };
 
index 453a9b3..d239fc5 100644 (file)
@@ -256,7 +256,6 @@ static int cs42l43_spi_probe(struct platform_device *pdev)
 
        ret = devm_spi_register_controller(priv->dev, priv->ctlr);
        if (ret) {
-               pm_runtime_disable(priv->dev);
                dev_err(priv->dev, "Failed to register SPI controller: %d\n", ret);
        }
 
index fd2fac2..3aff5a1 100644 (file)
@@ -194,7 +194,7 @@ static ssize_t gxp_spi_write(struct gxp_spi_chip *chip, const struct spi_mem_op
                return ret;
        }
 
-       return write_len;
+       return 0;
 }
 
 static int do_gxp_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op)
index a8a74c7..498e35c 100644 (file)
@@ -662,7 +662,7 @@ static int mx51_ecspi_prepare_transfer(struct spi_imx_data *spi_imx,
                if (spi_imx->count >= 512)
                        ctrl |= 0xFFF << MX51_ECSPI_CTRL_BL_OFFSET;
                else
-                       ctrl |= (spi_imx->count*8 - 1)
+                       ctrl |= (spi_imx->count * spi_imx->bits_per_word - 1)
                                << MX51_ECSPI_CTRL_BL_OFFSET;
        }
 
index a7381e7..57d767a 100644 (file)
@@ -72,6 +72,7 @@ static const struct pci_device_id intel_spi_pci_ids[] = {
        { PCI_VDEVICE(INTEL, 0x4da4), (unsigned long)&bxt_info },
        { PCI_VDEVICE(INTEL, 0x51a4), (unsigned long)&cnl_info },
        { PCI_VDEVICE(INTEL, 0x54a4), (unsigned long)&cnl_info },
+       { PCI_VDEVICE(INTEL, 0x5794), (unsigned long)&cnl_info },
        { PCI_VDEVICE(INTEL, 0x7a24), (unsigned long)&cnl_info },
        { PCI_VDEVICE(INTEL, 0x7aa4), (unsigned long)&cnl_info },
        { PCI_VDEVICE(INTEL, 0x7e23), (unsigned long)&cnl_info },
index 45a4acc..c964f41 100644 (file)
@@ -1084,6 +1084,13 @@ static int nxp_fspi_default_setup(struct nxp_fspi *f)
        fspi_writel(f, FSPI_AHBCR_PREF_EN | FSPI_AHBCR_RDADDROPT,
                 base + FSPI_AHBCR);
 
+       /* Reset the FLSHxCR1 registers. */
+       reg = FSPI_FLSHXCR1_TCSH(0x3) | FSPI_FLSHXCR1_TCSS(0x3);
+       fspi_writel(f, reg, base + FSPI_FLSHA1CR1);
+       fspi_writel(f, reg, base + FSPI_FLSHA2CR1);
+       fspi_writel(f, reg, base + FSPI_FLSHB1CR1);
+       fspi_writel(f, reg, base + FSPI_FLSHB2CR1);
+
        /* AHB Read - Set lut sequence ID for all CS. */
        fspi_writel(f, SEQID_LUT, base + FSPI_FLSHA1CR2);
        fspi_writel(f, SEQID_LUT, base + FSPI_FLSHA2CR2);
index b6d66ca..ef665f4 100644 (file)
@@ -277,6 +277,7 @@ struct stm32_spi_cfg {
  * @fifo_size: size of the embedded fifo in bytes
  * @cur_midi: master inter-data idleness in ns
  * @cur_speed: speed configured in Hz
+ * @cur_half_period: time of a half bit in us
  * @cur_bpw: number of bits in a single SPI data frame
  * @cur_fthlv: fifo threshold level (data frames in a single data packet)
  * @cur_comm: SPI communication mode
@@ -304,6 +305,7 @@ struct stm32_spi {
 
        unsigned int cur_midi;
        unsigned int cur_speed;
+       unsigned int cur_half_period;
        unsigned int cur_bpw;
        unsigned int cur_fthlv;
        unsigned int cur_comm;
@@ -468,6 +470,8 @@ static int stm32_spi_prepare_mbr(struct stm32_spi *spi, u32 speed_hz,
 
        spi->cur_speed = spi->clk_rate / (1 << mbrdiv);
 
+       spi->cur_half_period = DIV_ROUND_CLOSEST(USEC_PER_SEC, 2 * spi->cur_speed);
+
        return mbrdiv - 1;
 }
 
@@ -709,6 +713,10 @@ static void stm32h7_spi_disable(struct stm32_spi *spi)
                return;
        }
 
+       /* Add a delay to make sure that transmission is ended. */
+       if (spi->cur_half_period)
+               udelay(spi->cur_half_period);
+
        if (spi->cur_usedma && spi->dma_tx)
                dmaengine_terminate_async(spi->dma_tx);
        if (spi->cur_usedma && spi->dma_rx)
index 94d9a33..9a46b24 100644 (file)
@@ -1340,9 +1340,9 @@ static int zynqmp_qspi_probe(struct platform_device *pdev)
        return 0;
 
 clk_dis_all:
-       pm_runtime_put_sync(&pdev->dev);
-       pm_runtime_set_suspended(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
+       pm_runtime_put_noidle(&pdev->dev);
+       pm_runtime_set_suspended(&pdev->dev);
        clk_disable_unprepare(xqspi->refclk);
 clk_dis_pclk:
        clk_disable_unprepare(xqspi->pclk);
@@ -1366,11 +1366,15 @@ static void zynqmp_qspi_remove(struct platform_device *pdev)
 {
        struct zynqmp_qspi *xqspi = platform_get_drvdata(pdev);
 
+       pm_runtime_get_sync(&pdev->dev);
+
        zynqmp_gqspi_write(xqspi, GQSPI_EN_OFST, 0x0);
+
+       pm_runtime_disable(&pdev->dev);
+       pm_runtime_put_noidle(&pdev->dev);
+       pm_runtime_set_suspended(&pdev->dev);
        clk_disable_unprepare(xqspi->refclk);
        clk_disable_unprepare(xqspi->pclk);
-       pm_runtime_set_suspended(&pdev->dev);
-       pm_runtime_disable(&pdev->dev);
 }
 
 MODULE_DEVICE_TABLE(of, zynqmp_qspi_of_match);
index 5d89171..75c985d 100644 (file)
@@ -12,12 +12,12 @@ menuconfig INTEL_ATOMISP
 config VIDEO_ATOMISP
        tristate "Intel Atom Image Signal Processor Driver"
        depends on VIDEO_DEV && INTEL_ATOMISP
+       depends on IPU_BRIDGE
        depends on MEDIA_PCI_SUPPORT
        depends on PMIC_OPREGION
        depends on I2C
        select V4L2_FWNODE
        select IOSF_MBI
-       select IPU_BRIDGE
        select VIDEOBUF2_VMALLOC
        select VIDEO_V4L2_SUBDEV_API
        help
index e98b301..94171e6 100644 (file)
@@ -1455,17 +1455,18 @@ static int __maybe_unused vi_runtime_suspend(struct device *dev)
 }
 
 /*
- * Graph Management
+ * Find the entity matching a given fwnode in an v4l2_async_notifier list
  */
 static struct tegra_vi_graph_entity *
-tegra_vi_graph_find_entity(struct tegra_vi_channel *chan,
+tegra_vi_graph_find_entity(struct list_head *list,
                           const struct fwnode_handle *fwnode)
 {
        struct tegra_vi_graph_entity *entity;
        struct v4l2_async_connection *asd;
 
-       list_for_each_entry(asd, &chan->notifier.done_list, asc_entry) {
+       list_for_each_entry(asd, list, asc_entry) {
                entity = to_tegra_vi_graph_entity(asd);
+
                if (entity->asd.match.fwnode == fwnode)
                        return entity;
        }
@@ -1532,7 +1533,8 @@ static int tegra_vi_graph_build(struct tegra_vi_channel *chan,
                }
 
                /* find the remote entity from notifier list */
-               ent = tegra_vi_graph_find_entity(chan, link.remote_node);
+               ent = tegra_vi_graph_find_entity(&chan->notifier.done_list,
+                                                link.remote_node);
                if (!ent) {
                        dev_err(vi->dev, "no entity found for %pOF\n",
                                to_of_node(link.remote_node));
@@ -1664,7 +1666,8 @@ static int tegra_vi_graph_notify_bound(struct v4l2_async_notifier *notifier,
         * Locate the entity corresponding to the bound subdev and store the
         * subdev pointer.
         */
-       entity = tegra_vi_graph_find_entity(chan, subdev->fwnode);
+       entity = tegra_vi_graph_find_entity(&chan->notifier.waiting_list,
+                                           subdev->fwnode);
        if (!entity) {
                dev_err(vi->dev, "no entity for subdev %s\n", subdev->name);
                return -EINVAL;
@@ -1713,7 +1716,8 @@ static int tegra_vi_graph_parse_one(struct tegra_vi_channel *chan,
 
                /* skip entities that are already processed */
                if (device_match_fwnode(vi->dev, remote) ||
-                   tegra_vi_graph_find_entity(chan, remote)) {
+                   tegra_vi_graph_find_entity(&chan->notifier.waiting_list,
+                                              remote)) {
                        fwnode_handle_put(remote);
                        continue;
                }
index b7ac60f..b6523d4 100644 (file)
@@ -843,7 +843,6 @@ sector_t target_to_linux_sector(struct se_device *dev, sector_t lb)
 EXPORT_SYMBOL(target_to_linux_sector);
 
 struct devices_idr_iter {
-       struct config_item *prev_item;
        int (*fn)(struct se_device *dev, void *data);
        void *data;
 };
@@ -853,11 +852,9 @@ static int target_devices_idr_iter(int id, void *p, void *data)
 {
        struct devices_idr_iter *iter = data;
        struct se_device *dev = p;
+       struct config_item *item;
        int ret;
 
-       config_item_put(iter->prev_item);
-       iter->prev_item = NULL;
-
        /*
         * We add the device early to the idr, so it can be used
         * by backend modules during configuration. We do not want
@@ -867,12 +864,13 @@ static int target_devices_idr_iter(int id, void *p, void *data)
        if (!target_dev_configured(dev))
                return 0;
 
-       iter->prev_item = config_item_get_unless_zero(&dev->dev_group.cg_item);
-       if (!iter->prev_item)
+       item = config_item_get_unless_zero(&dev->dev_group.cg_item);
+       if (!item)
                return 0;
        mutex_unlock(&device_mutex);
 
        ret = iter->fn(dev, iter->data);
+       config_item_put(item);
 
        mutex_lock(&device_mutex);
        return ret;
@@ -895,7 +893,6 @@ int target_for_each_device(int (*fn)(struct se_device *dev, void *data),
        mutex_lock(&device_mutex);
        ret = idr_for_each(&devices_idr, target_devices_idr_iter, &iter);
        mutex_unlock(&device_mutex);
-       config_item_put(iter.prev_item);
        return ret;
 }
 
index 72685ee..6bb5cae 100644 (file)
@@ -238,8 +238,6 @@ int optee_notif_send(struct optee *optee, u_int key);
 u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params,
                        struct tee_param *param);
 
-int optee_supp_read(struct tee_context *ctx, void __user *buf, size_t len);
-int optee_supp_write(struct tee_context *ctx, void __user *buf, size_t len);
 void optee_supp_init(struct optee_supp *supp);
 void optee_supp_uninit(struct optee_supp *supp);
 void optee_supp_release(struct optee_supp *supp);
index 409cadc..754e11d 100644 (file)
@@ -47,8 +47,6 @@ struct tee_device {
        struct tee_shm_pool *pool;
 };
 
-int tee_shm_init(void);
-
 int tee_shm_get_fd(struct tee_shm *shm);
 
 bool tee_device_get(struct tee_device *teedev);
index 6c20c9f..4e6a97d 100644 (file)
@@ -185,9 +185,6 @@ trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
        if (sscanf(attr->attr.name, "trip_point_%d_hyst", &trip_id) != 1)
                return -EINVAL;
 
-       if (kstrtoint(buf, 10, &trip.hysteresis))
-               return -EINVAL;
-
        mutex_lock(&tz->lock);
 
        if (!device_is_registered(dev)) {
@@ -198,7 +195,11 @@ trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
        ret = __thermal_zone_get_trip(tz, trip_id, &trip);
        if (ret)
                goto unlock;
-       
+
+       ret = kstrtoint(buf, 10, &trip.hysteresis);
+       if (ret)
+               goto unlock;
+
        ret = thermal_zone_set_trip(tz, trip_id, &trip);
 unlock:
        mutex_unlock(&tz->lock);
index b3550ff..1f3aba6 100644 (file)
@@ -3097,10 +3097,8 @@ static void gsm_cleanup_mux(struct gsm_mux *gsm, bool disc)
                gsm->has_devices = false;
        }
        for (i = NUM_DLCI - 1; i >= 0; i--)
-               if (gsm->dlci[i]) {
+               if (gsm->dlci[i])
                        gsm_dlci_release(gsm->dlci[i]);
-                       gsm->dlci[i] = NULL;
-               }
        mutex_unlock(&gsm->mutex);
        /* Now wipe the queues */
        tty_ldisc_flush(gsm->tty);
index fb891b6..1416273 100644 (file)
@@ -1936,7 +1936,10 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
                skip_rx = true;
 
        if (status & (UART_LSR_DR | UART_LSR_BI) && !skip_rx) {
-               if (irqd_is_wakeup_set(irq_get_irq_data(port->irq)))
+               struct irq_data *d;
+
+               d = irq_get_irq_data(port->irq);
+               if (d && irqd_is_wakeup_set(d))
                        pm_wakeup_event(tport->tty->dev, 0);
                if (!up->dma || handle_rx_dma(up, iir))
                        status = serial8250_rx_chars(up, status);
index e449063..9d2738e 100644 (file)
@@ -233,7 +233,8 @@ int parent_create_sysfs_files(struct mdev_parent *parent)
 out_err:
        while (--i >= 0)
                mdev_type_remove(parent->types[i]);
-       return 0;
+       kset_unregister(parent->mdev_types_kset);
+       return ret;
 }
 
 static ssize_t remove_store(struct device *dev, struct device_attribute *attr,
index 407b3fd..6eceef7 100644 (file)
@@ -3,7 +3,7 @@
 
 config PDS_VFIO_PCI
        tristate "VFIO support for PDS PCI devices"
-       depends on PDS_CORE
+       depends on PDS_CORE && PCI_IOV
        select VFIO_PCI_CORE
        help
          This provides generic PCI support for PDS devices using the VFIO
index b46174f..649b18e 100644 (file)
@@ -162,7 +162,7 @@ static int pds_vfio_init_device(struct vfio_device *vdev)
        pci_id = PCI_DEVID(pdev->bus->number, pdev->devfn);
        dev_dbg(&pdev->dev,
                "%s: PF %#04x VF %#04x vf_id %d domain %d pds_vfio %p\n",
-               __func__, pci_dev_id(pdev->physfn), pci_id, vf_id,
+               __func__, pci_dev_id(pci_physfn(pdev)), pci_id, vf_id,
                pci_domain_nr(pdev->bus), pds_vfio);
 
        return 0;
index 955d938..7b8fd97 100644 (file)
@@ -123,8 +123,18 @@ static inline ssize_t vringh_iov_xfer(struct vringh *vrh,
                done += partlen;
                len -= partlen;
                ptr += partlen;
+               iov->consumed += partlen;
+               iov->iov[iov->i].iov_len -= partlen;
+               iov->iov[iov->i].iov_base += partlen;
 
-               vringh_kiov_advance(iov, partlen);
+               if (!iov->iov[iov->i].iov_len) {
+                       /* Fix up old iov element then increment. */
+                       iov->iov[iov->i].iov_len = iov->consumed;
+                       iov->iov[iov->i].iov_base -= iov->consumed;
+
+                       iov->consumed = 0;
+                       iov->i++;
+               }
        }
        return done;
 }
index 1b5a319..30577b1 100644 (file)
@@ -73,6 +73,7 @@ config DUMMY_CONSOLE_ROWS
 config FRAMEBUFFER_CONSOLE
        bool "Framebuffer Console support"
        depends on FB_CORE && !UML
+       default DRM_FBDEV_EMULATION
        select VT_HW_CONSOLE_BINDING
        select CRC32
        select FONT_SUPPORT
index eac0ba3..c29754b 100644 (file)
@@ -1762,7 +1762,7 @@ config FB_COBALT
 
 config FB_SH7760
        bool "SH7760/SH7763/SH7720/SH7721 LCDC support"
-       depends on FB && (CPU_SUBTYPE_SH7760 || CPU_SUBTYPE_SH7763 \
+       depends on FB=y && (CPU_SUBTYPE_SH7760 || CPU_SUBTYPE_SH7763 \
                || CPU_SUBTYPE_SH7720 || CPU_SUBTYPE_SH7721)
        select FB_IOMEM_HELPERS
        help
index baf7e85..5ac1b06 100644 (file)
@@ -28,7 +28,7 @@ config FIRMWARE_EDID
 config FB_DEVICE
        bool "Provide legacy /dev/fb* device"
        depends on FB_CORE
-       default y
+       default FB
        help
          Say Y here if you want the legacy /dev/fb* device file and
          interfaces within sysfs anc procfs. It is only required if you
index 3bdd5b5..1b2136f 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/slab.h>
 #include <linux/irqnr.h>
 #include <linux/pci.h>
+#include <linux/rcupdate.h>
 #include <linux/spinlock.h>
 #include <linux/cpuhotplug.h>
 #include <linux/atomic.h>
@@ -96,6 +97,7 @@ enum xen_irq_type {
 struct irq_info {
        struct list_head list;
        struct list_head eoi_list;
+       struct rcu_work rwork;
        short refcnt;
        u8 spurious_cnt;
        u8 is_accounted;
@@ -147,22 +149,12 @@ const struct evtchn_ops *evtchn_ops;
 static DEFINE_MUTEX(irq_mapping_update_lock);
 
 /*
- * Lock protecting event handling loop against removing event channels.
- * Adding of event channels is no issue as the associated IRQ becomes active
- * only after everything is setup (before request_[threaded_]irq() the handler
- * can't be entered for an event, as the event channel will be unmasked only
- * then).
- */
-static DEFINE_RWLOCK(evtchn_rwlock);
-
-/*
  * Lock hierarchy:
  *
  * irq_mapping_update_lock
- *   evtchn_rwlock
- *     IRQ-desc lock
- *       percpu eoi_list_lock
- *         irq_info->lock
+ *   IRQ-desc lock
+ *     percpu eoi_list_lock
+ *       irq_info->lock
  */
 
 static LIST_HEAD(xen_irq_list_head);
@@ -306,6 +298,22 @@ static void channels_on_cpu_inc(struct irq_info *info)
        info->is_accounted = 1;
 }
 
+static void delayed_free_irq(struct work_struct *work)
+{
+       struct irq_info *info = container_of(to_rcu_work(work), struct irq_info,
+                                            rwork);
+       unsigned int irq = info->irq;
+
+       /* Remove the info pointer only now, with no potential users left. */
+       set_info_for_irq(irq, NULL);
+
+       kfree(info);
+
+       /* Legacy IRQ descriptors are managed by the arch. */
+       if (irq >= nr_legacy_irqs())
+               irq_free_desc(irq);
+}
+
 /* Constructors for packed IRQ information. */
 static int xen_irq_info_common_setup(struct irq_info *info,
                                     unsigned irq,
@@ -668,33 +676,36 @@ static void xen_irq_lateeoi_worker(struct work_struct *work)
 
        eoi = container_of(to_delayed_work(work), struct lateeoi_work, delayed);
 
-       read_lock_irqsave(&evtchn_rwlock, flags);
+       rcu_read_lock();
 
        while (true) {
-               spin_lock(&eoi->eoi_list_lock);
+               spin_lock_irqsave(&eoi->eoi_list_lock, flags);
 
                info = list_first_entry_or_null(&eoi->eoi_list, struct irq_info,
                                                eoi_list);
 
-               if (info == NULL || now < info->eoi_time) {
-                       spin_unlock(&eoi->eoi_list_lock);
+               if (info == NULL)
+                       break;
+
+               if (now < info->eoi_time) {
+                       mod_delayed_work_on(info->eoi_cpu, system_wq,
+                                           &eoi->delayed,
+                                           info->eoi_time - now);
                        break;
                }
 
                list_del_init(&info->eoi_list);
 
-               spin_unlock(&eoi->eoi_list_lock);
+               spin_unlock_irqrestore(&eoi->eoi_list_lock, flags);
 
                info->eoi_time = 0;
 
                xen_irq_lateeoi_locked(info, false);
        }
 
-       if (info)
-               mod_delayed_work_on(info->eoi_cpu, system_wq,
-                                   &eoi->delayed, info->eoi_time - now);
+       spin_unlock_irqrestore(&eoi->eoi_list_lock, flags);
 
-       read_unlock_irqrestore(&evtchn_rwlock, flags);
+       rcu_read_unlock();
 }
 
 static void xen_cpu_init_eoi(unsigned int cpu)
@@ -709,16 +720,15 @@ static void xen_cpu_init_eoi(unsigned int cpu)
 void xen_irq_lateeoi(unsigned int irq, unsigned int eoi_flags)
 {
        struct irq_info *info;
-       unsigned long flags;
 
-       read_lock_irqsave(&evtchn_rwlock, flags);
+       rcu_read_lock();
 
        info = info_for_irq(irq);
 
        if (info)
                xen_irq_lateeoi_locked(info, eoi_flags & XEN_EOI_FLAG_SPURIOUS);
 
-       read_unlock_irqrestore(&evtchn_rwlock, flags);
+       rcu_read_unlock();
 }
 EXPORT_SYMBOL_GPL(xen_irq_lateeoi);
 
@@ -732,6 +742,7 @@ static void xen_irq_init(unsigned irq)
 
        info->type = IRQT_UNBOUND;
        info->refcnt = -1;
+       INIT_RCU_WORK(&info->rwork, delayed_free_irq);
 
        set_info_for_irq(irq, info);
        /*
@@ -789,31 +800,18 @@ static int __must_check xen_allocate_irq_gsi(unsigned gsi)
 static void xen_free_irq(unsigned irq)
 {
        struct irq_info *info = info_for_irq(irq);
-       unsigned long flags;
 
        if (WARN_ON(!info))
                return;
 
-       write_lock_irqsave(&evtchn_rwlock, flags);
-
        if (!list_empty(&info->eoi_list))
                lateeoi_list_del(info);
 
        list_del(&info->list);
 
-       set_info_for_irq(irq, NULL);
-
        WARN_ON(info->refcnt > 0);
 
-       write_unlock_irqrestore(&evtchn_rwlock, flags);
-
-       kfree(info);
-
-       /* Legacy IRQ descriptors are managed by the arch. */
-       if (irq < nr_legacy_irqs())
-               return;
-
-       irq_free_desc(irq);
+       queue_rcu_work(system_wq, &info->rwork);
 }
 
 /* Not called for lateeoi events. */
@@ -1704,14 +1702,21 @@ void handle_irq_for_port(evtchn_port_t port, struct evtchn_loop_ctrl *ctrl)
        generic_handle_irq(irq);
 }
 
-static int __xen_evtchn_do_upcall(void)
+int xen_evtchn_do_upcall(void)
 {
        struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu);
        int ret = vcpu_info->evtchn_upcall_pending ? IRQ_HANDLED : IRQ_NONE;
        int cpu = smp_processor_id();
        struct evtchn_loop_ctrl ctrl = { 0 };
 
-       read_lock(&evtchn_rwlock);
+       /*
+        * When closing an event channel the associated IRQ must not be freed
+        * until all cpus have left the event handling loop. This is ensured
+        * by taking the rcu_read_lock() while handling events, as freeing of
+        * the IRQ is handled via queue_rcu_work() _after_ closing the event
+        * channel.
+        */
+       rcu_read_lock();
 
        do {
                vcpu_info->evtchn_upcall_pending = 0;
@@ -1724,7 +1729,7 @@ static int __xen_evtchn_do_upcall(void)
 
        } while (vcpu_info->evtchn_upcall_pending);
 
-       read_unlock(&evtchn_rwlock);
+       rcu_read_unlock();
 
        /*
         * Increment irq_epoch only now to defer EOIs only for
@@ -1735,24 +1740,7 @@ static int __xen_evtchn_do_upcall(void)
 
        return ret;
 }
-
-void xen_evtchn_do_upcall(struct pt_regs *regs)
-{
-       struct pt_regs *old_regs = set_irq_regs(regs);
-
-       irq_enter();
-
-       __xen_evtchn_do_upcall();
-
-       irq_exit();
-       set_irq_regs(old_regs);
-}
-
-int xen_hvm_evtchn_do_upcall(void)
-{
-       return __xen_evtchn_do_upcall();
-}
-EXPORT_SYMBOL_GPL(xen_hvm_evtchn_do_upcall);
+EXPORT_SYMBOL_GPL(xen_evtchn_do_upcall);
 
 /* Rebind a new event channel to an existing irq. */
 void rebind_evtchn_irq(evtchn_port_t evtchn, int irq)
index fcc8191..544d3f9 100644 (file)
@@ -64,7 +64,7 @@ static uint64_t get_callback_via(struct pci_dev *pdev)
 
 static irqreturn_t do_hvm_evtchn_intr(int irq, void *dev_id)
 {
-       return xen_hvm_evtchn_do_upcall();
+       return xen_evtchn_do_upcall();
 }
 
 static int xen_allocate_irq(struct pci_dev *pdev)
index a4c2a6b..f8589ca 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -80,7 +80,7 @@ struct aio_ring {
 struct kioctx_table {
        struct rcu_head         rcu;
        unsigned                nr;
-       struct kioctx __rcu     *table[];
+       struct kioctx __rcu     *table[] __counted_by(nr);
 };
 
 struct kioctx_cpu {
index 43b2a28..206812c 100644 (file)
@@ -345,10 +345,9 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm)
        /* there's now no turning back... the old userspace image is dead,
         * defunct, deceased, etc.
         */
+       SET_PERSONALITY(exec_params.hdr);
        if (elf_check_fdpic(&exec_params.hdr))
-               set_personality(PER_LINUX_FDPIC);
-       else
-               set_personality(PER_LINUX);
+               current->personality |= PER_LINUX_FDPIC;
        if (elf_read_implies_exec(&exec_params.hdr, executable_stack))
                current->personality |= READ_IMPLIES_EXEC;
 
index a4cb4b6..da519c1 100644 (file)
@@ -682,18 +682,30 @@ noinline int btrfs_cow_block(struct btrfs_trans_handle *trans,
        u64 search_start;
        int ret;
 
-       if (test_bit(BTRFS_ROOT_DELETING, &root->state))
-               btrfs_err(fs_info,
-                       "COW'ing blocks on a fs root that's being dropped");
-
-       if (trans->transaction != fs_info->running_transaction)
-               WARN(1, KERN_CRIT "trans %llu running %llu\n",
-                      trans->transid,
-                      fs_info->running_transaction->transid);
+       if (unlikely(test_bit(BTRFS_ROOT_DELETING, &root->state))) {
+               btrfs_abort_transaction(trans, -EUCLEAN);
+               btrfs_crit(fs_info,
+                  "attempt to COW block %llu on root %llu that is being deleted",
+                          buf->start, btrfs_root_id(root));
+               return -EUCLEAN;
+       }
 
-       if (trans->transid != fs_info->generation)
-               WARN(1, KERN_CRIT "trans %llu running %llu\n",
-                      trans->transid, fs_info->generation);
+       /*
+        * COWing must happen through a running transaction, which always
+        * matches the current fs generation (it's a transaction with a state
+        * less than TRANS_STATE_UNBLOCKED). If it doesn't, then turn the fs
+        * into error state to prevent the commit of any transaction.
+        */
+       if (unlikely(trans->transaction != fs_info->running_transaction ||
+                    trans->transid != fs_info->generation)) {
+               btrfs_abort_transaction(trans, -EUCLEAN);
+               btrfs_crit(fs_info,
+"unexpected transaction when attempting to COW block %llu on root %llu, transaction %llu running transaction %llu fs generation %llu",
+                          buf->start, btrfs_root_id(root), trans->transid,
+                          fs_info->running_transaction->transid,
+                          fs_info->generation);
+               return -EUCLEAN;
+       }
 
        if (!should_cow_block(trans, root, buf)) {
                *cow_ret = buf;
@@ -805,8 +817,22 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
        int progress_passed = 0;
        struct btrfs_disk_key disk_key;
 
-       WARN_ON(trans->transaction != fs_info->running_transaction);
-       WARN_ON(trans->transid != fs_info->generation);
+       /*
+        * COWing must happen through a running transaction, which always
+        * matches the current fs generation (it's a transaction with a state
+        * less than TRANS_STATE_UNBLOCKED). If it doesn't, then turn the fs
+        * into error state to prevent the commit of any transaction.
+        */
+       if (unlikely(trans->transaction != fs_info->running_transaction ||
+                    trans->transid != fs_info->generation)) {
+               btrfs_abort_transaction(trans, -EUCLEAN);
+               btrfs_crit(fs_info,
+"unexpected transaction when attempting to reallocate parent %llu for root %llu, transaction %llu running transaction %llu fs generation %llu",
+                          parent->start, btrfs_root_id(root), trans->transid,
+                          fs_info->running_transaction->transid,
+                          fs_info->generation);
+               return -EUCLEAN;
+       }
 
        parent_nritems = btrfs_header_nritems(parent);
        blocksize = fs_info->nodesize;
index caf0bbd..90aaedc 100644 (file)
@@ -313,7 +313,7 @@ static struct btrfs_delayed_item *btrfs_alloc_delayed_item(u16 data_len,
 {
        struct btrfs_delayed_item *item;
 
-       item = kmalloc(sizeof(*item) + data_len, GFP_NOFS);
+       item = kmalloc(struct_size(item, data, data_len), GFP_NOFS);
        if (item) {
                item->data_len = data_len;
                item->type = type;
index dc1085b..1da2131 100644 (file)
@@ -95,7 +95,7 @@ struct btrfs_delayed_item {
        bool logged;
        /* The maximum leaf size is 64K, so u16 is more than enough. */
        u16 data_len;
-       char data[];
+       char data[] __counted_by(data_len);
 };
 
 static inline void btrfs_init_delayed_root(
index 6a13cf0..9fe4ccc 100644 (file)
@@ -103,24 +103,17 @@ void btrfs_update_delayed_refs_rsv(struct btrfs_trans_handle *trans)
  * Transfer bytes to our delayed refs rsv.
  *
  * @fs_info:   the filesystem
- * @src:       source block rsv to transfer from
  * @num_bytes: number of bytes to transfer
  *
- * This transfers up to the num_bytes amount from the src rsv to the
+ * This transfers up to the num_bytes amount, previously reserved, to the
  * delayed_refs_rsv.  Any extra bytes are returned to the space info.
  */
 void btrfs_migrate_to_delayed_refs_rsv(struct btrfs_fs_info *fs_info,
-                                      struct btrfs_block_rsv *src,
                                       u64 num_bytes)
 {
        struct btrfs_block_rsv *delayed_refs_rsv = &fs_info->delayed_refs_rsv;
        u64 to_free = 0;
 
-       spin_lock(&src->lock);
-       src->reserved -= num_bytes;
-       src->size -= num_bytes;
-       spin_unlock(&src->lock);
-
        spin_lock(&delayed_refs_rsv->lock);
        if (delayed_refs_rsv->size > delayed_refs_rsv->reserved) {
                u64 delta = delayed_refs_rsv->size -
@@ -163,6 +156,8 @@ int btrfs_delayed_refs_rsv_refill(struct btrfs_fs_info *fs_info,
        struct btrfs_block_rsv *block_rsv = &fs_info->delayed_refs_rsv;
        u64 limit = btrfs_calc_delayed_ref_bytes(fs_info, 1);
        u64 num_bytes = 0;
+       u64 refilled_bytes;
+       u64 to_free;
        int ret = -ENOSPC;
 
        spin_lock(&block_rsv->lock);
@@ -178,9 +173,38 @@ int btrfs_delayed_refs_rsv_refill(struct btrfs_fs_info *fs_info,
        ret = btrfs_reserve_metadata_bytes(fs_info, block_rsv, num_bytes, flush);
        if (ret)
                return ret;
-       btrfs_block_rsv_add_bytes(block_rsv, num_bytes, false);
-       trace_btrfs_space_reservation(fs_info, "delayed_refs_rsv",
-                                     0, num_bytes, 1);
+
+       /*
+        * We may have raced with someone else, so check again if we the block
+        * reserve is still not full and release any excess space.
+        */
+       spin_lock(&block_rsv->lock);
+       if (block_rsv->reserved < block_rsv->size) {
+               u64 needed = block_rsv->size - block_rsv->reserved;
+
+               if (num_bytes >= needed) {
+                       block_rsv->reserved += needed;
+                       block_rsv->full = true;
+                       to_free = num_bytes - needed;
+                       refilled_bytes = needed;
+               } else {
+                       block_rsv->reserved += num_bytes;
+                       to_free = 0;
+                       refilled_bytes = num_bytes;
+               }
+       } else {
+               to_free = num_bytes;
+               refilled_bytes = 0;
+       }
+       spin_unlock(&block_rsv->lock);
+
+       if (to_free > 0)
+               btrfs_space_info_free_bytes_may_use(fs_info, block_rsv->space_info,
+                                                   to_free);
+
+       if (refilled_bytes > 0)
+               trace_btrfs_space_reservation(fs_info, "delayed_refs_rsv", 0,
+                                             refilled_bytes, 1);
        return 0;
 }
 
index b8e14b0..fd9bf2b 100644 (file)
@@ -407,7 +407,6 @@ void btrfs_update_delayed_refs_rsv(struct btrfs_trans_handle *trans);
 int btrfs_delayed_refs_rsv_refill(struct btrfs_fs_info *fs_info,
                                  enum btrfs_reserve_flush_enum flush);
 void btrfs_migrate_to_delayed_refs_rsv(struct btrfs_fs_info *fs_info,
-                                      struct btrfs_block_rsv *src,
                                       u64 num_bytes);
 bool btrfs_check_space_for_delayed_refs(struct btrfs_fs_info *fs_info);
 
index f356f08..fc313fc 100644 (file)
@@ -1514,15 +1514,14 @@ static int __btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
        btrfs_release_path(path);
 
        /* now insert the actual backref */
-       if (owner < BTRFS_FIRST_FREE_OBJECTID) {
-               BUG_ON(refs_to_add != 1);
+       if (owner < BTRFS_FIRST_FREE_OBJECTID)
                ret = insert_tree_block_ref(trans, path, bytenr, parent,
                                            root_objectid);
-       } else {
+       else
                ret = insert_extent_data_ref(trans, path, bytenr, parent,
                                             root_objectid, owner, offset,
                                             refs_to_add);
-       }
+
        if (ret)
                btrfs_abort_transaction(trans, ret);
 out:
@@ -1656,7 +1655,10 @@ again:
                                goto again;
                        }
                } else {
-                       err = -EIO;
+                       err = -EUCLEAN;
+                       btrfs_err(fs_info,
+                 "missing extent item for extent %llu num_bytes %llu level %d",
+                                 head->bytenr, head->num_bytes, extent_op->level);
                        goto out;
                }
        }
@@ -1699,12 +1701,12 @@ static int run_delayed_tree_ref(struct btrfs_trans_handle *trans,
                parent = ref->parent;
        ref_root = ref->root;
 
-       if (node->ref_mod != 1) {
+       if (unlikely(node->ref_mod != 1)) {
                btrfs_err(trans->fs_info,
-       "btree block(%llu) has %d references rather than 1: action %d ref_root %llu parent %llu",
+       "btree block %llu has %d references rather than 1: action %d ref_root %llu parent %llu",
                          node->bytenr, node->ref_mod, node->action, ref_root,
                          parent);
-               return -EIO;
+               return -EUCLEAN;
        }
        if (node->action == BTRFS_ADD_DELAYED_REF && insert_reserved) {
                BUG_ON(!extent_op || !extent_op->update_flags);
index ac3fca5..caccd03 100644 (file)
@@ -484,10 +484,8 @@ static void end_bio_extent_writepage(struct btrfs_bio *bbio)
                                   bvec->bv_offset, bvec->bv_len);
 
                btrfs_finish_ordered_extent(bbio->ordered, page, start, len, !error);
-               if (error) {
-                       btrfs_page_clear_uptodate(fs_info, page, start, len);
+               if (error)
                        mapping_set_error(page->mapping, error);
-               }
                btrfs_page_clear_writeback(fs_info, page, start, len);
        }
 
@@ -1456,8 +1454,6 @@ done:
        if (ret) {
                btrfs_mark_ordered_io_finished(BTRFS_I(inode), page, page_start,
                                               PAGE_SIZE, !ret);
-               btrfs_page_clear_uptodate(btrfs_sb(inode->i_sb), page,
-                                         page_start, PAGE_SIZE);
                mapping_set_error(page->mapping, ret);
        }
        unlock_page(page);
@@ -1624,8 +1620,6 @@ static void extent_buffer_write_end_io(struct btrfs_bio *bbio)
                struct page *page = bvec->bv_page;
                u32 len = bvec->bv_len;
 
-               if (!uptodate)
-                       btrfs_page_clear_uptodate(fs_info, page, start, len);
                btrfs_page_clear_writeback(fs_info, page, start, len);
                bio_offset += len;
        }
@@ -2201,7 +2195,6 @@ void extent_write_locked_range(struct inode *inode, struct page *locked_page,
                if (ret) {
                        btrfs_mark_ordered_io_finished(BTRFS_I(inode), page,
                                                       cur, cur_len, !ret);
-                       btrfs_page_clear_uptodate(fs_info, page, cur, cur_len);
                        mapping_set_error(page->mapping, ret);
                }
                btrfs_page_unlock_writer(fs_info, page, cur, cur_len);
@@ -4002,8 +3995,14 @@ void read_extent_buffer(const struct extent_buffer *eb, void *dstv,
        char *dst = (char *)dstv;
        unsigned long i = get_eb_page_index(start);
 
-       if (check_eb_range(eb, start, len))
+       if (check_eb_range(eb, start, len)) {
+               /*
+                * Invalid range hit, reset the memory, so callers won't get
+                * some random garbage for their uninitialzed memory.
+                */
+               memset(dstv, 0, len);
                return;
+       }
 
        offset = get_eb_offset_in_page(eb, start);
 
index ca46a52..361535c 100644 (file)
@@ -1106,6 +1106,25 @@ void btrfs_check_nocow_unlock(struct btrfs_inode *inode)
        btrfs_drew_write_unlock(&inode->root->snapshot_lock);
 }
 
+static void update_time_for_write(struct inode *inode)
+{
+       struct timespec64 now, ctime;
+
+       if (IS_NOCMTIME(inode))
+               return;
+
+       now = current_time(inode);
+       if (!timespec64_equal(&inode->i_mtime, &now))
+               inode->i_mtime = now;
+
+       ctime = inode_get_ctime(inode);
+       if (!timespec64_equal(&ctime, &now))
+               inode_set_ctime_to_ts(inode, now);
+
+       if (IS_I_VERSION(inode))
+               inode_inc_iversion(inode);
+}
+
 static int btrfs_write_check(struct kiocb *iocb, struct iov_iter *from,
                             size_t count)
 {
@@ -1137,10 +1156,7 @@ static int btrfs_write_check(struct kiocb *iocb, struct iov_iter *from,
         * need to start yet another transaction to update the inode as we will
         * update the inode when we finish writing whatever data we write.
         */
-       if (!IS_NOCMTIME(inode)) {
-               inode->i_mtime = inode_set_ctime_current(inode);
-               inode_inc_iversion(inode);
-       }
+       update_time_for_write(inode);
 
        start_pos = round_down(pos, fs_info->sectorsize);
        oldsize = i_size_read(inode);
@@ -1451,8 +1467,13 @@ static ssize_t btrfs_direct_write(struct kiocb *iocb, struct iov_iter *from)
        if (iocb->ki_flags & IOCB_NOWAIT)
                ilock_flags |= BTRFS_ILOCK_TRY;
 
-       /* If the write DIO is within EOF, use a shared lock */
-       if (iocb->ki_pos + iov_iter_count(from) <= i_size_read(inode))
+       /*
+        * If the write DIO is within EOF, use a shared lock and also only if
+        * security bits will likely not be dropped by file_remove_privs() called
+        * from btrfs_write_check(). Either will need to be rechecked after the
+        * lock was acquired.
+        */
+       if (iocb->ki_pos + iov_iter_count(from) <= i_size_read(inode) && IS_NOSEC(inode))
                ilock_flags |= BTRFS_ILOCK_SHARED;
 
 relock:
@@ -1460,6 +1481,13 @@ relock:
        if (err < 0)
                return err;
 
+       /* Shared lock cannot be used with security bits set. */
+       if ((ilock_flags & BTRFS_ILOCK_SHARED) && !IS_NOSEC(inode)) {
+               btrfs_inode_unlock(BTRFS_I(inode), ilock_flags);
+               ilock_flags &= ~BTRFS_ILOCK_SHARED;
+               goto relock;
+       }
+
        err = generic_write_checks(iocb, from);
        if (err <= 0) {
                btrfs_inode_unlock(BTRFS_I(inode), ilock_flags);
index f09fbdc..7814b9d 100644 (file)
@@ -1085,9 +1085,6 @@ static void submit_uncompressed_range(struct btrfs_inode *inode,
                        btrfs_mark_ordered_io_finished(inode, locked_page,
                                                       page_start, PAGE_SIZE,
                                                       !ret);
-                       btrfs_page_clear_uptodate(inode->root->fs_info,
-                                                 locked_page, page_start,
-                                                 PAGE_SIZE);
                        mapping_set_error(locked_page->mapping, ret);
                        unlock_page(locked_page);
                }
@@ -2791,7 +2788,6 @@ out_page:
                mapping_set_error(page->mapping, ret);
                btrfs_mark_ordered_io_finished(inode, page, page_start,
                                               PAGE_SIZE, !ret);
-               btrfs_page_clear_uptodate(fs_info, page, page_start, PAGE_SIZE);
                clear_page_dirty_for_io(page);
        }
        btrfs_page_clear_checked(fs_info, page, page_start, PAGE_SIZE);
@@ -5769,20 +5765,24 @@ out:
 
 static int btrfs_get_dir_last_index(struct btrfs_inode *dir, u64 *index)
 {
-       if (dir->index_cnt == (u64)-1) {
-               int ret;
+       int ret = 0;
 
+       btrfs_inode_lock(dir, 0);
+       if (dir->index_cnt == (u64)-1) {
                ret = btrfs_inode_delayed_dir_index_count(dir);
                if (ret) {
                        ret = btrfs_set_inode_index_count(dir);
                        if (ret)
-                               return ret;
+                               goto out;
                }
        }
 
-       *index = dir->index_cnt;
+       /* index_cnt is the index number of next new entry, so decrement it. */
+       *index = dir->index_cnt - 1;
+out:
+       btrfs_inode_unlock(dir, 0);
 
-       return 0;
+       return ret;
 }
 
 /*
@@ -5817,6 +5817,19 @@ static int btrfs_opendir(struct inode *inode, struct file *file)
        return 0;
 }
 
+static loff_t btrfs_dir_llseek(struct file *file, loff_t offset, int whence)
+{
+       struct btrfs_file_private *private = file->private_data;
+       int ret;
+
+       ret = btrfs_get_dir_last_index(BTRFS_I(file_inode(file)),
+                                      &private->last_index);
+       if (ret)
+               return ret;
+
+       return generic_file_llseek(file, offset, whence);
+}
+
 struct dir_entry {
        u64 ino;
        u64 offset;
@@ -10868,7 +10881,7 @@ static const struct inode_operations btrfs_dir_inode_operations = {
 };
 
 static const struct file_operations btrfs_dir_file_operations = {
-       .llseek         = generic_file_llseek,
+       .llseek         = btrfs_dir_llseek,
        .read           = generic_read_dir,
        .iterate_shared = btrfs_real_readdir,
        .open           = btrfs_opendir,
index 75ab766..8e7d03b 100644 (file)
@@ -2978,7 +2978,7 @@ static void get_block_group_info(struct list_head *groups_list,
 static long btrfs_ioctl_space_info(struct btrfs_fs_info *fs_info,
                                   void __user *arg)
 {
-       struct btrfs_ioctl_space_args space_args;
+       struct btrfs_ioctl_space_args space_args = { 0 };
        struct btrfs_ioctl_space_info space;
        struct btrfs_ioctl_space_info *dest;
        struct btrfs_ioctl_space_info *dest_orig;
@@ -4338,7 +4338,7 @@ static int _btrfs_ioctl_send(struct inode *inode, void __user *argp, bool compat
 
        if (compat) {
 #if defined(CONFIG_64BIT) && defined(CONFIG_COMPAT)
-               struct btrfs_ioctl_send_args_32 args32;
+               struct btrfs_ioctl_send_args_32 args32 = { 0 };
 
                ret = copy_from_user(&args32, argp, sizeof(args32));
                if (ret)
index 09bfe68..1a093ec 100644 (file)
@@ -2117,7 +2117,7 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
         * calculated f_bavail.
         */
        if (!mixed && block_rsv->space_info->full &&
-           total_free_meta - thresh < block_rsv->size)
+           (total_free_meta < thresh || total_free_meta - thresh < block_rsv->size))
                buf->f_bavail = 0;
 
        buf->f_type = BTRFS_SUPER_MAGIC;
@@ -2150,7 +2150,7 @@ static struct file_system_type btrfs_fs_type = {
        .name           = "btrfs",
        .mount          = btrfs_mount,
        .kill_sb        = btrfs_kill_super,
-       .fs_flags       = FS_REQUIRES_DEV | FS_BINARY_MOUNTDATA | FS_MGTIME,
+       .fs_flags       = FS_REQUIRES_DEV | FS_BINARY_MOUNTDATA,
 };
 
 static struct file_system_type btrfs_root_fs_type = {
@@ -2158,8 +2158,7 @@ static struct file_system_type btrfs_root_fs_type = {
        .name           = "btrfs",
        .mount          = btrfs_mount_root,
        .kill_sb        = btrfs_kill_super,
-       .fs_flags       = FS_REQUIRES_DEV | FS_BINARY_MOUNTDATA |
-                         FS_ALLOW_IDMAP | FS_MGTIME,
+       .fs_flags       = FS_REQUIRES_DEV | FS_BINARY_MOUNTDATA | FS_ALLOW_IDMAP,
 };
 
 MODULE_ALIAS_FS("btrfs");
index 0bf42dc..c780d37 100644 (file)
@@ -631,14 +631,14 @@ start_transaction(struct btrfs_root *root, unsigned int num_items,
                        reloc_reserved = true;
                }
 
-               ret = btrfs_block_rsv_add(fs_info, rsv, num_bytes, flush);
+               ret = btrfs_reserve_metadata_bytes(fs_info, rsv, num_bytes, flush);
                if (ret)
                        goto reserve_fail;
                if (delayed_refs_bytes) {
-                       btrfs_migrate_to_delayed_refs_rsv(fs_info, rsv,
-                                                         delayed_refs_bytes);
+                       btrfs_migrate_to_delayed_refs_rsv(fs_info, delayed_refs_bytes);
                        num_bytes -= delayed_refs_bytes;
                }
+               btrfs_block_rsv_add_bytes(rsv, num_bytes, true);
 
                if (rsv->space_info->force_alloc)
                        do_chunk_alloc = true;
index 6b309f8..93869cd 100644 (file)
@@ -219,8 +219,8 @@ do {                                                                \
                        (errno))) {                                     \
                        /* Stack trace printed. */                      \
                } else {                                                \
-                       btrfs_debug((trans)->fs_info,                   \
-                                   "Transaction aborted (error %d)", \
+                       btrfs_err((trans)->fs_info,                     \
+                                 "Transaction aborted (error %d)",     \
                                  (errno));                     \
                }                                               \
        }                                                       \
index d1e46b8..cbb17b5 100644 (file)
@@ -4722,7 +4722,7 @@ static int btrfs_log_prealloc_extents(struct btrfs_trans_handle *trans,
        struct extent_buffer *leaf;
        int slot;
        int ins_nr = 0;
-       int start_slot;
+       int start_slot = 0;
        int ret;
 
        if (!(inode->flags & BTRFS_INODE_PREALLOC))
index c5ff16f..744f4f4 100644 (file)
@@ -715,7 +715,7 @@ static struct page *btrfs_read_merkle_tree_page(struct inode *inode,
                                                pgoff_t index,
                                                unsigned long num_ra_pages)
 {
-       struct page *page;
+       struct folio *folio;
        u64 off = (u64)index << PAGE_SHIFT;
        loff_t merkle_pos = merkle_file_pos(inode);
        int ret;
@@ -726,29 +726,36 @@ static struct page *btrfs_read_merkle_tree_page(struct inode *inode,
                return ERR_PTR(-EFBIG);
        index += merkle_pos >> PAGE_SHIFT;
 again:
-       page = find_get_page_flags(inode->i_mapping, index, FGP_ACCESSED);
-       if (page) {
-               if (PageUptodate(page))
-                       return page;
+       folio = __filemap_get_folio(inode->i_mapping, index, FGP_ACCESSED, 0);
+       if (!IS_ERR(folio)) {
+               if (folio_test_uptodate(folio))
+                       goto out;
 
-               lock_page(page);
-               /*
-                * We only insert uptodate pages, so !Uptodate has to be
-                * an error
-                */
-               if (!PageUptodate(page)) {
-                       unlock_page(page);
-                       put_page(page);
+               folio_lock(folio);
+               /* If it's not uptodate after we have the lock, we got a read error. */
+               if (!folio_test_uptodate(folio)) {
+                       folio_unlock(folio);
+                       folio_put(folio);
                        return ERR_PTR(-EIO);
                }
-               unlock_page(page);
-               return page;
+               folio_unlock(folio);
+               goto out;
        }
 
-       page = __page_cache_alloc(mapping_gfp_constraint(inode->i_mapping, ~__GFP_FS));
-       if (!page)
+       folio = filemap_alloc_folio(mapping_gfp_constraint(inode->i_mapping, ~__GFP_FS),
+                                   0);
+       if (!folio)
                return ERR_PTR(-ENOMEM);
 
+       ret = filemap_add_folio(inode->i_mapping, folio, index, GFP_NOFS);
+       if (ret) {
+               folio_put(folio);
+               /* Did someone else insert a folio here? */
+               if (ret == -EEXIST)
+                       goto again;
+               return ERR_PTR(ret);
+       }
+
        /*
         * Merkle item keys are indexed from byte 0 in the merkle tree.
         * They have the form:
@@ -756,28 +763,19 @@ again:
         * [ inode objectid, BTRFS_MERKLE_ITEM_KEY, offset in bytes ]
         */
        ret = read_key_bytes(BTRFS_I(inode), BTRFS_VERITY_MERKLE_ITEM_KEY, off,
-                            page_address(page), PAGE_SIZE, page);
+                            folio_address(folio), PAGE_SIZE, &folio->page);
        if (ret < 0) {
-               put_page(page);
+               folio_put(folio);
                return ERR_PTR(ret);
        }
        if (ret < PAGE_SIZE)
-               memzero_page(page, ret, PAGE_SIZE - ret);
+               folio_zero_segment(folio, ret, PAGE_SIZE);
 
-       SetPageUptodate(page);
-       ret = add_to_page_cache_lru(page, inode->i_mapping, index, GFP_NOFS);
+       folio_mark_uptodate(folio);
+       folio_unlock(folio);
 
-       if (!ret) {
-               /* Inserted and ready for fsverity */
-               unlock_page(page);
-       } else {
-               put_page(page);
-               /* Did someone race us into inserting this page? */
-               if (ret == -EEXIST)
-                       goto again;
-               page = ERR_PTR(ret);
-       }
-       return page;
+out:
+       return folio_file_page(folio, index);
 }
 
 /*
index 9621455..5a5a8d4 100644 (file)
@@ -1594,7 +1594,7 @@ static int find_free_dev_extent(struct btrfs_device *device, u64 num_bytes,
        u64 search_start;
        u64 hole_size;
        u64 max_hole_start;
-       u64 max_hole_size;
+       u64 max_hole_size = 0;
        u64 extent_end;
        u64 search_end = device->total_bytes;
        int ret;
@@ -1602,17 +1602,16 @@ static int find_free_dev_extent(struct btrfs_device *device, u64 num_bytes,
        struct extent_buffer *l;
 
        search_start = dev_extent_search_start(device);
+       max_hole_start = search_start;
 
        WARN_ON(device->zone_info &&
                !IS_ALIGNED(num_bytes, device->zone_info->zone_size));
 
        path = btrfs_alloc_path();
-       if (!path)
-               return -ENOMEM;
-
-       max_hole_start = search_start;
-       max_hole_size = 0;
-
+       if (!path) {
+               ret = -ENOMEM;
+               goto out;
+       }
 again:
        if (search_start >= search_end ||
                test_bit(BTRFS_DEV_STATE_REPLACE_TGT, &device->dev_state)) {
index 2379564..12e9a71 100644 (file)
@@ -2011,7 +2011,7 @@ void folio_zero_new_buffers(struct folio *folio, size_t from, size_t to)
 }
 EXPORT_SYMBOL(folio_zero_new_buffers);
 
-static void
+static int
 iomap_to_bh(struct inode *inode, sector_t block, struct buffer_head *bh,
                const struct iomap *iomap)
 {
@@ -2025,7 +2025,8 @@ iomap_to_bh(struct inode *inode, sector_t block, struct buffer_head *bh,
         * current block, then do not map the buffer and let the caller
         * handle it.
         */
-       BUG_ON(offset >= iomap->offset + iomap->length);
+       if (offset >= iomap->offset + iomap->length)
+               return -EIO;
 
        switch (iomap->type) {
        case IOMAP_HOLE:
@@ -2037,7 +2038,7 @@ iomap_to_bh(struct inode *inode, sector_t block, struct buffer_head *bh,
                if (!buffer_uptodate(bh) ||
                    (offset >= i_size_read(inode)))
                        set_buffer_new(bh);
-               break;
+               return 0;
        case IOMAP_DELALLOC:
                if (!buffer_uptodate(bh) ||
                    (offset >= i_size_read(inode)))
@@ -2045,7 +2046,7 @@ iomap_to_bh(struct inode *inode, sector_t block, struct buffer_head *bh,
                set_buffer_uptodate(bh);
                set_buffer_mapped(bh);
                set_buffer_delay(bh);
-               break;
+               return 0;
        case IOMAP_UNWRITTEN:
                /*
                 * For unwritten regions, we always need to ensure that regions
@@ -2057,12 +2058,24 @@ iomap_to_bh(struct inode *inode, sector_t block, struct buffer_head *bh,
                fallthrough;
        case IOMAP_MAPPED:
                if ((iomap->flags & IOMAP_F_NEW) ||
-                   offset >= i_size_read(inode))
+                   offset >= i_size_read(inode)) {
+                       /*
+                        * This can happen if truncating the block device races
+                        * with the check in the caller as i_size updates on
+                        * block devices aren't synchronized by i_rwsem for
+                        * block devices.
+                        */
+                       if (S_ISBLK(inode->i_mode))
+                               return -EIO;
                        set_buffer_new(bh);
+               }
                bh->b_blocknr = (iomap->addr + offset - iomap->offset) >>
                                inode->i_blkbits;
                set_buffer_mapped(bh);
-               break;
+               return 0;
+       default:
+               WARN_ON_ONCE(1);
+               return -EIO;
        }
 }
 
@@ -2103,13 +2116,12 @@ int __block_write_begin_int(struct folio *folio, loff_t pos, unsigned len,
                        clear_buffer_new(bh);
                if (!buffer_mapped(bh)) {
                        WARN_ON(bh->b_size != blocksize);
-                       if (get_block) {
+                       if (get_block)
                                err = get_block(inode, block, bh, 1);
-                               if (err)
-                                       break;
-                       } else {
-                               iomap_to_bh(inode, block, bh, iomap);
-                       }
+                       else
+                               err = iomap_to_bh(inode, block, bh, iomap);
+                       if (err)
+                               break;
 
                        if (buffer_new(bh)) {
                                clean_bdev_bh_alias(bh);
index e4d5cd5..e1f31b8 100644 (file)
@@ -249,11 +249,9 @@ static struct inode *parse_longname(const struct inode *parent,
        if (!dir) {
                /* This can happen if we're not mounting cephfs on the root */
                dir = ceph_get_inode(parent->i_sb, vino, NULL);
-               if (!dir)
-                       dir = ERR_PTR(-ENOENT);
+               if (IS_ERR(dir))
+                       dout("Can't find inode %s (%s)\n", inode_number, name);
        }
-       if (IS_ERR(dir))
-               dout("Can't find inode %s (%s)\n", inode_number, name);
 
 out:
        kfree(inode_number);
index 73091fb..dee10d2 100644 (file)
@@ -217,9 +217,12 @@ again:
                        strm->buf.out_size = min_t(u32, outlen,
                                                   PAGE_SIZE - pageofs);
                        outlen -= strm->buf.out_size;
-                       if (!rq->out[no] && rq->fillgaps)       /* deduped */
+                       if (!rq->out[no] && rq->fillgaps) {     /* deduped */
                                rq->out[no] = erofs_allocpage(pagepool,
                                                GFP_KERNEL | __GFP_NOFAIL);
+                               set_page_private(rq->out[no],
+                                                Z_EROFS_SHORTLIVED_PAGE);
+                       }
                        if (rq->out[no])
                                strm->buf.out = kmap(rq->out[no]) + pageofs;
                        pageofs = 0;
index 44a24d5..3700af9 100644 (file)
@@ -235,7 +235,7 @@ static int erofs_init_device(struct erofs_buf *buf, struct super_block *sb,
                return PTR_ERR(ptr);
        dis = ptr + erofs_blkoff(sb, *pos);
 
-       if (!dif->path) {
+       if (!sbi->devs->flatdev && !dif->path) {
                if (!dis->tag[0]) {
                        erofs_err(sb, "empty device tag @ pos %llu", *pos);
                        return -EINVAL;
index 3821742..dbebd8b 100644 (file)
@@ -7314,7 +7314,7 @@ static struct file_system_type ext4_fs_type = {
        .init_fs_context        = ext4_init_fs_context,
        .parameters             = ext4_param_specs,
        .kill_sb                = ext4_kill_sb,
-       .fs_flags               = FS_REQUIRES_DEV | FS_ALLOW_IDMAP | FS_MGTIME,
+       .fs_flags               = FS_REQUIRES_DEV | FS_ALLOW_IDMAP,
 };
 MODULE_ALIAS_FS("ext4");
 
index 969ce99..c1af01b 100644 (file)
@@ -1535,10 +1535,15 @@ static void requeue_inode(struct inode *inode, struct bdi_writeback *wb,
 
        if (wbc->pages_skipped) {
                /*
-                * writeback is not making progress due to locked
-                * buffers. Skip this inode for now.
+                * Writeback is not making progress due to locked buffers.
+                * Skip this inode for now. Although having skipped pages
+                * is odd for clean inodes, it can happen for some
+                * filesystems so handle that gracefully.
                 */
-               redirty_tail_locked(inode, wb);
+               if (inode->i_state & I_DIRTY_ALL)
+                       redirty_tail_locked(inode, wb);
+               else
+                       inode_cgwb_move_to_attached(inode, wb);
                return;
        }
 
index 9cbf8d9..4a280be 100644 (file)
@@ -2010,7 +2010,9 @@ static long gfs2_scan_glock_lru(int nr)
                if (!test_bit(GLF_LOCK, &gl->gl_flags)) {
                        if (!spin_trylock(&gl->gl_lockref.lock))
                                continue;
-                       if (!gl->gl_lockref.count) {
+                       if (gl->gl_lockref.count <= 1 &&
+                           (gl->gl_state == LM_ST_UNLOCKED ||
+                            demote_ok(gl))) {
                                list_move(&gl->gl_lru, &dispose);
                                atomic_dec(&lru_count);
                                freed++;
index d26759a..f41ca89 100644 (file)
@@ -567,15 +567,16 @@ static void freeze_go_callback(struct gfs2_glock *gl, bool remote)
        struct super_block *sb = sdp->sd_vfs;
 
        if (!remote ||
-           gl->gl_state != LM_ST_SHARED ||
+           (gl->gl_state != LM_ST_SHARED &&
+            gl->gl_state != LM_ST_UNLOCKED) ||
            gl->gl_demote_state != LM_ST_UNLOCKED)
                return;
 
        /*
         * Try to get an active super block reference to prevent racing with
-        * unmount (see trylock_super()).  But note that unmount isn't the only
-        * place where a write lock on s_umount is taken, and we can fail here
-        * because of things like remount as well.
+        * unmount (see super_trylock_shared()).  But note that unmount isn't
+        * the only place where a write lock on s_umount is taken, and we can
+        * fail here because of things like remount as well.
         */
        if (down_read_trylock(&sb->s_umount)) {
                atomic_inc(&sb->s_active);
index 21ada33..1429945 100644 (file)
@@ -50,7 +50,8 @@ static inline int gfs2_quota_lock_check(struct gfs2_inode *ip,
        ret = gfs2_quota_lock(ip, NO_UID_QUOTA_CHANGE, NO_GID_QUOTA_CHANGE);
        if (ret)
                return ret;
-       if (sdp->sd_args.ar_quota != GFS2_QUOTA_ON)
+       if (sdp->sd_args.ar_quota != GFS2_QUOTA_ON &&
+           sdp->sd_args.ar_quota != GFS2_QUOTA_QUIET)
                return 0;
        ret = gfs2_quota_check(ip, ip->i_inode.i_uid, ip->i_inode.i_gid, ap);
        if (ret)
index 35fd688..84bc3c7 100644 (file)
@@ -2102,52 +2102,10 @@ int file_remove_privs(struct file *file)
 }
 EXPORT_SYMBOL(file_remove_privs);
 
-/**
- * current_mgtime - Return FS time (possibly fine-grained)
- * @inode: inode.
- *
- * Return the current time truncated to the time granularity supported by
- * the fs, as suitable for a ctime/mtime change. If the ctime is flagged
- * as having been QUERIED, get a fine-grained timestamp.
- */
-struct timespec64 current_mgtime(struct inode *inode)
-{
-       struct timespec64 now, ctime;
-       atomic_long_t *pnsec = (atomic_long_t *)&inode->__i_ctime.tv_nsec;
-       long nsec = atomic_long_read(pnsec);
-
-       if (nsec & I_CTIME_QUERIED) {
-               ktime_get_real_ts64(&now);
-               return timestamp_truncate(now, inode);
-       }
-
-       ktime_get_coarse_real_ts64(&now);
-       now = timestamp_truncate(now, inode);
-
-       /*
-        * If we've recently fetched a fine-grained timestamp
-        * then the coarse-grained one may still be earlier than the
-        * existing ctime. Just keep the existing value if so.
-        */
-       ctime = inode_get_ctime(inode);
-       if (timespec64_compare(&ctime, &now) > 0)
-               now = ctime;
-
-       return now;
-}
-EXPORT_SYMBOL(current_mgtime);
-
-static struct timespec64 current_ctime(struct inode *inode)
-{
-       if (is_mgtime(inode))
-               return current_mgtime(inode);
-       return current_time(inode);
-}
-
 static int inode_needs_update_time(struct inode *inode)
 {
        int sync_it = 0;
-       struct timespec64 now = current_ctime(inode);
+       struct timespec64 now = current_time(inode);
        struct timespec64 ctime;
 
        /* First try to exhaust all avenues to not sync */
@@ -2578,43 +2536,9 @@ EXPORT_SYMBOL(current_time);
  */
 struct timespec64 inode_set_ctime_current(struct inode *inode)
 {
-       struct timespec64 now;
-       struct timespec64 ctime;
-
-       ctime.tv_nsec = READ_ONCE(inode->__i_ctime.tv_nsec);
-       if (!(ctime.tv_nsec & I_CTIME_QUERIED)) {
-               now = current_time(inode);
+       struct timespec64 now = current_time(inode);
 
-               /* Just copy it into place if it's not multigrain */
-               if (!is_mgtime(inode)) {
-                       inode_set_ctime_to_ts(inode, now);
-                       return now;
-               }
-
-               /*
-                * If we've recently updated with a fine-grained timestamp,
-                * then the coarse-grained one may still be earlier than the
-                * existing ctime. Just keep the existing value if so.
-                */
-               ctime.tv_sec = inode->__i_ctime.tv_sec;
-               if (timespec64_compare(&ctime, &now) > 0)
-                       return ctime;
-
-               /*
-                * Ctime updates are usually protected by the inode_lock, but
-                * we can still race with someone setting the QUERIED flag.
-                * Try to swap the new nsec value into place. If it's changed
-                * in the interim, then just go with a fine-grained timestamp.
-                */
-               if (cmpxchg(&inode->__i_ctime.tv_nsec, ctime.tv_nsec,
-                           now.tv_nsec) != ctime.tv_nsec)
-                       goto fine_grained;
-               inode->__i_ctime.tv_sec = now.tv_sec;
-               return now;
-       }
-fine_grained:
-       ktime_get_real_ts64(&now);
-       inode_set_ctime_to_ts(inode, timestamp_truncate(now, inode));
+       inode_set_ctime(inode, now.tv_sec, now.tv_nsec);
        return now;
 }
 EXPORT_SYMBOL(inode_set_ctime_current);
index ae8673c..5db54ca 100644 (file)
@@ -640,11 +640,13 @@ static int __iomap_write_begin(const struct iomap_iter *iter, loff_t pos,
        size_t poff, plen;
 
        /*
-        * If the write completely overlaps the current folio, then
+        * If the write or zeroing completely overlaps the current folio, then
         * entire folio will be dirtied so there is no need for
         * per-block state tracking structures to be attached to this folio.
+        * For the unshare case, we must read in the ondisk contents because we
+        * are not changing pagecache contents.
         */
-       if (pos <= folio_pos(folio) &&
+       if (!(iter->flags & IOMAP_UNSHARE) && pos <= folio_pos(folio) &&
            pos + len >= folio_pos(folio) + folio_size(folio))
                return 0;
 
@@ -1047,7 +1049,7 @@ static int iomap_write_delalloc_punch(struct inode *inode, struct folio *folio,
 
 /*
  * Scan the data range passed to us for dirty page cache folios. If we find a
- * dirty folio, punch out the preceeding range and update the offset from which
+ * dirty folio, punch out the preceding range and update the offset from which
  * the next punch will start from.
  *
  * We can punch out storage reservations under clean pages because they either
@@ -1261,7 +1263,6 @@ static loff_t iomap_unshare_iter(struct iomap_iter *iter)
        const struct iomap *srcmap = iomap_iter_srcmap(iter);
        loff_t pos = iter->pos;
        loff_t length = iomap_length(iter);
-       long status = 0;
        loff_t written = 0;
 
        /* don't bother with blocks that are not shared to start with */
@@ -1272,28 +1273,33 @@ static loff_t iomap_unshare_iter(struct iomap_iter *iter)
                return length;
 
        do {
-               unsigned long offset = offset_in_page(pos);
-               unsigned long bytes = min_t(loff_t, PAGE_SIZE - offset, length);
                struct folio *folio;
+               int status;
+               size_t offset;
+               size_t bytes = min_t(u64, SIZE_MAX, length);
 
                status = iomap_write_begin(iter, pos, bytes, &folio);
                if (unlikely(status))
                        return status;
-               if (iter->iomap.flags & IOMAP_F_STALE)
+               if (iomap->flags & IOMAP_F_STALE)
                        break;
 
-               status = iomap_write_end(iter, pos, bytes, bytes, folio);
-               if (WARN_ON_ONCE(status == 0))
+               offset = offset_in_folio(folio, pos);
+               if (bytes > folio_size(folio) - offset)
+                       bytes = folio_size(folio) - offset;
+
+               bytes = iomap_write_end(iter, pos, bytes, bytes, folio);
+               if (WARN_ON_ONCE(bytes == 0))
                        return -EIO;
 
                cond_resched();
 
-               pos += status;
-               written += status;
-               length -= status;
+               pos += bytes;
+               written += bytes;
+               length -= bytes;
 
                balance_dirty_pages_ratelimited(iter->inode->i_mapping);
-       } while (length);
+       } while (length > 0);
 
        return written;
 }
index a4eb127..37f2d34 100644 (file)
@@ -1903,6 +1903,7 @@ ssize_t direct_write_fallback(struct kiocb *iocb, struct iov_iter *iter,
                 * We don't know how much we wrote, so just return the number of
                 * bytes which were direct-written
                 */
+               iocb->ki_pos -= buffered_written;
                if (direct_written)
                        return direct_written;
                return err;
index 3404707..2cd3ccf 100644 (file)
@@ -47,12 +47,14 @@ void netfs_rreq_unlock_folios(struct netfs_io_request *rreq)
        xas_for_each(&xas, folio, last_page) {
                loff_t pg_end;
                bool pg_failed = false;
+               bool folio_started;
 
                if (xas_retry(&xas, folio))
                        continue;
 
                pg_end = folio_pos(folio) + folio_size(folio) - 1;
 
+               folio_started = false;
                for (;;) {
                        loff_t sreq_end;
 
@@ -60,8 +62,10 @@ void netfs_rreq_unlock_folios(struct netfs_io_request *rreq)
                                pg_failed = true;
                                break;
                        }
-                       if (test_bit(NETFS_SREQ_COPY_TO_CACHE, &subreq->flags))
+                       if (!folio_started && test_bit(NETFS_SREQ_COPY_TO_CACHE, &subreq->flags)) {
                                folio_start_fscache(folio);
+                               folio_started = true;
+                       }
                        pg_failed |= subreq_failed;
                        sreq_end = subreq->start + subreq->len - 1;
                        if (pg_end < sreq_end)
index 47d892a..f6c74f4 100644 (file)
@@ -93,12 +93,10 @@ nfs_direct_handle_truncated(struct nfs_direct_req *dreq,
                dreq->max_count = dreq_len;
                if (dreq->count > dreq_len)
                        dreq->count = dreq_len;
-
-               if (test_bit(NFS_IOHDR_ERROR, &hdr->flags))
-                       dreq->error = hdr->error;
-               else /* Clear outstanding error if this is EOF */
-                       dreq->error = 0;
        }
+
+       if (test_bit(NFS_IOHDR_ERROR, &hdr->flags) && !dreq->error)
+               dreq->error = hdr->error;
 }
 
 static void
@@ -120,6 +118,18 @@ nfs_direct_count_bytes(struct nfs_direct_req *dreq,
                dreq->count = dreq_len;
 }
 
+static void nfs_direct_truncate_request(struct nfs_direct_req *dreq,
+                                       struct nfs_page *req)
+{
+       loff_t offs = req_offset(req);
+       size_t req_start = (size_t)(offs - dreq->io_start);
+
+       if (req_start < dreq->max_count)
+               dreq->max_count = req_start;
+       if (req_start < dreq->count)
+               dreq->count = req_start;
+}
+
 /**
  * nfs_swap_rw - NFS address space operation for swap I/O
  * @iocb: target I/O control block
@@ -488,7 +498,9 @@ static void nfs_direct_add_page_head(struct list_head *list,
        kref_get(&head->wb_kref);
 }
 
-static void nfs_direct_join_group(struct list_head *list, struct inode *inode)
+static void nfs_direct_join_group(struct list_head *list,
+                                 struct nfs_commit_info *cinfo,
+                                 struct inode *inode)
 {
        struct nfs_page *req, *subreq;
 
@@ -510,7 +522,7 @@ static void nfs_direct_join_group(struct list_head *list, struct inode *inode)
                                nfs_release_request(subreq);
                        }
                } while ((subreq = subreq->wb_this_page) != req);
-               nfs_join_page_group(req, inode);
+               nfs_join_page_group(req, cinfo, inode);
        }
 }
 
@@ -528,20 +540,15 @@ nfs_direct_write_scan_commit_list(struct inode *inode,
 static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq)
 {
        struct nfs_pageio_descriptor desc;
-       struct nfs_page *req, *tmp;
+       struct nfs_page *req;
        LIST_HEAD(reqs);
        struct nfs_commit_info cinfo;
-       LIST_HEAD(failed);
 
        nfs_init_cinfo_from_dreq(&cinfo, dreq);
        nfs_direct_write_scan_commit_list(dreq->inode, &reqs, &cinfo);
 
-       nfs_direct_join_group(&reqs, dreq->inode);
+       nfs_direct_join_group(&reqs, &cinfo, dreq->inode);
 
-       dreq->count = 0;
-       dreq->max_count = 0;
-       list_for_each_entry(req, &reqs, wb_list)
-               dreq->max_count += req->wb_bytes;
        nfs_clear_pnfs_ds_commit_verifiers(&dreq->ds_cinfo);
        get_dreq(dreq);
 
@@ -549,27 +556,40 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq)
                              &nfs_direct_write_completion_ops);
        desc.pg_dreq = dreq;
 
-       list_for_each_entry_safe(req, tmp, &reqs, wb_list) {
+       while (!list_empty(&reqs)) {
+               req = nfs_list_entry(reqs.next);
                /* Bump the transmission count */
                req->wb_nio++;
                if (!nfs_pageio_add_request(&desc, req)) {
-                       nfs_list_move_request(req, &failed);
-                       spin_lock(&cinfo.inode->i_lock);
-                       dreq->flags = 0;
-                       if (desc.pg_error < 0)
+                       spin_lock(&dreq->lock);
+                       if (dreq->error < 0) {
+                               desc.pg_error = dreq->error;
+                       } else if (desc.pg_error != -EAGAIN) {
+                               dreq->flags = 0;
+                               if (!desc.pg_error)
+                                       desc.pg_error = -EIO;
                                dreq->error = desc.pg_error;
-                       else
-                               dreq->error = -EIO;
-                       spin_unlock(&cinfo.inode->i_lock);
+                       } else
+                               dreq->flags = NFS_ODIRECT_RESCHED_WRITES;
+                       spin_unlock(&dreq->lock);
+                       break;
                }
                nfs_release_request(req);
        }
        nfs_pageio_complete(&desc);
 
-       while (!list_empty(&failed)) {
-               req = nfs_list_entry(failed.next);
+       while (!list_empty(&reqs)) {
+               req = nfs_list_entry(reqs.next);
                nfs_list_remove_request(req);
                nfs_unlock_and_release_request(req);
+               if (desc.pg_error == -EAGAIN) {
+                       nfs_mark_request_commit(req, NULL, &cinfo, 0);
+               } else {
+                       spin_lock(&dreq->lock);
+                       nfs_direct_truncate_request(dreq, req);
+                       spin_unlock(&dreq->lock);
+                       nfs_release_request(req);
+               }
        }
 
        if (put_dreq(dreq))
@@ -589,8 +609,6 @@ static void nfs_direct_commit_complete(struct nfs_commit_data *data)
        if (status < 0) {
                /* Errors in commit are fatal */
                dreq->error = status;
-               dreq->max_count = 0;
-               dreq->count = 0;
                dreq->flags = NFS_ODIRECT_DONE;
        } else {
                status = dreq->error;
@@ -601,7 +619,12 @@ static void nfs_direct_commit_complete(struct nfs_commit_data *data)
        while (!list_empty(&data->pages)) {
                req = nfs_list_entry(data->pages.next);
                nfs_list_remove_request(req);
-               if (status >= 0 && !nfs_write_match_verf(verf, req)) {
+               if (status < 0) {
+                       spin_lock(&dreq->lock);
+                       nfs_direct_truncate_request(dreq, req);
+                       spin_unlock(&dreq->lock);
+                       nfs_release_request(req);
+               } else if (!nfs_write_match_verf(verf, req)) {
                        dreq->flags = NFS_ODIRECT_RESCHED_WRITES;
                        /*
                         * Despite the reboot, the write was successful,
@@ -609,7 +632,7 @@ static void nfs_direct_commit_complete(struct nfs_commit_data *data)
                         */
                        req->wb_nio = 0;
                        nfs_mark_request_commit(req, NULL, &cinfo, 0);
-               } else /* Error or match */
+               } else
                        nfs_release_request(req);
                nfs_unlock_and_release_request(req);
        }
@@ -662,6 +685,7 @@ static void nfs_direct_write_clear_reqs(struct nfs_direct_req *dreq)
        while (!list_empty(&reqs)) {
                req = nfs_list_entry(reqs.next);
                nfs_list_remove_request(req);
+               nfs_direct_truncate_request(dreq, req);
                nfs_release_request(req);
                nfs_unlock_and_release_request(req);
        }
@@ -711,7 +735,8 @@ static void nfs_direct_write_completion(struct nfs_pgio_header *hdr)
        }
 
        nfs_direct_count_bytes(dreq, hdr);
-       if (test_bit(NFS_IOHDR_UNSTABLE_WRITES, &hdr->flags)) {
+       if (test_bit(NFS_IOHDR_UNSTABLE_WRITES, &hdr->flags) &&
+           !test_bit(NFS_IOHDR_ERROR, &hdr->flags)) {
                if (!dreq->flags)
                        dreq->flags = NFS_ODIRECT_DO_COMMIT;
                flags = dreq->flags;
@@ -755,18 +780,23 @@ static void nfs_write_sync_pgio_error(struct list_head *head, int error)
 static void nfs_direct_write_reschedule_io(struct nfs_pgio_header *hdr)
 {
        struct nfs_direct_req *dreq = hdr->dreq;
+       struct nfs_page *req;
+       struct nfs_commit_info cinfo;
 
        trace_nfs_direct_write_reschedule_io(dreq);
 
+       nfs_init_cinfo_from_dreq(&cinfo, dreq);
        spin_lock(&dreq->lock);
-       if (dreq->error == 0) {
+       if (dreq->error == 0)
                dreq->flags = NFS_ODIRECT_RESCHED_WRITES;
-               /* fake unstable write to let common nfs resend pages */
-               hdr->verf.committed = NFS_UNSTABLE;
-               hdr->good_bytes = hdr->args.offset + hdr->args.count -
-                       hdr->io_start;
-       }
+       set_bit(NFS_IOHDR_REDO, &hdr->flags);
        spin_unlock(&dreq->lock);
+       while (!list_empty(&hdr->pages)) {
+               req = nfs_list_entry(hdr->pages.next);
+               nfs_list_remove_request(req);
+               nfs_unlock_request(req);
+               nfs_mark_request_commit(req, NULL, &cinfo, 0);
+       }
 }
 
 static const struct nfs_pgio_completion_ops nfs_direct_write_completion_ops = {
@@ -794,9 +824,11 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
 {
        struct nfs_pageio_descriptor desc;
        struct inode *inode = dreq->inode;
+       struct nfs_commit_info cinfo;
        ssize_t result = 0;
        size_t requested_bytes = 0;
        size_t wsize = max_t(size_t, NFS_SERVER(inode)->wsize, PAGE_SIZE);
+       bool defer = false;
 
        trace_nfs_direct_write_schedule_iovec(dreq);
 
@@ -837,17 +869,37 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
                                break;
                        }
 
-                       nfs_lock_request(req);
-                       if (!nfs_pageio_add_request(&desc, req)) {
-                               result = desc.pg_error;
-                               nfs_unlock_and_release_request(req);
-                               break;
-                       }
                        pgbase = 0;
                        bytes -= req_len;
                        requested_bytes += req_len;
                        pos += req_len;
                        dreq->bytes_left -= req_len;
+
+                       if (defer) {
+                               nfs_mark_request_commit(req, NULL, &cinfo, 0);
+                               continue;
+                       }
+
+                       nfs_lock_request(req);
+                       if (nfs_pageio_add_request(&desc, req))
+                               continue;
+
+                       /* Exit on hard errors */
+                       if (desc.pg_error < 0 && desc.pg_error != -EAGAIN) {
+                               result = desc.pg_error;
+                               nfs_unlock_and_release_request(req);
+                               break;
+                       }
+
+                       /* If the error is soft, defer remaining requests */
+                       nfs_init_cinfo_from_dreq(&cinfo, dreq);
+                       spin_lock(&dreq->lock);
+                       dreq->flags = NFS_ODIRECT_RESCHED_WRITES;
+                       spin_unlock(&dreq->lock);
+                       nfs_unlock_request(req);
+                       nfs_mark_request_commit(req, NULL, &cinfo, 0);
+                       desc.pg_error = 0;
+                       defer = true;
                }
                nfs_direct_release_pages(pagevec, npages);
                kvfree(pagevec);
index 7deb3cd..a1dc338 100644 (file)
@@ -1235,6 +1235,7 @@ static void ff_layout_io_track_ds_error(struct pnfs_layout_segment *lseg,
                case -EPFNOSUPPORT:
                case -EPROTONOSUPPORT:
                case -EOPNOTSUPP:
+               case -EINVAL:
                case -ECONNREFUSED:
                case -ECONNRESET:
                case -EHOSTDOWN:
index 27fb255..11e3a28 100644 (file)
@@ -417,6 +417,8 @@ static void nfs4_add_trunk(struct nfs_client *clp, struct nfs_client *old)
                .net = old->cl_net,
                .servername = old->cl_hostname,
        };
+       int max_connect = test_bit(NFS_CS_PNFS, &clp->cl_flags) ?
+               clp->cl_max_connect : old->cl_max_connect;
 
        if (clp->cl_proto != old->cl_proto)
                return;
@@ -430,7 +432,7 @@ static void nfs4_add_trunk(struct nfs_client *clp, struct nfs_client *old)
        xprt_args.addrlen = clp_salen;
 
        rpc_clnt_add_xprt(old->cl_rpcclient, &xprt_args,
-                         rpc_clnt_test_and_add_xprt, NULL);
+                         rpc_clnt_test_and_add_xprt, &max_connect);
 }
 
 /**
@@ -1010,6 +1012,8 @@ struct nfs_client *nfs4_set_ds_client(struct nfs_server *mds_srv,
                __set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags);
 
        __set_bit(NFS_CS_DS, &cl_init.init_flags);
+       __set_bit(NFS_CS_PNFS, &cl_init.init_flags);
+       cl_init.max_connect = NFS_MAX_TRANSPORTS;
        /*
         * Set an authflavor equual to the MDS value. Use the MDS nfs_client
         * cl_ipaddr so as to use the same EXCHANGE_ID co_ownerid as the MDS
index 7943437..7016eaa 100644 (file)
@@ -2703,8 +2703,12 @@ static int _nfs4_proc_open(struct nfs4_opendata *data,
                        return status;
        }
        if (!(o_res->f_attr->valid & NFS_ATTR_FATTR)) {
+               struct nfs_fh *fh = &o_res->fh;
+
                nfs4_sequence_free_slot(&o_res->seq_res);
-               nfs4_proc_getattr(server, &o_res->fh, o_res->f_attr, NULL);
+               if (o_arg->claim == NFS4_OPEN_CLAIM_FH)
+                       fh = NFS_FH(d_inode(data->dentry));
+               nfs4_proc_getattr(server, fh, o_res->f_attr, NULL);
        }
        return 0;
 }
@@ -10618,7 +10622,9 @@ static void nfs4_disable_swap(struct inode *inode)
         */
        struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
 
-       nfs4_schedule_state_manager(clp);
+       set_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state);
+       clear_bit(NFS4CLNT_MANAGER_AVAILABLE, &clp->cl_state);
+       wake_up_var(&clp->cl_state);
 }
 
 static const struct inode_operations nfs4_dir_inode_operations = {
index e079987..9a5d911 100644 (file)
@@ -1209,16 +1209,26 @@ void nfs4_schedule_state_manager(struct nfs_client *clp)
 {
        struct task_struct *task;
        char buf[INET6_ADDRSTRLEN + sizeof("-manager") + 1];
+       struct rpc_clnt *clnt = clp->cl_rpcclient;
+       bool swapon = false;
 
-       if (clp->cl_rpcclient->cl_shutdown)
+       if (clnt->cl_shutdown)
                return;
 
        set_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state);
-       if (test_and_set_bit(NFS4CLNT_MANAGER_AVAILABLE, &clp->cl_state) != 0) {
-               wake_up_var(&clp->cl_state);
-               return;
+
+       if (atomic_read(&clnt->cl_swapper)) {
+               swapon = !test_and_set_bit(NFS4CLNT_MANAGER_AVAILABLE,
+                                          &clp->cl_state);
+               if (!swapon) {
+                       wake_up_var(&clp->cl_state);
+                       return;
+               }
        }
-       set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state);
+
+       if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0)
+               return;
+
        __module_get(THIS_MODULE);
        refcount_inc(&clp->cl_count);
 
@@ -1235,8 +1245,9 @@ void nfs4_schedule_state_manager(struct nfs_client *clp)
                        __func__, PTR_ERR(task));
                if (!nfs_client_init_is_complete(clp))
                        nfs_mark_client_ready(clp, PTR_ERR(task));
+               if (swapon)
+                       clear_bit(NFS4CLNT_MANAGER_AVAILABLE, &clp->cl_state);
                nfs4_clear_state_manager_bit(clp);
-               clear_bit(NFS4CLNT_MANAGER_AVAILABLE, &clp->cl_state);
                nfs_put_client(clp);
                module_put(THIS_MODULE);
        }
@@ -2703,6 +2714,13 @@ static void nfs4_state_manager(struct nfs_client *clp)
                nfs4_end_drain_session(clp);
                nfs4_clear_state_manager_bit(clp);
 
+               if (test_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state) &&
+                   !test_and_set_bit(NFS4CLNT_MANAGER_RUNNING,
+                                     &clp->cl_state)) {
+                       memflags = memalloc_nofs_save();
+                       continue;
+               }
+
                if (!test_and_set_bit(NFS4CLNT_RECALL_RUNNING, &clp->cl_state)) {
                        if (test_and_clear_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state)) {
                                nfs_client_return_marked_delegations(clp);
@@ -2741,22 +2759,25 @@ static int nfs4_run_state_manager(void *ptr)
 
        allow_signal(SIGKILL);
 again:
-       set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state);
        nfs4_state_manager(clp);
-       if (atomic_read(&cl->cl_swapper)) {
+
+       if (test_bit(NFS4CLNT_MANAGER_AVAILABLE, &clp->cl_state) &&
+           !test_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state)) {
                wait_var_event_interruptible(&clp->cl_state,
                                             test_bit(NFS4CLNT_RUN_MANAGER,
                                                      &clp->cl_state));
-               if (atomic_read(&cl->cl_swapper) &&
-                   test_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state))
+               if (!atomic_read(&cl->cl_swapper))
+                       clear_bit(NFS4CLNT_MANAGER_AVAILABLE, &clp->cl_state);
+               if (refcount_read(&clp->cl_count) > 1 && !signalled() &&
+                   !test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state))
                        goto again;
                /* Either no longer a swapper, or were signalled */
+               clear_bit(NFS4CLNT_MANAGER_AVAILABLE, &clp->cl_state);
        }
-       clear_bit(NFS4CLNT_MANAGER_AVAILABLE, &clp->cl_state);
 
        if (refcount_read(&clp->cl_count) > 1 && !signalled() &&
            test_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state) &&
-           !test_and_set_bit(NFS4CLNT_MANAGER_AVAILABLE, &clp->cl_state))
+           !test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state))
                goto again;
 
        nfs_put_client(clp);
index f4cca8f..7720b5e 100644 (file)
@@ -59,7 +59,8 @@ static const struct nfs_pgio_completion_ops nfs_async_write_completion_ops;
 static const struct nfs_commit_completion_ops nfs_commit_completion_ops;
 static const struct nfs_rw_ops nfs_rw_write_ops;
 static void nfs_inode_remove_request(struct nfs_page *req);
-static void nfs_clear_request_commit(struct nfs_page *req);
+static void nfs_clear_request_commit(struct nfs_commit_info *cinfo,
+                                    struct nfs_page *req);
 static void nfs_init_cinfo_from_inode(struct nfs_commit_info *cinfo,
                                      struct inode *inode);
 static struct nfs_page *
@@ -502,8 +503,8 @@ nfs_destroy_unlinked_subrequests(struct nfs_page *destroy_list,
  * the (former) group.  All subrequests are removed from any write or commit
  * lists, unlinked from the group and destroyed.
  */
-void
-nfs_join_page_group(struct nfs_page *head, struct inode *inode)
+void nfs_join_page_group(struct nfs_page *head, struct nfs_commit_info *cinfo,
+                        struct inode *inode)
 {
        struct nfs_page *subreq;
        struct nfs_page *destroy_list = NULL;
@@ -533,7 +534,7 @@ nfs_join_page_group(struct nfs_page *head, struct inode *inode)
         * Commit list removal accounting is done after locks are dropped */
        subreq = head;
        do {
-               nfs_clear_request_commit(subreq);
+               nfs_clear_request_commit(cinfo, subreq);
                subreq = subreq->wb_this_page;
        } while (subreq != head);
 
@@ -566,8 +567,10 @@ static struct nfs_page *nfs_lock_and_join_requests(struct folio *folio)
 {
        struct inode *inode = folio_file_mapping(folio)->host;
        struct nfs_page *head;
+       struct nfs_commit_info cinfo;
        int ret;
 
+       nfs_init_cinfo_from_inode(&cinfo, inode);
        /*
         * A reference is taken only on the head request which acts as a
         * reference to the whole page group - the group will not be destroyed
@@ -584,7 +587,7 @@ static struct nfs_page *nfs_lock_and_join_requests(struct folio *folio)
                return ERR_PTR(ret);
        }
 
-       nfs_join_page_group(head, inode);
+       nfs_join_page_group(head, &cinfo, inode);
 
        return head;
 }
@@ -799,8 +802,8 @@ static void nfs_inode_remove_request(struct nfs_page *req)
        }
 
        if (test_and_clear_bit(PG_INODE_REF, &req->wb_flags)) {
-               nfs_release_request(req);
                atomic_long_dec(&NFS_I(nfs_page_to_inode(req))->nrequests);
+               nfs_release_request(req);
        }
 }
 
@@ -955,18 +958,16 @@ static void nfs_folio_clear_commit(struct folio *folio)
 }
 
 /* Called holding the request lock on @req */
-static void
-nfs_clear_request_commit(struct nfs_page *req)
+static void nfs_clear_request_commit(struct nfs_commit_info *cinfo,
+                                    struct nfs_page *req)
 {
        if (test_bit(PG_CLEAN, &req->wb_flags)) {
                struct nfs_open_context *ctx = nfs_req_openctx(req);
                struct inode *inode = d_inode(ctx->dentry);
-               struct nfs_commit_info cinfo;
 
-               nfs_init_cinfo_from_inode(&cinfo, inode);
                mutex_lock(&NFS_I(inode)->commit_mutex);
-               if (!pnfs_clear_request_commit(req, &cinfo)) {
-                       nfs_request_remove_commit_list(req, &cinfo);
+               if (!pnfs_clear_request_commit(req, cinfo)) {
+                       nfs_request_remove_commit_list(req, cinfo);
                }
                mutex_unlock(&NFS_I(inode)->commit_mutex);
                nfs_folio_clear_commit(nfs_page_to_folio(req));
index 2e40c74..92c7dde 100644 (file)
@@ -4113,6 +4113,7 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp,
                                 struct file *file, unsigned long maxcount)
 {
        struct xdr_stream *xdr = resp->xdr;
+       unsigned int base = xdr->buf->page_len & ~PAGE_MASK;
        unsigned int starting_len = xdr->buf->len;
        __be32 zero = xdr_zero;
        __be32 nfserr;
@@ -4121,8 +4122,7 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp,
                return nfserr_resource;
 
        nfserr = nfsd_iter_read(resp->rqstp, read->rd_fhp, file,
-                               read->rd_offset, &maxcount,
-                               xdr->buf->page_len & ~PAGE_MASK,
+                               read->rd_offset, &maxcount, base,
                                &read->rd_eof);
        read->rd_length = maxcount;
        if (nfserr)
index 48fe71d..8beb273 100644 (file)
@@ -73,10 +73,8 @@ int nilfs_gccache_submit_read_data(struct inode *inode, sector_t blkoff,
                struct the_nilfs *nilfs = inode->i_sb->s_fs_info;
 
                err = nilfs_dat_translate(nilfs->ns_dat, vbn, &pbn);
-               if (unlikely(err)) { /* -EIO, -ENOMEM, -ENOENT */
-                       brelse(bh);
+               if (unlikely(err)) /* -EIO, -ENOMEM, -ENOENT */
                        goto failed;
-               }
        }
 
        lock_buffer(bh);
@@ -102,6 +100,8 @@ int nilfs_gccache_submit_read_data(struct inode *inode, sector_t blkoff,
  failed:
        unlock_page(bh->b_page);
        put_page(bh->b_page);
+       if (unlikely(err))
+               brelse(bh);
        return err;
 }
 
index cfec5e0..5661a36 100644 (file)
@@ -1562,6 +1562,7 @@ load_root:
 put_inode_out:
        iput(inode);
 out:
+       ntfs3_put_sbi(sbi);
        kfree(boot2);
        return err;
 }
index d1761ec..ada3fcc 100644 (file)
@@ -337,7 +337,7 @@ static int ovl_set_timestamps(struct ovl_fs *ofs, struct dentry *upperdentry,
 {
        struct iattr attr = {
                .ia_valid =
-                    ATTR_ATIME | ATTR_MTIME | ATTR_ATIME_SET | ATTR_MTIME_SET,
+                    ATTR_ATIME | ATTR_MTIME | ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_CTIME,
                .ia_atime = stat->atime,
                .ia_mtime = stat->mtime,
        };
index c8c8588..26b782c 100644 (file)
@@ -188,7 +188,7 @@ static int ovl_check_encode_origin(struct dentry *dentry)
 
        /* Lower file handle for non-upper non-decodable */
        if (!ovl_dentry_upper(dentry) && !decodable)
-               return 0;
+               return 1;
 
        /* Upper file handle for pure upper */
        if (!ovl_dentry_lower(dentry))
index 4193633..8be4dc0 100644 (file)
@@ -341,7 +341,6 @@ static ssize_t ovl_read_iter(struct kiocb *iocb, struct iov_iter *iter)
                if (!aio_req)
                        goto out;
 
-               real.flags = 0;
                aio_req->orig_iocb = iocb;
                kiocb_clone(&aio_req->iocb, iocb, get_file(real.file));
                aio_req->iocb.ki_complete = ovl_aio_rw_complete;
@@ -391,6 +390,12 @@ static ssize_t ovl_write_iter(struct kiocb *iocb, struct iov_iter *iter)
        if (!ovl_should_sync(OVL_FS(inode->i_sb)))
                ifl &= ~(IOCB_DSYNC | IOCB_SYNC);
 
+       /*
+        * Overlayfs doesn't support deferred completions, don't copy
+        * this property in case it is set by the issuer.
+        */
+       ifl &= ~IOCB_DIO_CALLER_COMP;
+
        old_cred = ovl_override_creds(file_inode(file)->i_sb);
        if (is_sync_kiocb(iocb)) {
                file_start_write(real.file);
@@ -407,7 +412,6 @@ static ssize_t ovl_write_iter(struct kiocb *iocb, struct iov_iter *iter)
                if (!aio_req)
                        goto out;
 
-               real.flags = 0;
                aio_req->orig_iocb = iocb;
                kiocb_clone(&aio_req->iocb, iocb, get_file(real.file));
                aio_req->iocb.ki_flags = ifl;
index e9539f9..d82d2a0 100644 (file)
@@ -8,6 +8,7 @@
 struct ovl_config {
        char *upperdir;
        char *workdir;
+       char **lowerdirs;
        bool default_permissions;
        int redirect_mode;
        int verity_mode;
@@ -39,17 +40,8 @@ struct ovl_layer {
        int idx;
        /* One fsid per unique underlying sb (upper fsid == 0) */
        int fsid;
-       char *name;
 };
 
-/*
- * ovl_free_fs() relies on @mnt being the first member when unmounting
- * the private mounts created for each layer. Let's check both the
- * offset and type.
- */
-static_assert(offsetof(struct ovl_layer, mnt) == 0);
-static_assert(__same_type(typeof_member(struct ovl_layer, mnt), struct vfsmount *));
-
 struct ovl_path {
        const struct ovl_layer *layer;
        struct dentry *dentry;
index b9355bb..95b7515 100644 (file)
@@ -752,12 +752,12 @@ void ovl_free_fs(struct ovl_fs *ofs)
        if (ofs->upperdir_locked)
                ovl_inuse_unlock(ovl_upper_mnt(ofs)->mnt_root);
 
-       /* Hack!  Reuse ofs->layers as a vfsmount array before freeing it */
-       mounts = (struct vfsmount **) ofs->layers;
+       /* Reuse ofs->config.lowerdirs as a vfsmount array before freeing it */
+       mounts = (struct vfsmount **) ofs->config.lowerdirs;
        for (i = 0; i < ofs->numlayer; i++) {
                iput(ofs->layers[i].trap);
+               kfree(ofs->config.lowerdirs[i]);
                mounts[i] = ofs->layers[i].mnt;
-               kfree(ofs->layers[i].name);
        }
        kern_unmount_array(mounts, ofs->numlayer);
        kfree(ofs->layers);
@@ -765,6 +765,7 @@ void ovl_free_fs(struct ovl_fs *ofs)
                free_anon_bdev(ofs->fs[i].pseudo_dev);
        kfree(ofs->fs);
 
+       kfree(ofs->config.lowerdirs);
        kfree(ofs->config.upperdir);
        kfree(ofs->config.workdir);
        if (ofs->creator_cred)
@@ -949,16 +950,16 @@ int ovl_show_options(struct seq_file *m, struct dentry *dentry)
        struct super_block *sb = dentry->d_sb;
        struct ovl_fs *ofs = OVL_FS(sb);
        size_t nr, nr_merged_lower = ofs->numlayer - ofs->numdatalayer;
-       const struct ovl_layer *data_layers = &ofs->layers[nr_merged_lower];
+       char **lowerdatadirs = &ofs->config.lowerdirs[nr_merged_lower];
 
-       /* ofs->layers[0] is the upper layer */
-       seq_printf(m, ",lowerdir=%s", ofs->layers[1].name);
+       /* lowerdirs[] starts from offset 1 */
+       seq_printf(m, ",lowerdir=%s", ofs->config.lowerdirs[1]);
        /* dump regular lower layers */
        for (nr = 2; nr < nr_merged_lower; nr++)
-               seq_printf(m, ":%s", ofs->layers[nr].name);
+               seq_printf(m, ":%s", ofs->config.lowerdirs[nr]);
        /* dump data lower layers */
        for (nr = 0; nr < ofs->numdatalayer; nr++)
-               seq_printf(m, "::%s", data_layers[nr].name);
+               seq_printf(m, "::%s", lowerdatadirs[nr]);
        if (ofs->config.upperdir) {
                seq_show_option(m, "upperdir", ofs->config.upperdir);
                seq_show_option(m, "workdir", ofs->config.workdir);
index def266b..3fa2416 100644 (file)
@@ -104,8 +104,8 @@ static int ovl_revalidate_real(struct dentry *d, unsigned int flags, bool weak)
 static int ovl_dentry_revalidate_common(struct dentry *dentry,
                                        unsigned int flags, bool weak)
 {
-       struct ovl_entry *oe = OVL_E(dentry);
-       struct ovl_path *lowerstack = ovl_lowerstack(oe);
+       struct ovl_entry *oe;
+       struct ovl_path *lowerstack;
        struct inode *inode = d_inode_rcu(dentry);
        struct dentry *upper;
        unsigned int i;
@@ -115,6 +115,8 @@ static int ovl_dentry_revalidate_common(struct dentry *dentry,
        if (!inode)
                return -ECHILD;
 
+       oe = OVL_I_E(inode);
+       lowerstack = ovl_lowerstack(oe);
        upper = ovl_i_dentry_upper(inode);
        if (upper)
                ret = ovl_revalidate_real(upper, flags, weak);
@@ -167,6 +169,7 @@ static void ovl_free_inode(struct inode *inode)
        struct ovl_inode *oi = OVL_I(inode);
 
        kfree(oi->redirect);
+       kfree(oi->oe);
        mutex_destroy(&oi->lock);
        kmem_cache_free(ovl_inode_cachep, oi);
 }
@@ -176,7 +179,7 @@ static void ovl_destroy_inode(struct inode *inode)
        struct ovl_inode *oi = OVL_I(inode);
 
        dput(oi->__upperdentry);
-       ovl_free_entry(oi->oe);
+       ovl_stack_put(ovl_lowerstack(oi->oe), ovl_numlower(oi->oe));
        if (S_ISDIR(inode->i_mode))
                ovl_dir_cache_free(inode);
        else
@@ -569,11 +572,6 @@ static int ovl_get_upper(struct super_block *sb, struct ovl_fs *ofs,
        upper_layer->idx = 0;
        upper_layer->fsid = 0;
 
-       err = -ENOMEM;
-       upper_layer->name = kstrdup(ofs->config.upperdir, GFP_KERNEL);
-       if (!upper_layer->name)
-               goto out;
-
        /*
         * Inherit SB_NOSEC flag from upperdir.
         *
@@ -1122,7 +1120,8 @@ static int ovl_get_layers(struct super_block *sb, struct ovl_fs *ofs,
                layers[ofs->numlayer].idx = ofs->numlayer;
                layers[ofs->numlayer].fsid = fsid;
                layers[ofs->numlayer].fs = &ofs->fs[fsid];
-               layers[ofs->numlayer].name = l->name;
+               /* Store for printing lowerdir=... in ovl_show_options() */
+               ofs->config.lowerdirs[ofs->numlayer] = l->name;
                l->name = NULL;
                ofs->numlayer++;
                ofs->fs[fsid].is_lower = true;
@@ -1367,8 +1366,16 @@ int ovl_fill_super(struct super_block *sb, struct fs_context *fc)
        if (!layers)
                goto out_err;
 
+       ofs->config.lowerdirs = kcalloc(ctx->nr + 1, sizeof(char *), GFP_KERNEL);
+       if (!ofs->config.lowerdirs) {
+               kfree(layers);
+               goto out_err;
+       }
        ofs->layers = layers;
-       /* Layer 0 is reserved for upper even if there's no upper */
+       /*
+        * Layer 0 is reserved for upper even if there's no upper.
+        * For consistency, config.lowerdirs[0] is NULL.
+        */
        ofs->numlayer = 1;
 
        sb->s_stack_depth = 0;
index 6c1a9b1..1391901 100644 (file)
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -537,7 +537,6 @@ pipe_write(struct kiocb *iocb, struct iov_iter *from)
                                break;
                        }
                        ret += copied;
-                       buf->offset = 0;
                        buf->len = copied;
 
                        if (!iov_iter_count(from))
index 9dda7e5..9a8f32f 100644 (file)
@@ -289,9 +289,7 @@ struct proc_maps_private {
        struct inode *inode;
        struct task_struct *task;
        struct mm_struct *mm;
-#ifdef CONFIG_MMU
        struct vma_iterator iter;
-#endif
 #ifdef CONFIG_NUMA
        struct mempolicy *task_mempolicy;
 #endif
index a8ac0dd..7cebd39 100644 (file)
@@ -175,15 +175,28 @@ static int show_map(struct seq_file *m, void *_p)
        return nommu_vma_show(m, _p);
 }
 
-static void *m_start(struct seq_file *m, loff_t *pos)
+static struct vm_area_struct *proc_get_vma(struct proc_maps_private *priv,
+                                               loff_t *ppos)
+{
+       struct vm_area_struct *vma = vma_next(&priv->iter);
+
+       if (vma) {
+               *ppos = vma->vm_start;
+       } else {
+               *ppos = -1UL;
+       }
+
+       return vma;
+}
+
+static void *m_start(struct seq_file *m, loff_t *ppos)
 {
        struct proc_maps_private *priv = m->private;
+       unsigned long last_addr = *ppos;
        struct mm_struct *mm;
-       struct vm_area_struct *vma;
-       unsigned long addr = *pos;
 
-       /* See m_next(). Zero at the start or after lseek. */
-       if (addr == -1UL)
+       /* See proc_get_vma(). Zero at the start or after lseek. */
+       if (last_addr == -1UL)
                return NULL;
 
        /* pin the task and mm whilst we play with them */
@@ -192,44 +205,41 @@ static void *m_start(struct seq_file *m, loff_t *pos)
                return ERR_PTR(-ESRCH);
 
        mm = priv->mm;
-       if (!mm || !mmget_not_zero(mm))
+       if (!mm || !mmget_not_zero(mm)) {
+               put_task_struct(priv->task);
+               priv->task = NULL;
                return NULL;
+       }
 
        if (mmap_read_lock_killable(mm)) {
                mmput(mm);
+               put_task_struct(priv->task);
+               priv->task = NULL;
                return ERR_PTR(-EINTR);
        }
 
-       /* start the next element from addr */
-       vma = find_vma(mm, addr);
-       if (vma)
-               return vma;
+       vma_iter_init(&priv->iter, mm, last_addr);
 
-       mmap_read_unlock(mm);
-       mmput(mm);
-       return NULL;
+       return proc_get_vma(priv, ppos);
 }
 
-static void m_stop(struct seq_file *m, void *_vml)
+static void m_stop(struct seq_file *m, void *v)
 {
        struct proc_maps_private *priv = m->private;
+       struct mm_struct *mm = priv->mm;
 
-       if (!IS_ERR_OR_NULL(_vml)) {
-               mmap_read_unlock(priv->mm);
-               mmput(priv->mm);
-       }
-       if (priv->task) {
-               put_task_struct(priv->task);
-               priv->task = NULL;
-       }
+       if (!priv->task)
+               return;
+
+       mmap_read_unlock(mm);
+       mmput(mm);
+       put_task_struct(priv->task);
+       priv->task = NULL;
 }
 
-static void *m_next(struct seq_file *m, void *_p, loff_t *pos)
+static void *m_next(struct seq_file *m, void *_p, loff_t *ppos)
 {
-       struct vm_area_struct *vma = _p;
-
-       *pos = vma->vm_end;
-       return find_vma(vma->vm_mm, vma->vm_end);
+       return proc_get_vma(m->private, ppos);
 }
 
 static const struct seq_operations proc_pid_maps_ops = {
index 9e72bfe..31e897a 100644 (file)
@@ -233,19 +233,18 @@ static void put_quota_format(struct quota_format_type *fmt)
  * All dquots are placed to the end of inuse_list when first created, and this
  * list is used for invalidate operation, which must look at every dquot.
  *
- * When the last reference of a dquot will be dropped, the dquot will be
- * added to releasing_dquots. We'd then queue work item which would call
+ * When the last reference of a dquot is dropped, the dquot is added to
+ * releasing_dquots. We'll then queue work item which will call
  * synchronize_srcu() and after that perform the final cleanup of all the
- * dquots on the list. Both releasing_dquots and free_dquots use the
- * dq_free list_head in the dquot struct. When a dquot is removed from
- * releasing_dquots, a reference count is always subtracted, and if
- * dq_count == 0 at that point, the dquot will be added to the free_dquots.
+ * dquots on the list. Each cleaned up dquot is moved to free_dquots list.
+ * Both releasing_dquots and free_dquots use the dq_free list_head in the dquot
+ * struct.
  *
- * Unused dquots (dq_count == 0) are added to the free_dquots list when freed,
- * and this list is searched whenever we need an available dquot.  Dquots are
- * removed from the list as soon as they are used again, and
- * dqstats.free_dquots gives the number of dquots on the list. When
- * dquot is invalidated it's completely released from memory.
+ * Unused and cleaned up dquots are in the free_dquots list and this list is
+ * searched whenever we need an available dquot. Dquots are removed from the
+ * list as soon as they are used again and dqstats.free_dquots gives the number
+ * of dquots on the list. When dquot is invalidated it's completely released
+ * from memory.
  *
  * Dirty dquots are added to the dqi_dirty_list of quota_info when mark
  * dirtied, and this list is searched when writing dirty dquots back to
@@ -321,6 +320,7 @@ static inline void put_dquot_last(struct dquot *dquot)
 static inline void put_releasing_dquots(struct dquot *dquot)
 {
        list_add_tail(&dquot->dq_free, &releasing_dquots);
+       set_bit(DQ_RELEASING_B, &dquot->dq_flags);
 }
 
 static inline void remove_free_dquot(struct dquot *dquot)
@@ -328,8 +328,10 @@ static inline void remove_free_dquot(struct dquot *dquot)
        if (list_empty(&dquot->dq_free))
                return;
        list_del_init(&dquot->dq_free);
-       if (!atomic_read(&dquot->dq_count))
+       if (!test_bit(DQ_RELEASING_B, &dquot->dq_flags))
                dqstats_dec(DQST_FREE_DQUOTS);
+       else
+               clear_bit(DQ_RELEASING_B, &dquot->dq_flags);
 }
 
 static inline void put_inuse(struct dquot *dquot)
@@ -581,12 +583,6 @@ restart:
                        continue;
                /* Wait for dquot users */
                if (atomic_read(&dquot->dq_count)) {
-                       /* dquot in releasing_dquots, flush and retry */
-                       if (!list_empty(&dquot->dq_free)) {
-                               spin_unlock(&dq_list_lock);
-                               goto restart;
-                       }
-
                        atomic_inc(&dquot->dq_count);
                        spin_unlock(&dq_list_lock);
                        /*
@@ -606,6 +602,15 @@ restart:
                        goto restart;
                }
                /*
+                * The last user already dropped its reference but dquot didn't
+                * get fully cleaned up yet. Restart the scan which flushes the
+                * work cleaning up released dquots.
+                */
+               if (test_bit(DQ_RELEASING_B, &dquot->dq_flags)) {
+                       spin_unlock(&dq_list_lock);
+                       goto restart;
+               }
+               /*
                 * Quota now has no users and it has been written on last
                 * dqput()
                 */
@@ -696,6 +701,13 @@ int dquot_writeback_dquots(struct super_block *sb, int type)
                                                 dq_dirty);
 
                        WARN_ON(!dquot_active(dquot));
+                       /* If the dquot is releasing we should not touch it */
+                       if (test_bit(DQ_RELEASING_B, &dquot->dq_flags)) {
+                               spin_unlock(&dq_list_lock);
+                               flush_delayed_work(&quota_release_work);
+                               spin_lock(&dq_list_lock);
+                               continue;
+                       }
 
                        /* Now we have active dquot from which someone is
                         * holding reference so we can safely just increase
@@ -809,18 +821,18 @@ static void quota_release_workfn(struct work_struct *work)
        /* Exchange the list head to avoid livelock. */
        list_replace_init(&releasing_dquots, &rls_head);
        spin_unlock(&dq_list_lock);
+       synchronize_srcu(&dquot_srcu);
 
 restart:
-       synchronize_srcu(&dquot_srcu);
        spin_lock(&dq_list_lock);
        while (!list_empty(&rls_head)) {
                dquot = list_first_entry(&rls_head, struct dquot, dq_free);
-               /* Dquot got used again? */
-               if (atomic_read(&dquot->dq_count) > 1) {
-                       remove_free_dquot(dquot);
-                       atomic_dec(&dquot->dq_count);
-                       continue;
-               }
+               WARN_ON_ONCE(atomic_read(&dquot->dq_count));
+               /*
+                * Note that DQ_RELEASING_B protects us from racing with
+                * invalidate_dquots() calls so we are safe to work with the
+                * dquot even after we drop dq_list_lock.
+                */
                if (dquot_dirty(dquot)) {
                        spin_unlock(&dq_list_lock);
                        /* Commit dquot before releasing */
@@ -834,7 +846,6 @@ restart:
                }
                /* Dquot is inactive and clean, now move it to free list */
                remove_free_dquot(dquot);
-               atomic_dec(&dquot->dq_count);
                put_dquot_last(dquot);
        }
        spin_unlock(&dq_list_lock);
@@ -875,6 +886,7 @@ void dqput(struct dquot *dquot)
        BUG_ON(!list_empty(&dquot->dq_free));
 #endif
        put_releasing_dquots(dquot);
+       atomic_dec(&dquot->dq_count);
        spin_unlock(&dq_list_lock);
        queue_delayed_work(system_unbound_wq, &quota_release_work, 1);
 }
@@ -963,7 +975,7 @@ we_slept:
                dqstats_inc(DQST_LOOKUPS);
        }
        /* Wait for dq_lock - after this we know that either dquot_release() is
-        * already finished or it will be canceled due to dq_count > 1 test */
+        * already finished or it will be canceled due to dq_count > 0 test */
        wait_on_dquot(dquot);
        /* Read the dquot / allocate space in quota file */
        if (!dquot_active(dquot)) {
index b817494..7d12b8c 100644 (file)
@@ -2699,7 +2699,7 @@ struct reiserfs_iget_args {
 #define get_journal_desc_magic(bh) (bh->b_data + bh->b_size - 12)
 
 #define journal_trans_half(blocksize) \
-       ((blocksize - sizeof (struct reiserfs_journal_desc) + sizeof (__u32) - 12) / sizeof (__u32))
+       ((blocksize - sizeof(struct reiserfs_journal_desc) - 12) / sizeof(__u32))
 
 /* journal.c see journal.c for all the comments here */
 
@@ -2711,7 +2711,7 @@ struct reiserfs_journal_desc {
        __le32 j_len;
 
        __le32 j_mount_id;      /* mount id of this trans */
-       __le32 j_realblock[1];  /* real locations for each block */
+       __le32 j_realblock[];   /* real locations for each block */
 };
 
 #define get_desc_trans_id(d)   le32_to_cpu((d)->j_trans_id)
@@ -2726,7 +2726,7 @@ struct reiserfs_journal_desc {
 struct reiserfs_journal_commit {
        __le32 j_trans_id;      /* must match j_trans_id from the desc block */
        __le32 j_len;           /* ditto */
-       __le32 j_realblock[1];  /* real locations for each block */
+       __le32 j_realblock[];   /* real locations for each block */
 };
 
 #define get_commit_trans_id(c) le32_to_cpu((c)->j_trans_id)
index b17f067..e2be8ae 100644 (file)
@@ -452,6 +452,9 @@ void invalidate_all_cached_dirs(struct cifs_tcon *tcon)
        struct cached_fid *cfid, *q;
        LIST_HEAD(entry);
 
+       if (cfids == NULL)
+               return;
+
        spin_lock(&cfids->cfid_list_lock);
        list_for_each_entry_safe(cfid, q, &cfids->entries, entry) {
                list_move(&cfid->entry, &entry);
@@ -651,6 +654,9 @@ void free_cached_dirs(struct cached_fids *cfids)
        struct cached_fid *cfid, *q;
        LIST_HEAD(entry);
 
+       if (cfids == NULL)
+               return;
+
        if (cfids->laundromat) {
                kthread_stop(cfids->laundromat);
                cfids->laundromat = NULL;
index 032d871..0208262 100644 (file)
@@ -1807,6 +1807,7 @@ static inline bool is_retryable_error(int error)
 #define   MID_RETRY_NEEDED      8 /* session closed while this request out */
 #define   MID_RESPONSE_MALFORMED 0x10
 #define   MID_SHUTDOWN          0x20
+#define   MID_RESPONSE_READY 0x40 /* ready for other process handle the rsp */
 
 /* Flags */
 #define   MID_WAIT_CANCELLED    1 /* Cancelled while waiting for response */
@@ -1943,7 +1944,7 @@ require use of the stronger protocol */
  * cifsInodeInfo->lock_sem     cifsInodeInfo->llist            cifs_init_once
  *                             ->can_cache_brlcks
  * cifsInodeInfo->deferred_lock        cifsInodeInfo->deferred_closes  cifsInodeInfo_alloc
- * cached_fid->fid_mutex               cifs_tcon->crfid                tconInfoAlloc
+ * cached_fid->fid_mutex               cifs_tcon->crfid                tcon_info_alloc
  * cifsFileInfo->fh_mutex              cifsFileInfo                    cifs_new_fileinfo
  * cifsFileInfo->file_info_lock        cifsFileInfo->count             cifs_new_fileinfo
  *                             ->invalidHandle                 initiate_cifs_search
index 7d80358..0c37eef 100644 (file)
@@ -512,7 +512,7 @@ extern int CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses);
 
 extern struct cifs_ses *sesInfoAlloc(void);
 extern void sesInfoFree(struct cifs_ses *);
-extern struct cifs_tcon *tconInfoAlloc(void);
+extern struct cifs_tcon *tcon_info_alloc(bool dir_leases_enabled);
 extern void tconInfoFree(struct cifs_tcon *);
 
 extern int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server,
index 6877547..7b923e3 100644 (file)
@@ -1882,7 +1882,8 @@ cifs_setup_ipc(struct cifs_ses *ses, struct smb3_fs_context *ctx)
                }
        }
 
-       tcon = tconInfoAlloc();
+       /* no need to setup directory caching on IPC share, so pass in false */
+       tcon = tcon_info_alloc(false);
        if (tcon == NULL)
                return -ENOMEM;
 
@@ -2473,8 +2474,9 @@ cifs_put_tcon(struct cifs_tcon *tcon)
 static struct cifs_tcon *
 cifs_get_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx)
 {
-       int rc, xid;
        struct cifs_tcon *tcon;
+       bool nohandlecache;
+       int rc, xid;
 
        tcon = cifs_find_tcon(ses, ctx);
        if (tcon) {
@@ -2492,11 +2494,17 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx)
                goto out_fail;
        }
 
-       tcon = tconInfoAlloc();
+       if (ses->server->dialect >= SMB20_PROT_ID &&
+           (ses->server->capabilities & SMB2_GLOBAL_CAP_DIRECTORY_LEASING))
+               nohandlecache = ctx->nohandlecache;
+       else
+               nohandlecache = true;
+       tcon = tcon_info_alloc(!nohandlecache);
        if (tcon == NULL) {
                rc = -ENOMEM;
                goto out_fail;
        }
+       tcon->nohandlecache = nohandlecache;
 
        if (ctx->snapshot_time) {
                if (ses->server->vals->protocol_id == 0) {
@@ -2658,10 +2666,6 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx)
        tcon->nocase = ctx->nocase;
        tcon->broken_sparse_sup = ctx->no_sparse;
        tcon->max_cached_dirs = ctx->max_cached_dirs;
-       if (ses->server->capabilities & SMB2_GLOBAL_CAP_DIRECTORY_LEASING)
-               tcon->nohandlecache = ctx->nohandlecache;
-       else
-               tcon->nohandlecache = true;
        tcon->nodelete = ctx->nodelete;
        tcon->local_lease = ctx->local_lease;
        INIT_LIST_HEAD(&tcon->pending_opens);
@@ -2891,9 +2895,9 @@ bind_socket(struct TCP_Server_Info *server)
        if (server->srcaddr.ss_family != AF_UNSPEC) {
                /* Bind to the specified local IP address */
                struct socket *socket = server->ssocket;
-               rc = socket->ops->bind(socket,
-                                      (struct sockaddr *) &server->srcaddr,
-                                      sizeof(server->srcaddr));
+               rc = kernel_bind(socket,
+                                (struct sockaddr *) &server->srcaddr,
+                                sizeof(server->srcaddr));
                if (rc < 0) {
                        struct sockaddr_in *saddr4;
                        struct sockaddr_in6 *saddr6;
@@ -3042,8 +3046,8 @@ generic_ip_connect(struct TCP_Server_Info *server)
                 socket->sk->sk_sndbuf,
                 socket->sk->sk_rcvbuf, socket->sk->sk_rcvtimeo);
 
-       rc = socket->ops->connect(socket, saddr, slen,
-                                 server->noblockcnt ? O_NONBLOCK : 0);
+       rc = kernel_connect(socket, saddr, slen,
+                           server->noblockcnt ? O_NONBLOCK : 0);
        /*
         * When mounting SMB root file systems, we do not want to block in
         * connect. Otherwise bail out and then let cifs_reconnect() perform
index e45ce31..a3493da 100644 (file)
@@ -1541,6 +1541,7 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
 
  cifs_parse_mount_err:
        kfree_sensitive(ctx->password);
+       ctx->password = NULL;
        return -EINVAL;
 }
 
index 366b755..35b1764 100644 (file)
@@ -113,18 +113,22 @@ sesInfoFree(struct cifs_ses *buf_to_free)
 }
 
 struct cifs_tcon *
-tconInfoAlloc(void)
+tcon_info_alloc(bool dir_leases_enabled)
 {
        struct cifs_tcon *ret_buf;
 
        ret_buf = kzalloc(sizeof(*ret_buf), GFP_KERNEL);
        if (!ret_buf)
                return NULL;
-       ret_buf->cfids = init_cached_dirs();
-       if (!ret_buf->cfids) {
-               kfree(ret_buf);
-               return NULL;
+
+       if (dir_leases_enabled == true) {
+               ret_buf->cfids = init_cached_dirs();
+               if (!ret_buf->cfids) {
+                       kfree(ret_buf);
+                       return NULL;
+               }
        }
+       /* else ret_buf->cfids is already set to NULL above */
 
        atomic_inc(&tconInfoAllocCount);
        ret_buf->status = TID_NEW;
index b41e2e8..0b89f70 100644 (file)
@@ -539,6 +539,9 @@ static int parse_create_response(struct cifs_open_info_data *data,
        int rc = 0;
 
        switch (rsp->hdr.Status) {
+       case STATUS_IO_REPARSE_TAG_NOT_HANDLED:
+               reparse_point = true;
+               break;
        case STATUS_STOPPED_ON_SYMLINK:
                rc = smb2_parse_symlink_response(cifs_sb, iov,
                                                 &data->symlink_target);
index 194799d..1a90dd7 100644 (file)
@@ -877,8 +877,6 @@ static const struct status_to_posix_error smb2_error_map_table[] = {
        "STATUS_IO_REPARSE_TAG_MISMATCH"},
        {STATUS_IO_REPARSE_DATA_INVALID, -EIO,
        "STATUS_IO_REPARSE_DATA_INVALID"},
-       {STATUS_IO_REPARSE_TAG_NOT_HANDLED, -EIO,
-       "STATUS_IO_REPARSE_TAG_NOT_HANDLED"},
        {STATUS_REPARSE_POINT_NOT_RESOLVED, -EIO,
        "STATUS_REPARSE_POINT_NOT_RESOLVED"},
        {STATUS_DIRECTORY_IS_A_REPARSE_POINT, -EIO,
index 44d4943..c75a80b 100644 (file)
@@ -848,7 +848,7 @@ add_posix_context(struct kvec *iov, unsigned int *num_iovec, umode_t mode)
 
        iov[num].iov_base = create_posix_buf(mode);
        if (mode == ACL_NO_MODE)
-               cifs_dbg(FYI, "Invalid mode\n");
+               cifs_dbg(FYI, "%s: no mode\n", __func__);
        if (iov[num].iov_base == NULL)
                return -ENOMEM;
        iov[num].iov_len = sizeof(struct create_posix);
@@ -3878,7 +3878,7 @@ void smb2_reconnect_server(struct work_struct *work)
                goto done;
 
        /* allocate a dummy tcon struct used for reconnect */
-       tcon = tconInfoAlloc();
+       tcon = tcon_info_alloc(false);
        if (!tcon) {
                resched = true;
                list_for_each_entry_safe(ses, ses2, &tmp_ses_list, rlist) {
index 2a2aec8..94df9ee 100644 (file)
@@ -1401,10 +1401,13 @@ create_conn:
        server->smbd_conn = smbd_get_connection(
                server, (struct sockaddr *) &server->dstaddr);
 
-       if (server->smbd_conn)
+       if (server->smbd_conn) {
                cifs_dbg(VFS, "RDMA transport re-established\n");
-
-       return server->smbd_conn ? 0 : -ENOENT;
+               trace_smb3_smbd_connect_done(server->hostname, server->conn_id, &server->dstaddr);
+               return 0;
+       }
+       trace_smb3_smbd_connect_err(server->hostname, server->conn_id, &server->dstaddr);
+       return -ENOENT;
 }
 
 static void destroy_caches_and_workqueue(struct smbd_connection *info)
index a7e4755..de199ec 100644 (file)
@@ -935,6 +935,8 @@ DEFINE_EVENT(smb3_connect_class, smb3_##name,  \
        TP_ARGS(hostname, conn_id, addr))
 
 DEFINE_SMB3_CONNECT_EVENT(connect_done);
+DEFINE_SMB3_CONNECT_EVENT(smbd_connect_done);
+DEFINE_SMB3_CONNECT_EVENT(smbd_connect_err);
 
 DECLARE_EVENT_CLASS(smb3_connect_err_class,
        TP_PROTO(char *hostname, __u64 conn_id,
index d52057a..14710af 100644 (file)
@@ -35,6 +35,8 @@
 void
 cifs_wake_up_task(struct mid_q_entry *mid)
 {
+       if (mid->mid_state == MID_RESPONSE_RECEIVED)
+               mid->mid_state = MID_RESPONSE_READY;
        wake_up_process(mid->callback_data);
 }
 
@@ -87,7 +89,8 @@ static void __release_mid(struct kref *refcount)
        struct TCP_Server_Info *server = midEntry->server;
 
        if (midEntry->resp_buf && (midEntry->mid_flags & MID_WAIT_CANCELLED) &&
-           midEntry->mid_state == MID_RESPONSE_RECEIVED &&
+           (midEntry->mid_state == MID_RESPONSE_RECEIVED ||
+            midEntry->mid_state == MID_RESPONSE_READY) &&
            server->ops->handle_cancelled_mid)
                server->ops->handle_cancelled_mid(midEntry, server);
 
@@ -737,7 +740,8 @@ wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ)
        int error;
 
        error = wait_event_state(server->response_q,
-                                midQ->mid_state != MID_REQUEST_SUBMITTED,
+                                midQ->mid_state != MID_REQUEST_SUBMITTED &&
+                                midQ->mid_state != MID_RESPONSE_RECEIVED,
                                 (TASK_KILLABLE|TASK_FREEZABLE_UNSAFE));
        if (error < 0)
                return -ERESTARTSYS;
@@ -890,7 +894,7 @@ cifs_sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server)
 
        spin_lock(&server->mid_lock);
        switch (mid->mid_state) {
-       case MID_RESPONSE_RECEIVED:
+       case MID_RESPONSE_READY:
                spin_unlock(&server->mid_lock);
                return rc;
        case MID_RETRY_NEEDED:
@@ -989,6 +993,9 @@ cifs_compound_callback(struct mid_q_entry *mid)
        credits.instance = server->reconnect_instance;
 
        add_credits(server, &credits, mid->optype);
+
+       if (mid->mid_state == MID_RESPONSE_RECEIVED)
+               mid->mid_state = MID_RESPONSE_READY;
 }
 
 static void
@@ -1209,7 +1216,8 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
                        send_cancel(server, &rqst[i], midQ[i]);
                        spin_lock(&server->mid_lock);
                        midQ[i]->mid_flags |= MID_WAIT_CANCELLED;
-                       if (midQ[i]->mid_state == MID_REQUEST_SUBMITTED) {
+                       if (midQ[i]->mid_state == MID_REQUEST_SUBMITTED ||
+                           midQ[i]->mid_state == MID_RESPONSE_RECEIVED) {
                                midQ[i]->callback = cifs_cancelled_callback;
                                cancelled_mid[i] = true;
                                credits[i].value = 0;
@@ -1230,7 +1238,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
                }
 
                if (!midQ[i]->resp_buf ||
-                   midQ[i]->mid_state != MID_RESPONSE_RECEIVED) {
+                   midQ[i]->mid_state != MID_RESPONSE_READY) {
                        rc = -EIO;
                        cifs_dbg(FYI, "Bad MID state?\n");
                        goto out;
@@ -1417,7 +1425,8 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
        if (rc != 0) {
                send_cancel(server, &rqst, midQ);
                spin_lock(&server->mid_lock);
-               if (midQ->mid_state == MID_REQUEST_SUBMITTED) {
+               if (midQ->mid_state == MID_REQUEST_SUBMITTED ||
+                   midQ->mid_state == MID_RESPONSE_RECEIVED) {
                        /* no longer considered to be "in-flight" */
                        midQ->callback = release_mid;
                        spin_unlock(&server->mid_lock);
@@ -1434,7 +1443,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
        }
 
        if (!midQ->resp_buf || !out_buf ||
-           midQ->mid_state != MID_RESPONSE_RECEIVED) {
+           midQ->mid_state != MID_RESPONSE_READY) {
                rc = -EIO;
                cifs_server_dbg(VFS, "Bad MID state?\n");
                goto out;
@@ -1558,14 +1567,16 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 
        /* Wait for a reply - allow signals to interrupt. */
        rc = wait_event_interruptible(server->response_q,
-               (!(midQ->mid_state == MID_REQUEST_SUBMITTED)) ||
+               (!(midQ->mid_state == MID_REQUEST_SUBMITTED ||
+                  midQ->mid_state == MID_RESPONSE_RECEIVED)) ||
                ((server->tcpStatus != CifsGood) &&
                 (server->tcpStatus != CifsNew)));
 
        /* Were we interrupted by a signal ? */
        spin_lock(&server->srv_lock);
        if ((rc == -ERESTARTSYS) &&
-               (midQ->mid_state == MID_REQUEST_SUBMITTED) &&
+               (midQ->mid_state == MID_REQUEST_SUBMITTED ||
+                midQ->mid_state == MID_RESPONSE_RECEIVED) &&
                ((server->tcpStatus == CifsGood) ||
                 (server->tcpStatus == CifsNew))) {
                spin_unlock(&server->srv_lock);
@@ -1596,7 +1607,8 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
                if (rc) {
                        send_cancel(server, &rqst, midQ);
                        spin_lock(&server->mid_lock);
-                       if (midQ->mid_state == MID_REQUEST_SUBMITTED) {
+                       if (midQ->mid_state == MID_REQUEST_SUBMITTED ||
+                           midQ->mid_state == MID_RESPONSE_RECEIVED) {
                                /* no longer considered to be "in-flight" */
                                midQ->callback = release_mid;
                                spin_unlock(&server->mid_lock);
@@ -1616,7 +1628,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
                return rc;
 
        /* rcvd frame is ok */
-       if (out_buf == NULL || midQ->mid_state != MID_RESPONSE_RECEIVED) {
+       if (out_buf == NULL || midQ->mid_state != MID_RESPONSE_READY) {
                rc = -EIO;
                cifs_tcon_dbg(VFS, "Bad MID state?\n");
                goto out;
index 0d990c2..4b38c3a 100644 (file)
@@ -84,6 +84,8 @@ struct ksmbd_conn *ksmbd_conn_alloc(void)
        spin_lock_init(&conn->llist_lock);
        INIT_LIST_HEAD(&conn->lock_list);
 
+       init_rwsem(&conn->session_lock);
+
        down_write(&conn_list_lock);
        list_add(&conn->conns_list, &conn_list);
        up_write(&conn_list_lock);
@@ -197,6 +199,9 @@ int ksmbd_conn_write(struct ksmbd_work *work)
        if (work->send_no_response)
                return 0;
 
+       if (!work->iov_idx)
+               return -EINVAL;
+
        ksmbd_conn_lock(conn);
        sent = conn->transport->ops->writev(conn->transport, work->iov,
                        work->iov_cnt,
index ab2583f..3c00524 100644 (file)
@@ -50,6 +50,7 @@ struct ksmbd_conn {
        struct nls_table                *local_nls;
        struct unicode_map              *um;
        struct list_head                conns_list;
+       struct rw_semaphore             session_lock;
        /* smb session 1 per user */
        struct xarray                   sessions;
        unsigned long                   last_active;
index 408cddf..d2c81a8 100644 (file)
@@ -73,7 +73,10 @@ ksmbd_tree_conn_connect(struct ksmbd_conn *conn, struct ksmbd_session *sess,
 
        tree_conn->user = sess->user;
        tree_conn->share_conf = sc;
+       tree_conn->t_state = TREE_NEW;
        status.tree_conn = tree_conn;
+       atomic_set(&tree_conn->refcount, 1);
+       init_waitqueue_head(&tree_conn->refcount_q);
 
        ret = xa_err(xa_store(&sess->tree_conns, tree_conn->id, tree_conn,
                              GFP_KERNEL));
@@ -93,14 +96,33 @@ out_error:
        return status;
 }
 
+void ksmbd_tree_connect_put(struct ksmbd_tree_connect *tcon)
+{
+       /*
+        * Checking waitqueue to releasing tree connect on
+        * tree disconnect. waitqueue_active is safe because it
+        * uses atomic operation for condition.
+        */
+       if (!atomic_dec_return(&tcon->refcount) &&
+           waitqueue_active(&tcon->refcount_q))
+               wake_up(&tcon->refcount_q);
+}
+
 int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess,
                               struct ksmbd_tree_connect *tree_conn)
 {
        int ret;
 
+       write_lock(&sess->tree_conns_lock);
+       xa_erase(&sess->tree_conns, tree_conn->id);
+       write_unlock(&sess->tree_conns_lock);
+
+       if (!atomic_dec_and_test(&tree_conn->refcount))
+               wait_event(tree_conn->refcount_q,
+                          atomic_read(&tree_conn->refcount) == 0);
+
        ret = ksmbd_ipc_tree_disconnect_request(sess->id, tree_conn->id);
        ksmbd_release_tree_conn_id(sess, tree_conn->id);
-       xa_erase(&sess->tree_conns, tree_conn->id);
        ksmbd_share_config_put(tree_conn->share_conf);
        kfree(tree_conn);
        return ret;
@@ -111,11 +133,15 @@ struct ksmbd_tree_connect *ksmbd_tree_conn_lookup(struct ksmbd_session *sess,
 {
        struct ksmbd_tree_connect *tcon;
 
+       read_lock(&sess->tree_conns_lock);
        tcon = xa_load(&sess->tree_conns, id);
        if (tcon) {
-               if (test_bit(TREE_CONN_EXPIRE, &tcon->status))
+               if (tcon->t_state != TREE_CONNECTED)
+                       tcon = NULL;
+               else if (!atomic_inc_not_zero(&tcon->refcount))
                        tcon = NULL;
        }
+       read_unlock(&sess->tree_conns_lock);
 
        return tcon;
 }
@@ -129,8 +155,18 @@ int ksmbd_tree_conn_session_logoff(struct ksmbd_session *sess)
        if (!sess)
                return -EINVAL;
 
-       xa_for_each(&sess->tree_conns, id, tc)
+       xa_for_each(&sess->tree_conns, id, tc) {
+               write_lock(&sess->tree_conns_lock);
+               if (tc->t_state == TREE_DISCONNECTED) {
+                       write_unlock(&sess->tree_conns_lock);
+                       ret = -ENOENT;
+                       continue;
+               }
+               tc->t_state = TREE_DISCONNECTED;
+               write_unlock(&sess->tree_conns_lock);
+
                ret |= ksmbd_tree_conn_disconnect(sess, tc);
+       }
        xa_destroy(&sess->tree_conns);
        return ret;
 }
index 562d647..6377a70 100644 (file)
@@ -14,7 +14,11 @@ struct ksmbd_share_config;
 struct ksmbd_user;
 struct ksmbd_conn;
 
-#define TREE_CONN_EXPIRE               1
+enum {
+       TREE_NEW = 0,
+       TREE_CONNECTED,
+       TREE_DISCONNECTED
+};
 
 struct ksmbd_tree_connect {
        int                             id;
@@ -27,7 +31,9 @@ struct ksmbd_tree_connect {
 
        int                             maximal_access;
        bool                            posix_extensions;
-       unsigned long                   status;
+       atomic_t                        refcount;
+       wait_queue_head_t               refcount_q;
+       unsigned int                    t_state;
 };
 
 struct ksmbd_tree_conn_status {
@@ -46,6 +52,7 @@ struct ksmbd_session;
 struct ksmbd_tree_conn_status
 ksmbd_tree_conn_connect(struct ksmbd_conn *conn, struct ksmbd_session *sess,
                        const char *share_name);
+void ksmbd_tree_connect_put(struct ksmbd_tree_connect *tcon);
 
 int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess,
                               struct ksmbd_tree_connect *tree_conn);
index 8a5dcab..15f68ee 100644 (file)
@@ -174,7 +174,7 @@ static void ksmbd_expire_session(struct ksmbd_conn *conn)
        unsigned long id;
        struct ksmbd_session *sess;
 
-       down_write(&sessions_table_lock);
+       down_write(&conn->session_lock);
        xa_for_each(&conn->sessions, id, sess) {
                if (sess->state != SMB2_SESSION_VALID ||
                    time_after(jiffies,
@@ -185,7 +185,7 @@ static void ksmbd_expire_session(struct ksmbd_conn *conn)
                        continue;
                }
        }
-       up_write(&sessions_table_lock);
+       up_write(&conn->session_lock);
 }
 
 int ksmbd_session_register(struct ksmbd_conn *conn,
@@ -227,7 +227,9 @@ void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
                        }
                }
        }
+       up_write(&sessions_table_lock);
 
+       down_write(&conn->session_lock);
        xa_for_each(&conn->sessions, id, sess) {
                unsigned long chann_id;
                struct channel *chann;
@@ -244,7 +246,7 @@ void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
                        ksmbd_session_destroy(sess);
                }
        }
-       up_write(&sessions_table_lock);
+       up_write(&conn->session_lock);
 }
 
 struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn,
@@ -252,9 +254,11 @@ struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn,
 {
        struct ksmbd_session *sess;
 
+       down_read(&conn->session_lock);
        sess = xa_load(&conn->sessions, id);
        if (sess)
                sess->last_active = jiffies;
+       up_read(&conn->session_lock);
        return sess;
 }
 
@@ -351,6 +355,7 @@ static struct ksmbd_session *__session_create(int protocol)
        xa_init(&sess->ksmbd_chann_list);
        xa_init(&sess->rpc_handle_list);
        sess->sequence_number = 1;
+       rwlock_init(&sess->tree_conns_lock);
 
        ret = __init_smb2_session(sess);
        if (ret)
index f99d475..63cb08f 100644 (file)
@@ -60,6 +60,7 @@ struct ksmbd_session {
 
        struct ksmbd_file_table         file_table;
        unsigned long                   last_active;
+       rwlock_t                        tree_conns_lock;
 };
 
 static inline int test_session_flag(struct ksmbd_session *sess, int bit)
index 5ab2f52..3079e60 100644 (file)
@@ -115,8 +115,10 @@ static int __process_request(struct ksmbd_work *work, struct ksmbd_conn *conn,
        if (check_conn_state(work))
                return SERVER_HANDLER_CONTINUE;
 
-       if (ksmbd_verify_smb_message(work))
+       if (ksmbd_verify_smb_message(work)) {
+               conn->ops->set_rsp_status(work, STATUS_INVALID_PARAMETER);
                return SERVER_HANDLER_ABORT;
+       }
 
        command = conn->ops->get_cmd_val(work);
        *cmd = command;
@@ -239,6 +241,8 @@ static void __handle_ksmbd_work(struct ksmbd_work *work,
        } while (is_chained == true);
 
 send:
+       if (work->tcon)
+               ksmbd_tree_connect_put(work->tcon);
        smb3_preauth_hash_rsp(work);
        if (work->sess && work->sess->enc && work->encrypted &&
            conn->ops->encrypt_resp) {
index e881df1..23bd3d1 100644 (file)
@@ -440,10 +440,8 @@ int ksmbd_smb2_check_message(struct ksmbd_work *work)
 
 validate_credit:
        if ((work->conn->vals->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU) &&
-           smb2_validate_credit_charge(work->conn, hdr)) {
-               work->conn->ops->set_rsp_status(work, STATUS_INVALID_PARAMETER);
+           smb2_validate_credit_charge(work->conn, hdr))
                return 1;
-       }
 
        return 0;
 }
index 544022d..898860a 100644 (file)
@@ -1993,6 +1993,9 @@ int smb2_tree_connect(struct ksmbd_work *work)
        if (conn->posix_ext_supported)
                status.tree_conn->posix_extensions = true;
 
+       write_lock(&sess->tree_conns_lock);
+       status.tree_conn->t_state = TREE_CONNECTED;
+       write_unlock(&sess->tree_conns_lock);
        rsp->StructureSize = cpu_to_le16(16);
 out_err1:
        rsp->Capabilities = 0;
@@ -2122,27 +2125,50 @@ int smb2_tree_disconnect(struct ksmbd_work *work)
 
        ksmbd_debug(SMB, "request\n");
 
+       if (!tcon) {
+               ksmbd_debug(SMB, "Invalid tid %d\n", req->hdr.Id.SyncId.TreeId);
+
+               rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED;
+               err = -ENOENT;
+               goto err_out;
+       }
+
+       ksmbd_close_tree_conn_fds(work);
+
+       write_lock(&sess->tree_conns_lock);
+       if (tcon->t_state == TREE_DISCONNECTED) {
+               write_unlock(&sess->tree_conns_lock);
+               rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED;
+               err = -ENOENT;
+               goto err_out;
+       }
+
+       WARN_ON_ONCE(atomic_dec_and_test(&tcon->refcount));
+       tcon->t_state = TREE_DISCONNECTED;
+       write_unlock(&sess->tree_conns_lock);
+
+       err = ksmbd_tree_conn_disconnect(sess, tcon);
+       if (err) {
+               rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED;
+               goto err_out;
+       }
+
+       work->tcon = NULL;
+
        rsp->StructureSize = cpu_to_le16(4);
        err = ksmbd_iov_pin_rsp(work, rsp,
                                sizeof(struct smb2_tree_disconnect_rsp));
        if (err) {
                rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES;
-               smb2_set_err_rsp(work);
-               return err;
+               goto err_out;
        }
 
-       if (!tcon || test_and_set_bit(TREE_CONN_EXPIRE, &tcon->status)) {
-               ksmbd_debug(SMB, "Invalid tid %d\n", req->hdr.Id.SyncId.TreeId);
+       return 0;
 
-               rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED;
-               smb2_set_err_rsp(work);
-               return -ENOENT;
-       }
+err_out:
+       smb2_set_err_rsp(work);
+       return err;
 
-       ksmbd_close_tree_conn_fds(work);
-       ksmbd_tree_conn_disconnect(sess, tcon);
-       work->tcon = NULL;
-       return 0;
 }
 
 /**
@@ -2164,17 +2190,17 @@ int smb2_session_logoff(struct ksmbd_work *work)
 
        ksmbd_debug(SMB, "request\n");
 
-       sess_id = le64_to_cpu(req->hdr.SessionId);
-
-       rsp->StructureSize = cpu_to_le16(4);
-       err = ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_logoff_rsp));
-       if (err) {
-               rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES;
+       ksmbd_conn_lock(conn);
+       if (!ksmbd_conn_good(conn)) {
+               ksmbd_conn_unlock(conn);
+               rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED;
                smb2_set_err_rsp(work);
-               return err;
+               return -ENOENT;
        }
-
+       sess_id = le64_to_cpu(req->hdr.SessionId);
        ksmbd_all_conn_set_status(sess_id, KSMBD_SESS_NEED_RECONNECT);
+       ksmbd_conn_unlock(conn);
+
        ksmbd_close_session_fds(work);
        ksmbd_conn_wait_idle(conn, sess_id);
 
@@ -2196,6 +2222,14 @@ int smb2_session_logoff(struct ksmbd_work *work)
        ksmbd_free_user(sess->user);
        sess->user = NULL;
        ksmbd_all_conn_set_status(sess_id, KSMBD_SESS_NEED_NEGOTIATE);
+
+       rsp->StructureSize = cpu_to_le16(4);
+       err = ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_logoff_rsp));
+       if (err) {
+               rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES;
+               smb2_set_err_rsp(work);
+               return err;
+       }
        return 0;
 }
 
@@ -3370,8 +3404,10 @@ err_out:
        }
        ksmbd_revert_fsids(work);
 err_out1:
-       if (!rc)
+       if (!rc) {
+               ksmbd_update_fstate(&work->sess->file_table, fp, FP_INITED);
                rc = ksmbd_iov_pin_rsp(work, (void *)rsp, iov_len);
+       }
        if (rc) {
                if (rc == -EINVAL)
                        rsp->hdr.Status = STATUS_INVALID_PARAMETER;
@@ -7028,10 +7064,6 @@ skip:
 
                                ksmbd_debug(SMB,
                                            "would have to wait for getting lock\n");
-                               spin_lock(&work->conn->llist_lock);
-                               list_add_tail(&smb_lock->clist,
-                                             &work->conn->lock_list);
-                               spin_unlock(&work->conn->llist_lock);
                                list_add(&smb_lock->llist, &rollback_list);
 
                                argv = kmalloc(sizeof(void *), GFP_KERNEL);
@@ -7062,9 +7094,6 @@ skip:
 
                                if (work->state != KSMBD_WORK_ACTIVE) {
                                        list_del(&smb_lock->llist);
-                                       spin_lock(&work->conn->llist_lock);
-                                       list_del(&smb_lock->clist);
-                                       spin_unlock(&work->conn->llist_lock);
                                        locks_free_lock(flock);
 
                                        if (work->state == KSMBD_WORK_CANCELLED) {
@@ -7084,19 +7113,16 @@ skip:
                                }
 
                                list_del(&smb_lock->llist);
-                               spin_lock(&work->conn->llist_lock);
-                               list_del(&smb_lock->clist);
-                               spin_unlock(&work->conn->llist_lock);
                                release_async_work(work);
                                goto retry;
                        } else if (!rc) {
+                               list_add(&smb_lock->llist, &rollback_list);
                                spin_lock(&work->conn->llist_lock);
                                list_add_tail(&smb_lock->clist,
                                              &work->conn->lock_list);
                                list_add_tail(&smb_lock->flist,
                                              &fp->lock_list);
                                spin_unlock(&work->conn->llist_lock);
-                               list_add(&smb_lock->llist, &rollback_list);
                                ksmbd_debug(SMB, "successful in taking lock\n");
                        } else {
                                goto out;
@@ -8036,10 +8062,10 @@ static void smb20_oplock_break_ack(struct ksmbd_work *work)
                goto err_out;
        }
 
-       opinfo_put(opinfo);
-       ksmbd_fd_put(work, fp);
        opinfo->op_state = OPLOCK_STATE_NONE;
        wake_up_interruptible_all(&opinfo->oplock_q);
+       opinfo_put(opinfo);
+       ksmbd_fd_put(work, fp);
 
        rsp->StructureSize = cpu_to_le16(24);
        rsp->OplockLevel = rsp_oplevel;
index f41f8d6..c4b80ab 100644 (file)
@@ -333,6 +333,9 @@ static void __ksmbd_close_fd(struct ksmbd_file_table *ft, struct ksmbd_file *fp)
 
 static struct ksmbd_file *ksmbd_fp_get(struct ksmbd_file *fp)
 {
+       if (fp->f_state != FP_INITED)
+               return NULL;
+
        if (!atomic_inc_not_zero(&fp->refcount))
                return NULL;
        return fp;
@@ -382,15 +385,20 @@ int ksmbd_close_fd(struct ksmbd_work *work, u64 id)
                return 0;
 
        ft = &work->sess->file_table;
-       read_lock(&ft->lock);
+       write_lock(&ft->lock);
        fp = idr_find(ft->idr, id);
        if (fp) {
                set_close_state_blocked_works(fp);
 
-               if (!atomic_dec_and_test(&fp->refcount))
+               if (fp->f_state != FP_INITED)
                        fp = NULL;
+               else {
+                       fp->f_state = FP_CLOSED;
+                       if (!atomic_dec_and_test(&fp->refcount))
+                               fp = NULL;
+               }
        }
-       read_unlock(&ft->lock);
+       write_unlock(&ft->lock);
 
        if (!fp)
                return -EINVAL;
@@ -570,6 +578,7 @@ struct ksmbd_file *ksmbd_open_fd(struct ksmbd_work *work, struct file *filp)
        fp->tcon                = work->tcon;
        fp->volatile_id         = KSMBD_NO_FID;
        fp->persistent_id       = KSMBD_NO_FID;
+       fp->f_state             = FP_NEW;
        fp->f_ci                = ksmbd_inode_get(fp);
 
        if (!fp->f_ci) {
@@ -591,6 +600,14 @@ err_out:
        return ERR_PTR(ret);
 }
 
+void ksmbd_update_fstate(struct ksmbd_file_table *ft, struct ksmbd_file *fp,
+                        unsigned int state)
+{
+       write_lock(&ft->lock);
+       fp->f_state = state;
+       write_unlock(&ft->lock);
+}
+
 static int
 __close_file_table_ids(struct ksmbd_file_table *ft,
                       struct ksmbd_tree_connect *tcon,
index fcb1341..03d0bf9 100644 (file)
@@ -60,6 +60,12 @@ struct ksmbd_inode {
        __le32                          m_fattr;
 };
 
+enum {
+       FP_NEW = 0,
+       FP_INITED,
+       FP_CLOSED
+};
+
 struct ksmbd_file {
        struct file                     *filp;
        u64                             persistent_id;
@@ -98,6 +104,7 @@ struct ksmbd_file {
        /* if ls is happening on directory, below is valid*/
        struct ksmbd_readdir_data       readdir_data;
        int                             dot_dotdot[2];
+       unsigned int                    f_state;
 };
 
 static inline void set_ctx_actor(struct dir_context *ctx,
@@ -142,6 +149,8 @@ int ksmbd_close_inode_fds(struct ksmbd_work *work, struct inode *inode);
 int ksmbd_init_global_file_table(void);
 void ksmbd_free_global_file_table(void);
 void ksmbd_set_fd_limit(unsigned long limit);
+void ksmbd_update_fstate(struct ksmbd_file_table *ft, struct ksmbd_file *fp,
+                        unsigned int state);
 
 /*
  * INODE hash
index 6e60389..d43a5cc 100644 (file)
--- a/fs/stat.c
+++ b/fs/stat.c
 #include "mount.h"
 
 /**
- * fill_mg_cmtime - Fill in the mtime and ctime and flag ctime as QUERIED
- * @stat: where to store the resulting values
- * @request_mask: STATX_* values requested
- * @inode: inode from which to grab the c/mtime
- *
- * Given @inode, grab the ctime and mtime out if it and store the result
- * in @stat. When fetching the value, flag it as queried so the next write
- * will use a fine-grained timestamp.
- */
-void fill_mg_cmtime(struct kstat *stat, u32 request_mask, struct inode *inode)
-{
-       atomic_long_t *pnsec = (atomic_long_t *)&inode->__i_ctime.tv_nsec;
-
-       /* If neither time was requested, then don't report them */
-       if (!(request_mask & (STATX_CTIME|STATX_MTIME))) {
-               stat->result_mask &= ~(STATX_CTIME|STATX_MTIME);
-               return;
-       }
-
-       stat->mtime = inode->i_mtime;
-       stat->ctime.tv_sec = inode->__i_ctime.tv_sec;
-       /*
-        * Atomically set the QUERIED flag and fetch the new value with
-        * the flag masked off.
-        */
-       stat->ctime.tv_nsec = atomic_long_fetch_or(I_CTIME_QUERIED, pnsec) &
-                                       ~I_CTIME_QUERIED;
-}
-EXPORT_SYMBOL(fill_mg_cmtime);
-
-/**
  * generic_fillattr - Fill in the basic attributes from the inode struct
  * @idmap:             idmap of the mount the inode was found from
  * @request_mask:      statx request_mask
@@ -89,14 +58,8 @@ void generic_fillattr(struct mnt_idmap *idmap, u32 request_mask,
        stat->rdev = inode->i_rdev;
        stat->size = i_size_read(inode);
        stat->atime = inode->i_atime;
-
-       if (is_mgtime(inode)) {
-               fill_mg_cmtime(stat, request_mask, inode);
-       } else {
-               stat->mtime = inode->i_mtime;
-               stat->ctime = inode_get_ctime(inode);
-       }
-
+       stat->mtime = inode->i_mtime;
+       stat->ctime = inode_get_ctime(inode);
        stat->blksize = i_blocksize(inode);
        stat->blocks = inode->i_blocks;
 
index 9f64e73..8c8d64e 100644 (file)
@@ -70,6 +70,7 @@ static struct dentry *eventfs_root_lookup(struct inode *dir,
                                          struct dentry *dentry,
                                          unsigned int flags);
 static int dcache_dir_open_wrapper(struct inode *inode, struct file *file);
+static int dcache_readdir_wrapper(struct file *file, struct dir_context *ctx);
 static int eventfs_release(struct inode *inode, struct file *file);
 
 static const struct inode_operations eventfs_root_dir_inode_operations = {
@@ -79,7 +80,7 @@ static const struct inode_operations eventfs_root_dir_inode_operations = {
 static const struct file_operations eventfs_file_operations = {
        .open           = dcache_dir_open_wrapper,
        .read           = generic_read_dir,
-       .iterate_shared = dcache_readdir,
+       .iterate_shared = dcache_readdir_wrapper,
        .llseek         = generic_file_llseek,
        .release        = eventfs_release,
 };
@@ -396,6 +397,11 @@ static struct dentry *eventfs_root_lookup(struct inode *dir,
        return ret;
 }
 
+struct dentry_list {
+       void                    *cursor;
+       struct dentry           **dentries;
+};
+
 /**
  * eventfs_release - called to release eventfs file/dir
  * @inode: inode to be released
@@ -404,26 +410,25 @@ static struct dentry *eventfs_root_lookup(struct inode *dir,
 static int eventfs_release(struct inode *inode, struct file *file)
 {
        struct tracefs_inode *ti;
-       struct eventfs_inode *ei;
-       struct eventfs_file *ef;
-       struct dentry *dentry;
-       int idx;
+       struct dentry_list *dlist = file->private_data;
+       void *cursor;
+       int i;
 
        ti = get_tracefs(inode);
        if (!(ti->flags & TRACEFS_EVENT_INODE))
                return -EINVAL;
 
-       ei = ti->private;
-       idx = srcu_read_lock(&eventfs_srcu);
-       list_for_each_entry_srcu(ef, &ei->e_top_files, list,
-                                srcu_read_lock_held(&eventfs_srcu)) {
-               mutex_lock(&eventfs_mutex);
-               dentry = ef->dentry;
-               mutex_unlock(&eventfs_mutex);
-               if (dentry)
-                       dput(dentry);
+       if (WARN_ON_ONCE(!dlist))
+               return -EINVAL;
+
+       for (i = 0; dlist->dentries && dlist->dentries[i]; i++) {
+               dput(dlist->dentries[i]);
        }
-       srcu_read_unlock(&eventfs_srcu, idx);
+
+       cursor = dlist->cursor;
+       kfree(dlist->dentries);
+       kfree(dlist);
+       file->private_data = cursor;
        return dcache_dir_close(inode, file);
 }
 
@@ -442,22 +447,70 @@ static int dcache_dir_open_wrapper(struct inode *inode, struct file *file)
        struct tracefs_inode *ti;
        struct eventfs_inode *ei;
        struct eventfs_file *ef;
+       struct dentry_list *dlist;
+       struct dentry **dentries = NULL;
        struct dentry *dentry = file_dentry(file);
+       struct dentry *d;
        struct inode *f_inode = file_inode(file);
+       int cnt = 0;
        int idx;
+       int ret;
 
        ti = get_tracefs(f_inode);
        if (!(ti->flags & TRACEFS_EVENT_INODE))
                return -EINVAL;
 
+       if (WARN_ON_ONCE(file->private_data))
+               return -EINVAL;
+
+       dlist = kmalloc(sizeof(*dlist), GFP_KERNEL);
+       if (!dlist)
+               return -ENOMEM;
+
        ei = ti->private;
        idx = srcu_read_lock(&eventfs_srcu);
        list_for_each_entry_srcu(ef, &ei->e_top_files, list,
                                 srcu_read_lock_held(&eventfs_srcu)) {
-               create_dentry(ef, dentry, false);
+               d = create_dentry(ef, dentry, false);
+               if (d) {
+                       struct dentry **tmp;
+
+                       tmp = krealloc(dentries, sizeof(d) * (cnt + 2), GFP_KERNEL);
+                       if (!tmp)
+                               break;
+                       tmp[cnt] = d;
+                       tmp[cnt + 1] = NULL;
+                       cnt++;
+                       dentries = tmp;
+               }
        }
        srcu_read_unlock(&eventfs_srcu, idx);
-       return dcache_dir_open(inode, file);
+       ret = dcache_dir_open(inode, file);
+
+       /*
+        * dcache_dir_open() sets file->private_data to a dentry cursor.
+        * Need to save that but also save all the dentries that were
+        * opened by this function.
+        */
+       dlist->cursor = file->private_data;
+       dlist->dentries = dentries;
+       file->private_data = dlist;
+       return ret;
+}
+
+/*
+ * This just sets the file->private_data back to the cursor and back.
+ */
+static int dcache_readdir_wrapper(struct file *file, struct dir_context *ctx)
+{
+       struct dentry_list *dlist = file->private_data;
+       int ret;
+
+       file->private_data = dlist->cursor;
+       ret = dcache_readdir(file, ctx);
+       dlist->cursor = file->private_data;
+       file->private_data = dlist;
+       return ret;
 }
 
 /**
index c9d6531..ed0bc8c 100644 (file)
@@ -147,7 +147,7 @@ config XFS_ONLINE_SCRUB_STATS
        bool "XFS online metadata check usage data collection"
        default y
        depends on XFS_ONLINE_SCRUB
-       select FS_DEBUG
+       select XFS_DEBUG
        help
          If you say Y here, the kernel will gather usage data about
          the online metadata check subsystem.  This includes the number
index 2420865..a5100a1 100644 (file)
@@ -131,4 +131,26 @@ void xlog_check_buf_cancel_table(struct xlog *log);
 #define xlog_check_buf_cancel_table(log) do { } while (0)
 #endif
 
+/*
+ * Transform a regular reservation into one suitable for recovery of a log
+ * intent item.
+ *
+ * Intent recovery only runs a single step of the transaction chain and defers
+ * the rest to a separate transaction.  Therefore, we reduce logcount to 1 here
+ * to avoid livelocks if the log grant space is nearly exhausted due to the
+ * recovered intent pinning the tail.  Keep the same logflags to avoid tripping
+ * asserts elsewhere.  Struct copies abound below.
+ */
+static inline struct xfs_trans_res
+xlog_recover_resv(const struct xfs_trans_res *r)
+{
+       struct xfs_trans_res ret = {
+               .tr_logres      = r->tr_logres,
+               .tr_logcount    = 1,
+               .tr_logflags    = r->tr_logflags,
+       };
+
+       return ret;
+}
+
 #endif /* __XFS_LOG_RECOVER_H__ */
index 5e17468..6264daa 100644 (file)
@@ -266,7 +266,8 @@ xfs_validate_sb_write(
                return -EFSCORRUPTED;
        }
 
-       if (xfs_sb_has_ro_compat_feature(sbp, XFS_SB_FEAT_RO_COMPAT_UNKNOWN)) {
+       if (!xfs_is_readonly(mp) &&
+           xfs_sb_has_ro_compat_feature(sbp, XFS_SB_FEAT_RO_COMPAT_UNKNOWN)) {
                xfs_alert(mp,
 "Corruption detected in superblock read-only compatible features (0x%x)!",
                        (sbp->sb_features_ro_compat &
index ad22656..6b2296f 100644 (file)
@@ -62,12 +62,12 @@ xfs_trans_ichgtime(
        ASSERT(tp);
        ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
 
-       /* If the mtime changes, then ctime must also change */
-       ASSERT(flags & XFS_ICHGTIME_CHG);
+       tv = current_time(inode);
 
-       tv = inode_set_ctime_current(inode);
        if (flags & XFS_ICHGTIME_MOD)
                inode->i_mtime = tv;
+       if (flags & XFS_ICHGTIME_CHG)
+               inode_set_ctime_to_ts(inode, tv);
        if (flags & XFS_ICHGTIME_CREATE)
                ip->i_crtime = tv;
 }
index 7d3aa14..4849efc 100644 (file)
@@ -588,6 +588,8 @@ out_nofix:
 out_teardown:
        error = xchk_teardown(sc, error);
 out_sc:
+       if (error != -ENOENT)
+               xchk_stats_merge(mp, sm, &run);
        kfree(sc);
 out:
        trace_xchk_done(XFS_I(file_inode(file)), sm, error);
@@ -595,8 +597,6 @@ out:
                sm->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT;
                error = 0;
        }
-       if (error != -ENOENT)
-               xchk_stats_merge(mp, sm, &run);
        return error;
 need_drain:
        error = xchk_teardown(sc, 0);
index aeb9262..cd91db4 100644 (file)
@@ -185,7 +185,10 @@ xchk_stats_merge_one(
 {
        struct xchk_scrub_stats         *css;
 
-       ASSERT(sm->sm_type < XFS_SCRUB_TYPE_NR);
+       if (sm->sm_type >= XFS_SCRUB_TYPE_NR) {
+               ASSERT(sm->sm_type < XFS_SCRUB_TYPE_NR);
+               return;
+       }
 
        css = &cs->cs_stats[sm->sm_type];
        spin_lock(&css->css_lock);
index 5db87b3..89c7a9f 100644 (file)
@@ -333,7 +333,6 @@ xfs_attr_inactive(
        int                     error = 0;
 
        mp = dp->i_mount;
-       ASSERT(! XFS_NOT_DQATTACHED(mp, dp));
 
        xfs_ilock(dp, lock_mode);
        if (!xfs_inode_has_attr_fork(dp))
index 2788a6f..36fe2ab 100644 (file)
@@ -547,7 +547,7 @@ xfs_attri_item_recover(
        struct xfs_inode                *ip;
        struct xfs_da_args              *args;
        struct xfs_trans                *tp;
-       struct xfs_trans_res            tres;
+       struct xfs_trans_res            resv;
        struct xfs_attri_log_format     *attrp;
        struct xfs_attri_log_nameval    *nv = attrip->attri_nameval;
        int                             error;
@@ -618,8 +618,9 @@ xfs_attri_item_recover(
                goto out;
        }
 
-       xfs_init_attr_trans(args, &tres, &total);
-       error = xfs_trans_alloc(mp, &tres, total, 0, XFS_TRANS_RESERVE, &tp);
+       xfs_init_attr_trans(args, &resv, &total);
+       resv = xlog_recover_resv(&resv);
+       error = xfs_trans_alloc(mp, &resv, total, 0, XFS_TRANS_RESERVE, &tp);
        if (error)
                goto out;
 
index 7551c3e..e736a08 100644 (file)
@@ -490,6 +490,7 @@ xfs_bui_item_recover(
        struct list_head                *capture_list)
 {
        struct xfs_bmap_intent          fake = { };
+       struct xfs_trans_res            resv;
        struct xfs_bui_log_item         *buip = BUI_ITEM(lip);
        struct xfs_trans                *tp;
        struct xfs_inode                *ip = NULL;
@@ -515,7 +516,8 @@ xfs_bui_item_recover(
                return error;
 
        /* Allocate transaction and do the work. */
-       error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate,
+       resv = xlog_recover_resv(&M_RES(mp)->tr_itruncate);
+       error = xfs_trans_alloc(mp, &resv,
                        XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK), 0, 0, &tp);
        if (error)
                goto err_rele;
index afc4c78..d578799 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * Copyright (C) 2010 Red Hat, Inc.
+ * Copyright (C) 2010, 2023 Red Hat, Inc.
  * All Rights Reserved.
  */
 #include "xfs.h"
 #include "xfs_log.h"
 #include "xfs_ag.h"
 
-STATIC int
-xfs_trim_extents(
+/*
+ * Notes on an efficient, low latency fstrim algorithm
+ *
+ * We need to walk the filesystem free space and issue discards on the free
+ * space that meet the search criteria (size and location). We cannot issue
+ * discards on extents that might be in use, or are so recently in use they are
+ * still marked as busy. To serialise against extent state changes whilst we are
+ * gathering extents to trim, we must hold the AGF lock to lock out other
+ * allocations and extent free operations that might change extent state.
+ *
+ * However, we cannot just hold the AGF for the entire AG free space walk whilst
+ * we issue discards on each free space that is found. Storage devices can have
+ * extremely slow discard implementations (e.g. ceph RBD) and so walking a
+ * couple of million free extents and issuing synchronous discards on each
+ * extent can take a *long* time. Whilst we are doing this walk, nothing else
+ * can access the AGF, and we can stall transactions and hence the log whilst
+ * modifications wait for the AGF lock to be released. This can lead hung tasks
+ * kicking the hung task timer and rebooting the system. This is bad.
+ *
+ * Hence we need to take a leaf from the bulkstat playbook. It takes the AGI
+ * lock, gathers a range of inode cluster buffers that are allocated, drops the
+ * AGI lock and then reads all the inode cluster buffers and processes them. It
+ * loops doing this, using a cursor to keep track of where it is up to in the AG
+ * for each iteration to restart the INOBT lookup from.
+ *
+ * We can't do this exactly with free space - once we drop the AGF lock, the
+ * state of the free extent is out of our control and we cannot run a discard
+ * safely on it in this situation. Unless, of course, we've marked the free
+ * extent as busy and undergoing a discard operation whilst we held the AGF
+ * locked.
+ *
+ * This is exactly how online discard works - free extents are marked busy when
+ * they are freed, and once the extent free has been committed to the journal,
+ * the busy extent record is marked as "undergoing discard" and the discard is
+ * then issued on the free extent. Once the discard completes, the busy extent
+ * record is removed and the extent is able to be allocated again.
+ *
+ * In the context of fstrim, if we find a free extent we need to discard, we
+ * don't have to discard it immediately. All we need to do it record that free
+ * extent as being busy and under discard, and all the allocation routines will
+ * now avoid trying to allocate it. Hence if we mark the extent as busy under
+ * the AGF lock, we can safely discard it without holding the AGF lock because
+ * nothing will attempt to allocate that free space until the discard completes.
+ *
+ * This also allows us to issue discards asynchronously like we do with online
+ * discard, and so for fast devices fstrim will run much faster as we can have
+ * multiple discard operations in flight at once, as well as pipeline the free
+ * extent search so that it overlaps in flight discard IO.
+ */
+
+struct workqueue_struct *xfs_discard_wq;
+
+static void
+xfs_discard_endio_work(
+       struct work_struct      *work)
+{
+       struct xfs_busy_extents *extents =
+               container_of(work, struct xfs_busy_extents, endio_work);
+
+       xfs_extent_busy_clear(extents->mount, &extents->extent_list, false);
+       kmem_free(extents->owner);
+}
+
+/*
+ * Queue up the actual completion to a thread to avoid IRQ-safe locking for
+ * pagb_lock.
+ */
+static void
+xfs_discard_endio(
+       struct bio              *bio)
+{
+       struct xfs_busy_extents *extents = bio->bi_private;
+
+       INIT_WORK(&extents->endio_work, xfs_discard_endio_work);
+       queue_work(xfs_discard_wq, &extents->endio_work);
+       bio_put(bio);
+}
+
+/*
+ * Walk the discard list and issue discards on all the busy extents in the
+ * list. We plug and chain the bios so that we only need a single completion
+ * call to clear all the busy extents once the discards are complete.
+ */
+int
+xfs_discard_extents(
+       struct xfs_mount        *mp,
+       struct xfs_busy_extents *extents)
+{
+       struct xfs_extent_busy  *busyp;
+       struct bio              *bio = NULL;
+       struct blk_plug         plug;
+       int                     error = 0;
+
+       blk_start_plug(&plug);
+       list_for_each_entry(busyp, &extents->extent_list, list) {
+               trace_xfs_discard_extent(mp, busyp->agno, busyp->bno,
+                                        busyp->length);
+
+               error = __blkdev_issue_discard(mp->m_ddev_targp->bt_bdev,
+                               XFS_AGB_TO_DADDR(mp, busyp->agno, busyp->bno),
+                               XFS_FSB_TO_BB(mp, busyp->length),
+                               GFP_NOFS, &bio);
+               if (error && error != -EOPNOTSUPP) {
+                       xfs_info(mp,
+        "discard failed for extent [0x%llx,%u], error %d",
+                                (unsigned long long)busyp->bno,
+                                busyp->length,
+                                error);
+                       break;
+               }
+       }
+
+       if (bio) {
+               bio->bi_private = extents;
+               bio->bi_end_io = xfs_discard_endio;
+               submit_bio(bio);
+       } else {
+               xfs_discard_endio_work(&extents->endio_work);
+       }
+       blk_finish_plug(&plug);
+
+       return error;
+}
+
+
+static int
+xfs_trim_gather_extents(
        struct xfs_perag        *pag,
        xfs_daddr_t             start,
        xfs_daddr_t             end,
        xfs_daddr_t             minlen,
+       struct xfs_alloc_rec_incore *tcur,
+       struct xfs_busy_extents *extents,
        uint64_t                *blocks_trimmed)
 {
        struct xfs_mount        *mp = pag->pag_mount;
-       struct block_device     *bdev = mp->m_ddev_targp->bt_bdev;
        struct xfs_btree_cur    *cur;
        struct xfs_buf          *agbp;
-       struct xfs_agf          *agf;
        int                     error;
        int                     i;
+       int                     batch = 100;
 
        /*
         * Force out the log.  This means any transactions that might have freed
@@ -45,20 +171,28 @@ xfs_trim_extents(
        error = xfs_alloc_read_agf(pag, NULL, 0, &agbp);
        if (error)
                return error;
-       agf = agbp->b_addr;
 
        cur = xfs_allocbt_init_cursor(mp, NULL, agbp, pag, XFS_BTNUM_CNT);
 
        /*
-        * Look up the longest btree in the AGF and start with it.
+        * Look up the extent length requested in the AGF and start with it.
         */
-       error = xfs_alloc_lookup_ge(cur, 0, be32_to_cpu(agf->agf_longest), &i);
+       if (tcur->ar_startblock == NULLAGBLOCK)
+               error = xfs_alloc_lookup_ge(cur, 0, tcur->ar_blockcount, &i);
+       else
+               error = xfs_alloc_lookup_le(cur, tcur->ar_startblock,
+                               tcur->ar_blockcount, &i);
        if (error)
                goto out_del_cursor;
+       if (i == 0) {
+               /* nothing of that length left in the AG, we are done */
+               tcur->ar_blockcount = 0;
+               goto out_del_cursor;
+       }
 
        /*
         * Loop until we are done with all extents that are large
-        * enough to be worth discarding.
+        * enough to be worth discarding or we hit batch limits.
         */
        while (i) {
                xfs_agblock_t   fbno;
@@ -73,7 +207,16 @@ xfs_trim_extents(
                        error = -EFSCORRUPTED;
                        break;
                }
-               ASSERT(flen <= be32_to_cpu(agf->agf_longest));
+
+               if (--batch <= 0) {
+                       /*
+                        * Update the cursor to point at this extent so we
+                        * restart the next batch from this extent.
+                        */
+                       tcur->ar_startblock = fbno;
+                       tcur->ar_blockcount = flen;
+                       break;
+               }
 
                /*
                 * use daddr format for all range/len calculations as that is
@@ -88,6 +231,7 @@ xfs_trim_extents(
                 */
                if (dlen < minlen) {
                        trace_xfs_discard_toosmall(mp, pag->pag_agno, fbno, flen);
+                       tcur->ar_blockcount = 0;
                        break;
                }
 
@@ -110,29 +254,103 @@ xfs_trim_extents(
                        goto next_extent;
                }
 
-               trace_xfs_discard_extent(mp, pag->pag_agno, fbno, flen);
-               error = blkdev_issue_discard(bdev, dbno, dlen, GFP_NOFS);
-               if (error)
-                       break;
+               xfs_extent_busy_insert_discard(pag, fbno, flen,
+                               &extents->extent_list);
                *blocks_trimmed += flen;
-
 next_extent:
                error = xfs_btree_decrement(cur, 0, &i);
                if (error)
                        break;
 
-               if (fatal_signal_pending(current)) {
-                       error = -ERESTARTSYS;
-                       break;
-               }
+               /*
+                * If there's no more records in the tree, we are done. Set the
+                * cursor block count to 0 to indicate to the caller that there
+                * is no more extents to search.
+                */
+               if (i == 0)
+                       tcur->ar_blockcount = 0;
        }
 
+       /*
+        * If there was an error, release all the gathered busy extents because
+        * we aren't going to issue a discard on them any more.
+        */
+       if (error)
+               xfs_extent_busy_clear(mp, &extents->extent_list, false);
 out_del_cursor:
        xfs_btree_del_cursor(cur, error);
        xfs_buf_relse(agbp);
        return error;
 }
 
+static bool
+xfs_trim_should_stop(void)
+{
+       return fatal_signal_pending(current) || freezing(current);
+}
+
+/*
+ * Iterate the free list gathering extents and discarding them. We need a cursor
+ * for the repeated iteration of gather/discard loop, so use the longest extent
+ * we found in the last batch as the key to start the next.
+ */
+static int
+xfs_trim_extents(
+       struct xfs_perag        *pag,
+       xfs_daddr_t             start,
+       xfs_daddr_t             end,
+       xfs_daddr_t             minlen,
+       uint64_t                *blocks_trimmed)
+{
+       struct xfs_alloc_rec_incore tcur = {
+               .ar_blockcount = pag->pagf_longest,
+               .ar_startblock = NULLAGBLOCK,
+       };
+       int                     error = 0;
+
+       do {
+               struct xfs_busy_extents *extents;
+
+               extents = kzalloc(sizeof(*extents), GFP_KERNEL);
+               if (!extents) {
+                       error = -ENOMEM;
+                       break;
+               }
+
+               extents->mount = pag->pag_mount;
+               extents->owner = extents;
+               INIT_LIST_HEAD(&extents->extent_list);
+
+               error = xfs_trim_gather_extents(pag, start, end, minlen,
+                               &tcur, extents, blocks_trimmed);
+               if (error) {
+                       kfree(extents);
+                       break;
+               }
+
+               /*
+                * We hand the extent list to the discard function here so the
+                * discarded extents can be removed from the busy extent list.
+                * This allows the discards to run asynchronously with gathering
+                * the next round of extents to discard.
+                *
+                * However, we must ensure that we do not reference the extent
+                * list  after this function call, as it may have been freed by
+                * the time control returns to us.
+                */
+               error = xfs_discard_extents(pag->pag_mount, extents);
+               if (error)
+                       break;
+
+               if (xfs_trim_should_stop())
+                       break;
+
+       } while (tcur.ar_blockcount != 0);
+
+       return error;
+
+}
+
 /*
  * trim a range of the filesystem.
  *
@@ -195,12 +413,12 @@ xfs_ioc_trim(
        for_each_perag_range(mp, agno, xfs_daddr_to_agno(mp, end), pag) {
                error = xfs_trim_extents(pag, start, end, minlen,
                                          &blocks_trimmed);
-               if (error) {
+               if (error)
                        last_error = error;
-                       if (error == -ERESTARTSYS) {
-                               xfs_perag_rele(pag);
-                               break;
-                       }
+
+               if (xfs_trim_should_stop()) {
+                       xfs_perag_rele(pag);
+                       break;
                }
        }
 
index de92d9c..2b1a852 100644 (file)
@@ -3,8 +3,10 @@
 #define XFS_DISCARD_H 1
 
 struct fstrim_range;
-struct list_head;
+struct xfs_mount;
+struct xfs_busy_extents;
 
-extern int     xfs_ioc_trim(struct xfs_mount *, struct fstrim_range __user *);
+int xfs_discard_extents(struct xfs_mount *mp, struct xfs_busy_extents *busy);
+int xfs_ioc_trim(struct xfs_mount *mp, struct fstrim_range __user *fstrim);
 
 #endif /* XFS_DISCARD_H */
index 1064c23..7cd09c3 100644 (file)
@@ -146,6 +146,20 @@ xfs_nfs_get_inode(
                return ERR_PTR(error);
        }
 
+       /*
+        * Reload the incore unlinked list to avoid failure in inodegc.
+        * Use an unlocked check here because unrecovered unlinked inodes
+        * should be somewhat rare.
+        */
+       if (xfs_inode_unlinked_incomplete(ip)) {
+               error = xfs_inode_reload_unlinked(ip);
+               if (error) {
+                       xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
+                       xfs_irele(ip);
+                       return ERR_PTR(error);
+               }
+       }
+
        if (VFS_I(ip)->i_generation != generation) {
                xfs_irele(ip);
                return ERR_PTR(-ESTALE);
index 7c2fdc7..7468148 100644 (file)
 #include "xfs_log.h"
 #include "xfs_ag.h"
 
-void
-xfs_extent_busy_insert(
-       struct xfs_trans        *tp,
+static void
+xfs_extent_busy_insert_list(
        struct xfs_perag        *pag,
        xfs_agblock_t           bno,
        xfs_extlen_t            len,
-       unsigned int            flags)
+       unsigned int            flags,
+       struct list_head        *busy_list)
 {
        struct xfs_extent_busy  *new;
        struct xfs_extent_busy  *busyp;
@@ -40,7 +40,7 @@ xfs_extent_busy_insert(
        new->flags = flags;
 
        /* trace before insert to be able to see failed inserts */
-       trace_xfs_extent_busy(tp->t_mountp, pag->pag_agno, bno, len);
+       trace_xfs_extent_busy(pag->pag_mount, pag->pag_agno, bno, len);
 
        spin_lock(&pag->pagb_lock);
        rbp = &pag->pagb_tree.rb_node;
@@ -62,10 +62,32 @@ xfs_extent_busy_insert(
        rb_link_node(&new->rb_node, parent, rbp);
        rb_insert_color(&new->rb_node, &pag->pagb_tree);
 
-       list_add(&new->list, &tp->t_busy);
+       list_add(&new->list, busy_list);
        spin_unlock(&pag->pagb_lock);
 }
 
+void
+xfs_extent_busy_insert(
+       struct xfs_trans        *tp,
+       struct xfs_perag        *pag,
+       xfs_agblock_t           bno,
+       xfs_extlen_t            len,
+       unsigned int            flags)
+{
+       xfs_extent_busy_insert_list(pag, bno, len, flags, &tp->t_busy);
+}
+
+void
+xfs_extent_busy_insert_discard(
+       struct xfs_perag        *pag,
+       xfs_agblock_t           bno,
+       xfs_extlen_t            len,
+       struct list_head        *busy_list)
+{
+       xfs_extent_busy_insert_list(pag, bno, len, XFS_EXTENT_BUSY_DISCARDED,
+                       busy_list);
+}
+
 /*
  * Search for a busy extent within the range of the extent we are about to
  * allocate.  You need to be holding the busy extent tree lock when calling
index c37bf87..0639aab 100644 (file)
@@ -16,9 +16,6 @@ struct xfs_alloc_arg;
 /*
  * Busy block/extent entry.  Indexed by a rbtree in perag to mark blocks that
  * have been freed but whose transactions aren't committed to disk yet.
- *
- * Note that we use the transaction ID to record the transaction, not the
- * transaction structure itself. See xfs_extent_busy_insert() for details.
  */
 struct xfs_extent_busy {
        struct rb_node  rb_node;        /* ag by-bno indexed search tree */
@@ -31,11 +28,32 @@ struct xfs_extent_busy {
 #define XFS_EXTENT_BUSY_SKIP_DISCARD   0x02    /* do not discard */
 };
 
+/*
+ * List used to track groups of related busy extents all the way through
+ * to discard completion.
+ */
+struct xfs_busy_extents {
+       struct xfs_mount        *mount;
+       struct list_head        extent_list;
+       struct work_struct      endio_work;
+
+       /*
+        * Owner is the object containing the struct xfs_busy_extents to free
+        * once the busy extents have been processed. If only the
+        * xfs_busy_extents object needs freeing, then point this at itself.
+        */
+       void                    *owner;
+};
+
 void
 xfs_extent_busy_insert(struct xfs_trans *tp, struct xfs_perag *pag,
        xfs_agblock_t bno, xfs_extlen_t len, unsigned int flags);
 
 void
+xfs_extent_busy_insert_discard(struct xfs_perag *pag, xfs_agblock_t bno,
+       xfs_extlen_t len, struct list_head *busy_list);
+
+void
 xfs_extent_busy_clear(struct xfs_mount *mp, struct list_head *list,
        bool do_discard);
 
index f1a5ecf..3fa8789 100644 (file)
@@ -660,6 +660,7 @@ xfs_efi_item_recover(
        struct xfs_log_item             *lip,
        struct list_head                *capture_list)
 {
+       struct xfs_trans_res            resv;
        struct xfs_efi_log_item         *efip = EFI_ITEM(lip);
        struct xfs_mount                *mp = lip->li_log->l_mp;
        struct xfs_efd_log_item         *efdp;
@@ -683,7 +684,8 @@ xfs_efi_item_recover(
                }
        }
 
-       error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp);
+       resv = xlog_recover_resv(&M_RES(mp)->tr_itruncate);
+       error = xfs_trans_alloc(mp, &resv, 0, 0, 0, &tp);
        if (error)
                return error;
        efdp = xfs_trans_get_efd(tp, efip, efip->efi_format.efi_nextents);
index 10403ba..736e554 100644 (file)
@@ -565,6 +565,19 @@ err:
 }
 #endif /* CONFIG_XFS_RT */
 
+static inline bool
+rmap_not_shareable(struct xfs_mount *mp, const struct xfs_rmap_irec *r)
+{
+       if (!xfs_has_reflink(mp))
+               return true;
+       if (XFS_RMAP_NON_INODE_OWNER(r->rm_owner))
+               return true;
+       if (r->rm_flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK |
+                          XFS_RMAP_UNWRITTEN))
+               return true;
+       return false;
+}
+
 /* Execute a getfsmap query against the regular data device. */
 STATIC int
 __xfs_getfsmap_datadev(
@@ -598,7 +611,6 @@ __xfs_getfsmap_datadev(
         * low to the fsmap low key and max out the high key to the end
         * of the AG.
         */
-       info->low.rm_startblock = XFS_FSB_TO_AGBNO(mp, start_fsb);
        info->low.rm_offset = XFS_BB_TO_FSBT(mp, keys[0].fmr_offset);
        error = xfs_fsmap_owner_to_rmap(&info->low, &keys[0]);
        if (error)
@@ -608,12 +620,9 @@ __xfs_getfsmap_datadev(
 
        /* Adjust the low key if we are continuing from where we left off. */
        if (info->low.rm_blockcount == 0) {
-               /* empty */
-       } else if (XFS_RMAP_NON_INODE_OWNER(info->low.rm_owner) ||
-                  (info->low.rm_flags & (XFS_RMAP_ATTR_FORK |
-                                         XFS_RMAP_BMBT_BLOCK |
-                                         XFS_RMAP_UNWRITTEN))) {
-               info->low.rm_startblock += info->low.rm_blockcount;
+               /* No previous record from which to continue */
+       } else if (rmap_not_shareable(mp, &info->low)) {
+               /* Last record seen was an unshareable extent */
                info->low.rm_owner = 0;
                info->low.rm_offset = 0;
 
@@ -621,8 +630,10 @@ __xfs_getfsmap_datadev(
                if (XFS_FSB_TO_DADDR(mp, start_fsb) >= eofs)
                        return 0;
        } else {
+               /* Last record seen was a shareable file data extent */
                info->low.rm_offset += info->low.rm_blockcount;
        }
+       info->low.rm_startblock = XFS_FSB_TO_AGBNO(mp, start_fsb);
 
        info->high.rm_startblock = -1U;
        info->high.rm_owner = ULLONG_MAX;
index e541f5c..3c210ac 100644 (file)
@@ -113,7 +113,7 @@ xfs_inode_alloc(
        INIT_LIST_HEAD(&ip->i_ioend_list);
        spin_lock_init(&ip->i_ioend_lock);
        ip->i_next_unlinked = NULLAGINO;
-       ip->i_prev_unlinked = NULLAGINO;
+       ip->i_prev_unlinked = 0;
 
        return ip;
 }
@@ -443,7 +443,7 @@ xfs_inodegc_queue_all(
        int                     cpu;
        bool                    ret = false;
 
-       for_each_online_cpu(cpu) {
+       for_each_cpu(cpu, &mp->m_inodegc_cpumask) {
                gc = per_cpu_ptr(mp->m_inodegc, cpu);
                if (!llist_empty(&gc->list)) {
                        mod_delayed_work_on(cpu, mp->m_inodegc_wq, &gc->work, 0);
@@ -463,7 +463,7 @@ xfs_inodegc_wait_all(
        int                     error = 0;
 
        flush_workqueue(mp->m_inodegc_wq);
-       for_each_online_cpu(cpu) {
+       for_each_cpu(cpu, &mp->m_inodegc_cpumask) {
                struct xfs_inodegc      *gc;
 
                gc = per_cpu_ptr(mp->m_inodegc, cpu);
@@ -1845,9 +1845,17 @@ xfs_inodegc_worker(
                                                struct xfs_inodegc, work);
        struct llist_node       *node = llist_del_all(&gc->list);
        struct xfs_inode        *ip, *n;
+       struct xfs_mount        *mp = gc->mp;
        unsigned int            nofs_flag;
 
-       ASSERT(gc->cpu == smp_processor_id());
+       /*
+        * Clear the cpu mask bit and ensure that we have seen the latest
+        * update of the gc structure associated with this CPU. This matches
+        * with the release semantics used when setting the cpumask bit in
+        * xfs_inodegc_queue.
+        */
+       cpumask_clear_cpu(gc->cpu, &mp->m_inodegc_cpumask);
+       smp_mb__after_atomic();
 
        WRITE_ONCE(gc->items, 0);
 
@@ -1862,7 +1870,7 @@ xfs_inodegc_worker(
        nofs_flag = memalloc_nofs_save();
 
        ip = llist_entry(node, struct xfs_inode, i_gclist);
-       trace_xfs_inodegc_worker(ip->i_mount, READ_ONCE(gc->shrinker_hits));
+       trace_xfs_inodegc_worker(mp, READ_ONCE(gc->shrinker_hits));
 
        WRITE_ONCE(gc->shrinker_hits, 0);
        llist_for_each_entry_safe(ip, n, node, i_gclist) {
@@ -2057,6 +2065,7 @@ xfs_inodegc_queue(
        struct xfs_inodegc      *gc;
        int                     items;
        unsigned int            shrinker_hits;
+       unsigned int            cpu_nr;
        unsigned long           queue_delay = 1;
 
        trace_xfs_inode_set_need_inactive(ip);
@@ -2064,18 +2073,28 @@ xfs_inodegc_queue(
        ip->i_flags |= XFS_NEED_INACTIVE;
        spin_unlock(&ip->i_flags_lock);
 
-       gc = get_cpu_ptr(mp->m_inodegc);
+       cpu_nr = get_cpu();
+       gc = this_cpu_ptr(mp->m_inodegc);
        llist_add(&ip->i_gclist, &gc->list);
        items = READ_ONCE(gc->items);
        WRITE_ONCE(gc->items, items + 1);
        shrinker_hits = READ_ONCE(gc->shrinker_hits);
 
        /*
+        * Ensure the list add is always seen by anyone who finds the cpumask
+        * bit set. This effectively gives the cpumask bit set operation
+        * release ordering semantics.
+        */
+       smp_mb__before_atomic();
+       if (!cpumask_test_cpu(cpu_nr, &mp->m_inodegc_cpumask))
+               cpumask_test_and_set_cpu(cpu_nr, &mp->m_inodegc_cpumask);
+
+       /*
         * We queue the work while holding the current CPU so that the work
         * is scheduled to run on this CPU.
         */
        if (!xfs_is_inodegc_enabled(mp)) {
-               put_cpu_ptr(gc);
+               put_cpu();
                return;
        }
 
@@ -2085,7 +2104,7 @@ xfs_inodegc_queue(
        trace_xfs_inodegc_queue(mp, __return_address);
        mod_delayed_work_on(current_cpu(), mp->m_inodegc_wq, &gc->work,
                        queue_delay);
-       put_cpu_ptr(gc);
+       put_cpu();
 
        if (xfs_inodegc_want_flush_work(ip, items, shrinker_hits)) {
                trace_xfs_inodegc_throttle(mp, __return_address);
@@ -2094,47 +2113,6 @@ xfs_inodegc_queue(
 }
 
 /*
- * Fold the dead CPU inodegc queue into the current CPUs queue.
- */
-void
-xfs_inodegc_cpu_dead(
-       struct xfs_mount        *mp,
-       unsigned int            dead_cpu)
-{
-       struct xfs_inodegc      *dead_gc, *gc;
-       struct llist_node       *first, *last;
-       unsigned int            count = 0;
-
-       dead_gc = per_cpu_ptr(mp->m_inodegc, dead_cpu);
-       cancel_delayed_work_sync(&dead_gc->work);
-
-       if (llist_empty(&dead_gc->list))
-               return;
-
-       first = dead_gc->list.first;
-       last = first;
-       while (last->next) {
-               last = last->next;
-               count++;
-       }
-       dead_gc->list.first = NULL;
-       dead_gc->items = 0;
-
-       /* Add pending work to current CPU */
-       gc = get_cpu_ptr(mp->m_inodegc);
-       llist_add_batch(first, last, &gc->list);
-       count += READ_ONCE(gc->items);
-       WRITE_ONCE(gc->items, count);
-
-       if (xfs_is_inodegc_enabled(mp)) {
-               trace_xfs_inodegc_queue(mp, __return_address);
-               mod_delayed_work_on(current_cpu(), mp->m_inodegc_wq, &gc->work,
-                               0);
-       }
-       put_cpu_ptr(gc);
-}
-
-/*
  * We set the inode flag atomically with the radix tree tag.  Once we get tag
  * lookups on the radix tree, this inode flag can go away.
  *
@@ -2195,7 +2173,7 @@ xfs_inodegc_shrinker_count(
        if (!xfs_is_inodegc_enabled(mp))
                return 0;
 
-       for_each_online_cpu(cpu) {
+       for_each_cpu(cpu, &mp->m_inodegc_cpumask) {
                gc = per_cpu_ptr(mp->m_inodegc, cpu);
                if (!llist_empty(&gc->list))
                        return XFS_INODEGC_SHRINKER_COUNT;
@@ -2220,7 +2198,7 @@ xfs_inodegc_shrinker_scan(
 
        trace_xfs_inodegc_shrinker_scan(mp, sc, __return_address);
 
-       for_each_online_cpu(cpu) {
+       for_each_cpu(cpu, &mp->m_inodegc_cpumask) {
                gc = per_cpu_ptr(mp->m_inodegc, cpu);
                if (!llist_empty(&gc->list)) {
                        unsigned int    h = READ_ONCE(gc->shrinker_hits);
index 2fa6f2e..905944d 100644 (file)
@@ -79,7 +79,6 @@ void xfs_inodegc_push(struct xfs_mount *mp);
 int xfs_inodegc_flush(struct xfs_mount *mp);
 void xfs_inodegc_stop(struct xfs_mount *mp);
 void xfs_inodegc_start(struct xfs_mount *mp);
-void xfs_inodegc_cpu_dead(struct xfs_mount *mp, unsigned int cpu);
 int xfs_inodegc_register_shrinker(struct xfs_mount *mp);
 
 #endif
index 360fe83..4d55f58 100644 (file)
@@ -1642,8 +1642,11 @@ xfs_inode_needs_inactive(
        if (VFS_I(ip)->i_mode == 0)
                return false;
 
-       /* If this is a read-only mount, don't do this (would generate I/O) */
-       if (xfs_is_readonly(mp))
+       /*
+        * If this is a read-only mount, don't do this (would generate I/O)
+        * unless we're in log recovery and cleaning the iunlinked list.
+        */
+       if (xfs_is_readonly(mp) && !xlog_recovery_needed(mp->m_log))
                return false;
 
        /* If the log isn't running, push inodes straight to reclaim. */
@@ -1703,8 +1706,11 @@ xfs_inactive(
        mp = ip->i_mount;
        ASSERT(!xfs_iflags_test(ip, XFS_IRECOVERY));
 
-       /* If this is a read-only mount, don't do this (would generate I/O) */
-       if (xfs_is_readonly(mp))
+       /*
+        * If this is a read-only mount, don't do this (would generate I/O)
+        * unless we're in log recovery and cleaning the iunlinked list.
+        */
+       if (xfs_is_readonly(mp) && !xlog_recovery_needed(mp->m_log))
                goto out;
 
        /* Metadata inodes require explicit resource cleanup. */
@@ -1736,9 +1742,21 @@ xfs_inactive(
             ip->i_df.if_nextents > 0 || ip->i_delayed_blks > 0))
                truncate = 1;
 
-       error = xfs_qm_dqattach(ip);
-       if (error)
-               goto out;
+       if (xfs_iflags_test(ip, XFS_IQUOTAUNCHECKED)) {
+               /*
+                * If this inode is being inactivated during a quotacheck and
+                * has not yet been scanned by quotacheck, we /must/ remove
+                * the dquots from the inode before inactivation changes the
+                * block and inode counts.  Most probably this is a result of
+                * reloading the incore iunlinked list to purge unrecovered
+                * unlinked inodes.
+                */
+               xfs_qm_dqdetach(ip);
+       } else {
+               error = xfs_qm_dqattach(ip);
+               if (error)
+                       goto out;
+       }
 
        if (S_ISLNK(VFS_I(ip)->i_mode))
                error = xfs_inactive_symlink(ip);
@@ -1822,12 +1840,17 @@ xfs_iunlink_lookup(
 
        rcu_read_lock();
        ip = radix_tree_lookup(&pag->pag_ici_root, agino);
+       if (!ip) {
+               /* Caller can handle inode not being in memory. */
+               rcu_read_unlock();
+               return NULL;
+       }
 
        /*
-        * Inode not in memory or in RCU freeing limbo should not happen.
-        * Warn about this and let the caller handle the failure.
+        * Inode in RCU freeing limbo should not happen.  Warn about this and
+        * let the caller handle the failure.
         */
-       if (WARN_ON_ONCE(!ip || !ip->i_ino)) {
+       if (WARN_ON_ONCE(!ip->i_ino)) {
                rcu_read_unlock();
                return NULL;
        }
@@ -1836,7 +1859,10 @@ xfs_iunlink_lookup(
        return ip;
 }
 
-/* Update the prev pointer of the next agino. */
+/*
+ * Update the prev pointer of the next agino.  Returns -ENOLINK if the inode
+ * is not in cache.
+ */
 static int
 xfs_iunlink_update_backref(
        struct xfs_perag        *pag,
@@ -1851,7 +1877,8 @@ xfs_iunlink_update_backref(
 
        ip = xfs_iunlink_lookup(pag, next_agino);
        if (!ip)
-               return -EFSCORRUPTED;
+               return -ENOLINK;
+
        ip->i_prev_unlinked = prev_agino;
        return 0;
 }
@@ -1895,6 +1922,64 @@ xfs_iunlink_update_bucket(
        return 0;
 }
 
+/*
+ * Load the inode @next_agino into the cache and set its prev_unlinked pointer
+ * to @prev_agino.  Caller must hold the AGI to synchronize with other changes
+ * to the unlinked list.
+ */
+STATIC int
+xfs_iunlink_reload_next(
+       struct xfs_trans        *tp,
+       struct xfs_buf          *agibp,
+       xfs_agino_t             prev_agino,
+       xfs_agino_t             next_agino)
+{
+       struct xfs_perag        *pag = agibp->b_pag;
+       struct xfs_mount        *mp = pag->pag_mount;
+       struct xfs_inode        *next_ip = NULL;
+       xfs_ino_t               ino;
+       int                     error;
+
+       ASSERT(next_agino != NULLAGINO);
+
+#ifdef DEBUG
+       rcu_read_lock();
+       next_ip = radix_tree_lookup(&pag->pag_ici_root, next_agino);
+       ASSERT(next_ip == NULL);
+       rcu_read_unlock();
+#endif
+
+       xfs_info_ratelimited(mp,
+ "Found unrecovered unlinked inode 0x%x in AG 0x%x.  Initiating recovery.",
+                       next_agino, pag->pag_agno);
+
+       /*
+        * Use an untrusted lookup just to be cautious in case the AGI has been
+        * corrupted and now points at a free inode.  That shouldn't happen,
+        * but we'd rather shut down now since we're already running in a weird
+        * situation.
+        */
+       ino = XFS_AGINO_TO_INO(mp, pag->pag_agno, next_agino);
+       error = xfs_iget(mp, tp, ino, XFS_IGET_UNTRUSTED, 0, &next_ip);
+       if (error)
+               return error;
+
+       /* If this is not an unlinked inode, something is very wrong. */
+       if (VFS_I(next_ip)->i_nlink != 0) {
+               error = -EFSCORRUPTED;
+               goto rele;
+       }
+
+       next_ip->i_prev_unlinked = prev_agino;
+       trace_xfs_iunlink_reload_next(next_ip);
+rele:
+       ASSERT(!(VFS_I(next_ip)->i_state & I_DONTCACHE));
+       if (xfs_is_quotacheck_running(mp) && next_ip)
+               xfs_iflags_set(next_ip, XFS_IQUOTAUNCHECKED);
+       xfs_irele(next_ip);
+       return error;
+}
+
 static int
 xfs_iunlink_insert_inode(
        struct xfs_trans        *tp,
@@ -1926,6 +2011,8 @@ xfs_iunlink_insert_inode(
         * inode.
         */
        error = xfs_iunlink_update_backref(pag, agino, next_agino);
+       if (error == -ENOLINK)
+               error = xfs_iunlink_reload_next(tp, agibp, agino, next_agino);
        if (error)
                return error;
 
@@ -1941,6 +2028,7 @@ xfs_iunlink_insert_inode(
        }
 
        /* Point the head of the list to point to this inode. */
+       ip->i_prev_unlinked = NULLAGINO;
        return xfs_iunlink_update_bucket(tp, pag, agibp, bucket_index, agino);
 }
 
@@ -2020,6 +2108,9 @@ xfs_iunlink_remove_inode(
         */
        error = xfs_iunlink_update_backref(pag, ip->i_prev_unlinked,
                        ip->i_next_unlinked);
+       if (error == -ENOLINK)
+               error = xfs_iunlink_reload_next(tp, agibp, ip->i_prev_unlinked,
+                               ip->i_next_unlinked);
        if (error)
                return error;
 
@@ -2040,7 +2131,7 @@ xfs_iunlink_remove_inode(
        }
 
        ip->i_next_unlinked = NULLAGINO;
-       ip->i_prev_unlinked = NULLAGINO;
+       ip->i_prev_unlinked = 0;
        return error;
 }
 
@@ -3529,3 +3620,117 @@ xfs_iunlock2_io_mmap(
        if (ip1 != ip2)
                inode_unlock(VFS_I(ip1));
 }
+
+/*
+ * Reload the incore inode list for this inode.  Caller should ensure that
+ * the link count cannot change, either by taking ILOCK_SHARED or otherwise
+ * preventing other threads from executing.
+ */
+int
+xfs_inode_reload_unlinked_bucket(
+       struct xfs_trans        *tp,
+       struct xfs_inode        *ip)
+{
+       struct xfs_mount        *mp = tp->t_mountp;
+       struct xfs_buf          *agibp;
+       struct xfs_agi          *agi;
+       struct xfs_perag        *pag;
+       xfs_agnumber_t          agno = XFS_INO_TO_AGNO(mp, ip->i_ino);
+       xfs_agino_t             agino = XFS_INO_TO_AGINO(mp, ip->i_ino);
+       xfs_agino_t             prev_agino, next_agino;
+       unsigned int            bucket;
+       bool                    foundit = false;
+       int                     error;
+
+       /* Grab the first inode in the list */
+       pag = xfs_perag_get(mp, agno);
+       error = xfs_ialloc_read_agi(pag, tp, &agibp);
+       xfs_perag_put(pag);
+       if (error)
+               return error;
+
+       /*
+        * We've taken ILOCK_SHARED and the AGI buffer lock to stabilize the
+        * incore unlinked list pointers for this inode.  Check once more to
+        * see if we raced with anyone else to reload the unlinked list.
+        */
+       if (!xfs_inode_unlinked_incomplete(ip)) {
+               foundit = true;
+               goto out_agibp;
+       }
+
+       bucket = agino % XFS_AGI_UNLINKED_BUCKETS;
+       agi = agibp->b_addr;
+
+       trace_xfs_inode_reload_unlinked_bucket(ip);
+
+       xfs_info_ratelimited(mp,
+ "Found unrecovered unlinked inode 0x%x in AG 0x%x.  Initiating list recovery.",
+                       agino, agno);
+
+       prev_agino = NULLAGINO;
+       next_agino = be32_to_cpu(agi->agi_unlinked[bucket]);
+       while (next_agino != NULLAGINO) {
+               struct xfs_inode        *next_ip = NULL;
+
+               /* Found this caller's inode, set its backlink. */
+               if (next_agino == agino) {
+                       next_ip = ip;
+                       next_ip->i_prev_unlinked = prev_agino;
+                       foundit = true;
+                       goto next_inode;
+               }
+
+               /* Try in-memory lookup first. */
+               next_ip = xfs_iunlink_lookup(pag, next_agino);
+               if (next_ip)
+                       goto next_inode;
+
+               /* Inode not in memory, try reloading it. */
+               error = xfs_iunlink_reload_next(tp, agibp, prev_agino,
+                               next_agino);
+               if (error)
+                       break;
+
+               /* Grab the reloaded inode. */
+               next_ip = xfs_iunlink_lookup(pag, next_agino);
+               if (!next_ip) {
+                       /* No incore inode at all?  We reloaded it... */
+                       ASSERT(next_ip != NULL);
+                       error = -EFSCORRUPTED;
+                       break;
+               }
+
+next_inode:
+               prev_agino = next_agino;
+               next_agino = next_ip->i_next_unlinked;
+       }
+
+out_agibp:
+       xfs_trans_brelse(tp, agibp);
+       /* Should have found this inode somewhere in the iunlinked bucket. */
+       if (!error && !foundit)
+               error = -EFSCORRUPTED;
+       return error;
+}
+
+/* Decide if this inode is missing its unlinked list and reload it. */
+int
+xfs_inode_reload_unlinked(
+       struct xfs_inode        *ip)
+{
+       struct xfs_trans        *tp;
+       int                     error;
+
+       error = xfs_trans_alloc_empty(ip->i_mount, &tp);
+       if (error)
+               return error;
+
+       xfs_ilock(ip, XFS_ILOCK_SHARED);
+       if (xfs_inode_unlinked_incomplete(ip))
+               error = xfs_inode_reload_unlinked_bucket(tp, ip);
+       xfs_iunlock(ip, XFS_ILOCK_SHARED);
+       xfs_trans_cancel(tp);
+
+       return error;
+}
index 7547caf..0c5bdb9 100644 (file)
@@ -68,8 +68,21 @@ typedef struct xfs_inode {
        uint64_t                i_diflags2;     /* XFS_DIFLAG2_... */
        struct timespec64       i_crtime;       /* time created */
 
-       /* unlinked list pointers */
+       /*
+        * Unlinked list pointers.  These point to the next and previous inodes
+        * in the AGI unlinked bucket list, respectively.  These fields can
+        * only be updated with the AGI locked.
+        *
+        * i_next_unlinked caches di_next_unlinked.
+        */
        xfs_agino_t             i_next_unlinked;
+
+       /*
+        * If the inode is not on an unlinked list, this field is zero.  If the
+        * inode is the first element in an unlinked list, this field is
+        * NULLAGINO.  Otherwise, i_prev_unlinked points to the previous inode
+        * in the unlinked list.
+        */
        xfs_agino_t             i_prev_unlinked;
 
        /* VFS inode */
@@ -81,6 +94,11 @@ typedef struct xfs_inode {
        struct list_head        i_ioend_list;
 } xfs_inode_t;
 
+static inline bool xfs_inode_on_unlinked_list(const struct xfs_inode *ip)
+{
+       return ip->i_prev_unlinked != 0;
+}
+
 static inline bool xfs_inode_has_attr_fork(struct xfs_inode *ip)
 {
        return ip->i_forkoff > 0;
@@ -326,6 +344,9 @@ static inline bool xfs_inode_has_large_extent_counts(struct xfs_inode *ip)
  */
 #define XFS_INACTIVATING       (1 << 13)
 
+/* Quotacheck is running but inode has not been added to quota counts. */
+#define XFS_IQUOTAUNCHECKED    (1 << 14)
+
 /* All inode state flags related to inode reclaim. */
 #define XFS_ALL_IRECLAIM_FLAGS (XFS_IRECLAIMABLE | \
                                 XFS_IRECLAIM | \
@@ -340,7 +361,7 @@ static inline bool xfs_inode_has_large_extent_counts(struct xfs_inode *ip)
 #define XFS_IRECLAIM_RESET_FLAGS       \
        (XFS_IRECLAIMABLE | XFS_IRECLAIM | \
         XFS_IDIRTY_RELEASE | XFS_ITRUNCATED | XFS_NEED_INACTIVE | \
-        XFS_INACTIVATING)
+        XFS_INACTIVATING | XFS_IQUOTAUNCHECKED)
 
 /*
  * Flags for inode locking.
@@ -575,4 +596,13 @@ void xfs_end_io(struct work_struct *work);
 int xfs_ilock2_io_mmap(struct xfs_inode *ip1, struct xfs_inode *ip2);
 void xfs_iunlock2_io_mmap(struct xfs_inode *ip1, struct xfs_inode *ip2);
 
+static inline bool
+xfs_inode_unlinked_incomplete(
+       struct xfs_inode        *ip)
+{
+       return VFS_I(ip)->i_nlink == 0 && !xfs_inode_on_unlinked_list(ip);
+}
+int xfs_inode_reload_unlinked_bucket(struct xfs_trans *tp, struct xfs_inode *ip);
+int xfs_inode_reload_unlinked(struct xfs_inode *ip);
+
 #endif /* __XFS_INODE_H__ */
index 2ededd3..1c1e617 100644 (file)
@@ -573,10 +573,10 @@ xfs_vn_getattr(
        stat->gid = vfsgid_into_kgid(vfsgid);
        stat->ino = ip->i_ino;
        stat->atime = inode->i_atime;
+       stat->mtime = inode->i_mtime;
+       stat->ctime = inode_get_ctime(inode);
        stat->blocks = XFS_FSB_TO_BB(mp, ip->i_nblocks + ip->i_delayed_blks);
 
-       fill_mg_cmtime(stat, request_mask, inode);
-
        if (xfs_has_v3inodes(mp)) {
                if (request_mask & STATX_BTIME) {
                        stat->result_mask |= STATX_BTIME;
@@ -917,7 +917,7 @@ xfs_setattr_size(
        if (newsize != oldsize &&
            !(iattr->ia_valid & (ATTR_CTIME | ATTR_MTIME))) {
                iattr->ia_ctime = iattr->ia_mtime =
-                       current_mgtime(inode);
+                       current_time(inode);
                iattr->ia_valid |= ATTR_CTIME | ATTR_MTIME;
        }
 
index c2093cb..f5377ba 100644 (file)
@@ -80,6 +80,17 @@ xfs_bulkstat_one_int(
        if (error)
                goto out;
 
+       /* Reload the incore unlinked list to avoid failure in inodegc. */
+       if (xfs_inode_unlinked_incomplete(ip)) {
+               error = xfs_inode_reload_unlinked_bucket(tp, ip);
+               if (error) {
+                       xfs_iunlock(ip, XFS_ILOCK_SHARED);
+                       xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
+                       xfs_irele(ip);
+                       return error;
+               }
+       }
+
        ASSERT(ip != NULL);
        ASSERT(ip->i_imap.im_blkno != 0);
        inode = VFS_I(ip);
index 79004d1..51c100c 100644 (file)
@@ -715,15 +715,7 @@ xfs_log_mount(
         * just worked.
         */
        if (!xfs_has_norecovery(mp)) {
-               /*
-                * log recovery ignores readonly state and so we need to clear
-                * mount-based read only state so it can write to disk.
-                */
-               bool    readonly = test_and_clear_bit(XFS_OPSTATE_READONLY,
-                                               &mp->m_opstate);
                error = xlog_recover(log);
-               if (readonly)
-                       set_bit(XFS_OPSTATE_READONLY, &mp->m_opstate);
                if (error) {
                        xfs_warn(mp, "log mount/recovery failed: error %d",
                                error);
@@ -772,7 +764,6 @@ xfs_log_mount_finish(
        struct xfs_mount        *mp)
 {
        struct xlog             *log = mp->m_log;
-       bool                    readonly;
        int                     error = 0;
 
        if (xfs_has_norecovery(mp)) {
@@ -781,12 +772,6 @@ xfs_log_mount_finish(
        }
 
        /*
-        * log recovery ignores readonly state and so we need to clear
-        * mount-based read only state so it can write to disk.
-        */
-       readonly = test_and_clear_bit(XFS_OPSTATE_READONLY, &mp->m_opstate);
-
-       /*
         * During the second phase of log recovery, we need iget and
         * iput to behave like they do for an active filesystem.
         * xfs_fs_drop_inode needs to be able to prevent the deletion
@@ -835,8 +820,6 @@ xfs_log_mount_finish(
        xfs_buftarg_drain(mp->m_ddev_targp);
 
        clear_bit(XLOG_RECOVERY_NEEDED, &log->l_opstate);
-       if (readonly)
-               set_bit(XFS_OPSTATE_READONLY, &mp->m_opstate);
 
        /* Make sure the log is dead if we're returning failure. */
        ASSERT(!error || xlog_is_shutdown(log));
index eccbfb9..67a99d9 100644 (file)
@@ -16,8 +16,7 @@
 #include "xfs_log.h"
 #include "xfs_log_priv.h"
 #include "xfs_trace.h"
-
-struct workqueue_struct *xfs_discard_wq;
+#include "xfs_discard.h"
 
 /*
  * Allocate a new ticket. Failing to get a new ticket makes it really hard to
@@ -103,7 +102,7 @@ xlog_cil_ctx_alloc(void)
 
        ctx = kmem_zalloc(sizeof(*ctx), KM_NOFS);
        INIT_LIST_HEAD(&ctx->committing);
-       INIT_LIST_HEAD(&ctx->busy_extents);
+       INIT_LIST_HEAD(&ctx->busy_extents.extent_list);
        INIT_LIST_HEAD(&ctx->log_items);
        INIT_LIST_HEAD(&ctx->lv_chain);
        INIT_WORK(&ctx->push_work, xlog_cil_push_work);
@@ -124,7 +123,7 @@ xlog_cil_push_pcp_aggregate(
        struct xlog_cil_pcp     *cilpcp;
        int                     cpu;
 
-       for_each_online_cpu(cpu) {
+       for_each_cpu(cpu, &ctx->cil_pcpmask) {
                cilpcp = per_cpu_ptr(cil->xc_pcp, cpu);
 
                ctx->ticket->t_curr_res += cilpcp->space_reserved;
@@ -132,7 +131,7 @@ xlog_cil_push_pcp_aggregate(
 
                if (!list_empty(&cilpcp->busy_extents)) {
                        list_splice_init(&cilpcp->busy_extents,
-                                       &ctx->busy_extents);
+                                       &ctx->busy_extents.extent_list);
                }
                if (!list_empty(&cilpcp->log_items))
                        list_splice_init(&cilpcp->log_items, &ctx->log_items);
@@ -165,7 +164,13 @@ xlog_cil_insert_pcp_aggregate(
        if (!test_and_clear_bit(XLOG_CIL_PCP_SPACE, &cil->xc_flags))
                return;
 
-       for_each_online_cpu(cpu) {
+       /*
+        * We can race with other cpus setting cil_pcpmask.  However, we've
+        * atomically cleared PCP_SPACE which forces other threads to add to
+        * the global space used count.  cil_pcpmask is a superset of cilpcp
+        * structures that could have a nonzero space_used.
+        */
+       for_each_cpu(cpu, &ctx->cil_pcpmask) {
                int     old, prev;
 
                cilpcp = per_cpu_ptr(cil->xc_pcp, cpu);
@@ -554,6 +559,7 @@ xlog_cil_insert_items(
        int                     iovhdr_res = 0, split_res = 0, ctx_res = 0;
        int                     space_used;
        int                     order;
+       unsigned int            cpu_nr;
        struct xlog_cil_pcp     *cilpcp;
 
        ASSERT(tp);
@@ -577,7 +583,12 @@ xlog_cil_insert_items(
         * can't be scheduled away between split sample/update operations that
         * are done without outside locking to serialise them.
         */
-       cilpcp = get_cpu_ptr(cil->xc_pcp);
+       cpu_nr = get_cpu();
+       cilpcp = this_cpu_ptr(cil->xc_pcp);
+
+       /* Tell the future push that there was work added by this CPU. */
+       if (!cpumask_test_cpu(cpu_nr, &ctx->cil_pcpmask))
+               cpumask_test_and_set_cpu(cpu_nr, &ctx->cil_pcpmask);
 
        /*
         * We need to take the CIL checkpoint unit reservation on the first
@@ -663,7 +674,7 @@ xlog_cil_insert_items(
                        continue;
                list_add_tail(&lip->li_cil, &cilpcp->log_items);
        }
-       put_cpu_ptr(cilpcp);
+       put_cpu();
 
        /*
         * If we've overrun the reservation, dump the tx details before we move
@@ -696,76 +707,6 @@ xlog_cil_free_logvec(
        }
 }
 
-static void
-xlog_discard_endio_work(
-       struct work_struct      *work)
-{
-       struct xfs_cil_ctx      *ctx =
-               container_of(work, struct xfs_cil_ctx, discard_endio_work);
-       struct xfs_mount        *mp = ctx->cil->xc_log->l_mp;
-
-       xfs_extent_busy_clear(mp, &ctx->busy_extents, false);
-       kmem_free(ctx);
-}
-
-/*
- * Queue up the actual completion to a thread to avoid IRQ-safe locking for
- * pagb_lock.  Note that we need a unbounded workqueue, otherwise we might
- * get the execution delayed up to 30 seconds for weird reasons.
- */
-static void
-xlog_discard_endio(
-       struct bio              *bio)
-{
-       struct xfs_cil_ctx      *ctx = bio->bi_private;
-
-       INIT_WORK(&ctx->discard_endio_work, xlog_discard_endio_work);
-       queue_work(xfs_discard_wq, &ctx->discard_endio_work);
-       bio_put(bio);
-}
-
-static void
-xlog_discard_busy_extents(
-       struct xfs_mount        *mp,
-       struct xfs_cil_ctx      *ctx)
-{
-       struct list_head        *list = &ctx->busy_extents;
-       struct xfs_extent_busy  *busyp;
-       struct bio              *bio = NULL;
-       struct blk_plug         plug;
-       int                     error = 0;
-
-       ASSERT(xfs_has_discard(mp));
-
-       blk_start_plug(&plug);
-       list_for_each_entry(busyp, list, list) {
-               trace_xfs_discard_extent(mp, busyp->agno, busyp->bno,
-                                        busyp->length);
-
-               error = __blkdev_issue_discard(mp->m_ddev_targp->bt_bdev,
-                               XFS_AGB_TO_DADDR(mp, busyp->agno, busyp->bno),
-                               XFS_FSB_TO_BB(mp, busyp->length),
-                               GFP_NOFS, &bio);
-               if (error && error != -EOPNOTSUPP) {
-                       xfs_info(mp,
-        "discard failed for extent [0x%llx,%u], error %d",
-                                (unsigned long long)busyp->bno,
-                                busyp->length,
-                                error);
-                       break;
-               }
-       }
-
-       if (bio) {
-               bio->bi_private = ctx;
-               bio->bi_end_io = xlog_discard_endio;
-               submit_bio(bio);
-       } else {
-               xlog_discard_endio_work(&ctx->discard_endio_work);
-       }
-       blk_finish_plug(&plug);
-}
-
 /*
  * Mark all items committed and clear busy extents. We free the log vector
  * chains in a separate pass so that we unpin the log items as quickly as
@@ -795,8 +736,8 @@ xlog_cil_committed(
        xfs_trans_committed_bulk(ctx->cil->xc_log->l_ailp, &ctx->lv_chain,
                                        ctx->start_lsn, abort);
 
-       xfs_extent_busy_sort(&ctx->busy_extents);
-       xfs_extent_busy_clear(mp, &ctx->busy_extents,
+       xfs_extent_busy_sort(&ctx->busy_extents.extent_list);
+       xfs_extent_busy_clear(mp, &ctx->busy_extents.extent_list,
                              xfs_has_discard(mp) && !abort);
 
        spin_lock(&ctx->cil->xc_push_lock);
@@ -805,10 +746,14 @@ xlog_cil_committed(
 
        xlog_cil_free_logvec(&ctx->lv_chain);
 
-       if (!list_empty(&ctx->busy_extents))
-               xlog_discard_busy_extents(mp, ctx);
-       else
-               kmem_free(ctx);
+       if (!list_empty(&ctx->busy_extents.extent_list)) {
+               ctx->busy_extents.mount = mp;
+               ctx->busy_extents.owner = ctx;
+               xfs_discard_extents(mp, &ctx->busy_extents);
+               return;
+       }
+
+       kmem_free(ctx);
 }
 
 void
@@ -1791,38 +1736,6 @@ out_shutdown:
 }
 
 /*
- * Move dead percpu state to the relevant CIL context structures.
- *
- * We have to lock the CIL context here to ensure that nothing is modifying
- * the percpu state, either addition or removal. Both of these are done under
- * the CIL context lock, so grabbing that exclusively here will ensure we can
- * safely drain the cilpcp for the CPU that is dying.
- */
-void
-xlog_cil_pcp_dead(
-       struct xlog             *log,
-       unsigned int            cpu)
-{
-       struct xfs_cil          *cil = log->l_cilp;
-       struct xlog_cil_pcp     *cilpcp = per_cpu_ptr(cil->xc_pcp, cpu);
-       struct xfs_cil_ctx      *ctx;
-
-       down_write(&cil->xc_ctx_lock);
-       ctx = cil->xc_ctx;
-       if (ctx->ticket)
-               ctx->ticket->t_curr_res += cilpcp->space_reserved;
-       cilpcp->space_reserved = 0;
-
-       if (!list_empty(&cilpcp->log_items))
-               list_splice_init(&cilpcp->log_items, &ctx->log_items);
-       if (!list_empty(&cilpcp->busy_extents))
-               list_splice_init(&cilpcp->busy_extents, &ctx->busy_extents);
-       atomic_add(cilpcp->space_used, &ctx->space_used);
-       cilpcp->space_used = 0;
-       up_write(&cil->xc_ctx_lock);
-}
-
-/*
  * Perform initial CIL structure initialisation.
  */
 int
index 1bd2963..fa3ad1d 100644 (file)
@@ -6,6 +6,8 @@
 #ifndef        __XFS_LOG_PRIV_H__
 #define __XFS_LOG_PRIV_H__
 
+#include "xfs_extent_busy.h"   /* for struct xfs_busy_extents */
+
 struct xfs_buf;
 struct xlog;
 struct xlog_ticket;
@@ -223,14 +225,19 @@ struct xfs_cil_ctx {
        struct xlog_in_core     *commit_iclog;
        struct xlog_ticket      *ticket;        /* chkpt ticket */
        atomic_t                space_used;     /* aggregate size of regions */
-       struct list_head        busy_extents;   /* busy extents in chkpt */
+       struct xfs_busy_extents busy_extents;
        struct list_head        log_items;      /* log items in chkpt */
        struct list_head        lv_chain;       /* logvecs being pushed */
        struct list_head        iclog_entry;
        struct list_head        committing;     /* ctx committing list */
-       struct work_struct      discard_endio_work;
        struct work_struct      push_work;
        atomic_t                order_id;
+
+       /*
+        * CPUs that could have added items to the percpu CIL data.  Access is
+        * coordinated with xc_ctx_lock.
+        */
+       struct cpumask          cil_pcpmask;
 };
 
 /*
@@ -278,9 +285,6 @@ struct xfs_cil {
        wait_queue_head_t       xc_push_wait;   /* background push throttle */
 
        void __percpu           *xc_pcp;        /* percpu CIL structures */
-#ifdef CONFIG_HOTPLUG_CPU
-       struct list_head        xc_pcp_list;
-#endif
 } ____cacheline_aligned_in_smp;
 
 /* xc_flags bit values */
@@ -705,9 +709,4 @@ xlog_kvmalloc(
        return p;
 }
 
-/*
- * CIL CPU dead notifier
- */
-void xlog_cil_pcp_dead(struct xlog *log, unsigned int cpu);
-
 #endif /* __XFS_LOG_PRIV_H__ */
index 82c81d2..13b94d2 100644 (file)
@@ -329,7 +329,7 @@ xlog_find_verify_cycle(
         * try a smaller size.  We need to be able to read at least
         * a log sector, or we're out of luck.
         */
-       bufblks = 1 << ffs(nbblks);
+       bufblks = roundup_pow_of_two(nbblks);
        while (bufblks > log->l_logBBsize)
                bufblks >>= 1;
        while (!(buffer = xlog_alloc_buffer(log, bufblks))) {
@@ -1528,7 +1528,7 @@ xlog_write_log_records(
         * a smaller size.  We need to be able to write at least a
         * log sector, or we're out of luck.
         */
-       bufblks = 1 << ffs(blocks);
+       bufblks = roundup_pow_of_two(blocks);
        while (bufblks > log->l_logBBsize)
                bufblks >>= 1;
        while (!(buffer = xlog_alloc_buffer(log, bufblks))) {
index a25eece..d19cca0 100644 (file)
@@ -60,6 +60,7 @@ struct xfs_error_cfg {
  * Per-cpu deferred inode inactivation GC lists.
  */
 struct xfs_inodegc {
+       struct xfs_mount        *mp;
        struct llist_head       list;
        struct delayed_work     work;
        int                     error;
@@ -67,9 +68,7 @@ struct xfs_inodegc {
        /* approximate count of inodes in the list */
        unsigned int            items;
        unsigned int            shrinker_hits;
-#if defined(DEBUG) || defined(XFS_WARN)
        unsigned int            cpu;
-#endif
 };
 
 /*
@@ -98,7 +97,6 @@ typedef struct xfs_mount {
        xfs_buftarg_t           *m_ddev_targp;  /* saves taking the address */
        xfs_buftarg_t           *m_logdev_targp;/* ptr to log device */
        xfs_buftarg_t           *m_rtdev_targp; /* ptr to rt device */
-       struct list_head        m_mount_list;   /* global mount list */
        void __percpu           *m_inodegc;     /* percpu inodegc structures */
 
        /*
@@ -249,6 +247,9 @@ typedef struct xfs_mount {
        unsigned int            *m_errortag;
        struct xfs_kobj         m_errortag_kobj;
 #endif
+
+       /* cpus that have inodes queued for inactivation */
+       struct cpumask          m_inodegc_cpumask;
 } xfs_mount_t;
 
 #define M_IGEO(mp)             (&(mp)->m_ino_geo)
@@ -404,6 +405,8 @@ __XFS_HAS_FEAT(nouuid, NOUUID)
 #define XFS_OPSTATE_WARNED_SHRINK      8
 /* Kernel has logged a warning about logged xattr updates being used. */
 #define XFS_OPSTATE_WARNED_LARP                9
+/* Mount time quotacheck is running */
+#define XFS_OPSTATE_QUOTACHECK_RUNNING 10
 
 #define __XFS_IS_OPSTATE(name, NAME) \
 static inline bool xfs_is_ ## name (struct xfs_mount *mp) \
@@ -426,6 +429,11 @@ __XFS_IS_OPSTATE(inode32, INODE32)
 __XFS_IS_OPSTATE(readonly, READONLY)
 __XFS_IS_OPSTATE(inodegc_enabled, INODEGC_ENABLED)
 __XFS_IS_OPSTATE(blockgc_enabled, BLOCKGC_ENABLED)
+#ifdef CONFIG_XFS_QUOTA
+__XFS_IS_OPSTATE(quotacheck_running, QUOTACHECK_RUNNING)
+#else
+# define xfs_is_quotacheck_running(mp) (false)
+#endif
 
 static inline bool
 xfs_should_warn(struct xfs_mount *mp, long nr)
@@ -443,7 +451,8 @@ xfs_should_warn(struct xfs_mount *mp, long nr)
        { (1UL << XFS_OPSTATE_BLOCKGC_ENABLED),         "blockgc" }, \
        { (1UL << XFS_OPSTATE_WARNED_SCRUB),            "wscrub" }, \
        { (1UL << XFS_OPSTATE_WARNED_SHRINK),           "wshrink" }, \
-       { (1UL << XFS_OPSTATE_WARNED_LARP),             "wlarp" }
+       { (1UL << XFS_OPSTATE_WARNED_LARP),             "wlarp" }, \
+       { (1UL << XFS_OPSTATE_QUOTACHECK_RUNNING),      "quotacheck" }
 
 /*
  * Max and min values for mount-option defined I/O
index 6abcc34..086e78a 100644 (file)
@@ -1160,6 +1160,19 @@ xfs_qm_dqusage_adjust(
        if (error)
                return error;
 
+       /*
+        * Reload the incore unlinked list to avoid failure in inodegc.
+        * Use an unlocked check here because unrecovered unlinked inodes
+        * should be somewhat rare.
+        */
+       if (xfs_inode_unlinked_incomplete(ip)) {
+               error = xfs_inode_reload_unlinked(ip);
+               if (error) {
+                       xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
+                       goto error0;
+               }
+       }
+
        ASSERT(ip->i_delayed_blks == 0);
 
        if (XFS_IS_REALTIME_INODE(ip)) {
@@ -1173,6 +1186,7 @@ xfs_qm_dqusage_adjust(
        }
 
        nblks = (xfs_qcnt_t)ip->i_nblocks - rtblks;
+       xfs_iflags_clear(ip, XFS_IQUOTAUNCHECKED);
 
        /*
         * Add the (disk blocks and inode) resources occupied by this
@@ -1319,8 +1333,10 @@ xfs_qm_quotacheck(
                flags |= XFS_PQUOTA_CHKD;
        }
 
+       xfs_set_quotacheck_running(mp);
        error = xfs_iwalk_threaded(mp, 0, 0, xfs_qm_dqusage_adjust, 0, true,
                        NULL);
+       xfs_clear_quotacheck_running(mp);
 
        /*
         * On error, the inode walk may have partially populated the dquot
index edd8587..2d4444d 100644 (file)
@@ -477,6 +477,7 @@ xfs_cui_item_recover(
        struct xfs_log_item             *lip,
        struct list_head                *capture_list)
 {
+       struct xfs_trans_res            resv;
        struct xfs_cui_log_item         *cuip = CUI_ITEM(lip);
        struct xfs_cud_log_item         *cudp;
        struct xfs_trans                *tp;
@@ -514,8 +515,9 @@ xfs_cui_item_recover(
         * doesn't fit.  We need to reserve enough blocks to handle a
         * full btree split on either end of the refcount range.
         */
-       error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate,
-                       mp->m_refc_maxlevels * 2, 0, XFS_TRANS_RESERVE, &tp);
+       resv = xlog_recover_resv(&M_RES(mp)->tr_itruncate);
+       error = xfs_trans_alloc(mp, &resv, mp->m_refc_maxlevels * 2, 0,
+                       XFS_TRANS_RESERVE, &tp);
        if (error)
                return error;
 
index 520c7eb..0e0e747 100644 (file)
@@ -507,6 +507,7 @@ xfs_rui_item_recover(
        struct xfs_log_item             *lip,
        struct list_head                *capture_list)
 {
+       struct xfs_trans_res            resv;
        struct xfs_rui_log_item         *ruip = RUI_ITEM(lip);
        struct xfs_rud_log_item         *rudp;
        struct xfs_trans                *tp;
@@ -530,8 +531,9 @@ xfs_rui_item_recover(
                }
        }
 
-       error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate,
-                       mp->m_rmap_maxlevels, 0, XFS_TRANS_RESERVE, &tp);
+       resv = xlog_recover_resv(&M_RES(mp)->tr_itruncate);
+       error = xfs_trans_alloc(mp, &resv, mp->m_rmap_maxlevels, 0,
+                       XFS_TRANS_RESERVE, &tp);
        if (error)
                return error;
        rudp = xfs_trans_get_rud(tp, ruip);
index 1f77014..819a356 100644 (file)
@@ -56,28 +56,6 @@ static struct kset *xfs_kset;                /* top-level xfs sysfs dir */
 static struct xfs_kobj xfs_dbg_kobj;   /* global debug sysfs attrs */
 #endif
 
-#ifdef CONFIG_HOTPLUG_CPU
-static LIST_HEAD(xfs_mount_list);
-static DEFINE_SPINLOCK(xfs_mount_list_lock);
-
-static inline void xfs_mount_list_add(struct xfs_mount *mp)
-{
-       spin_lock(&xfs_mount_list_lock);
-       list_add(&mp->m_mount_list, &xfs_mount_list);
-       spin_unlock(&xfs_mount_list_lock);
-}
-
-static inline void xfs_mount_list_del(struct xfs_mount *mp)
-{
-       spin_lock(&xfs_mount_list_lock);
-       list_del(&mp->m_mount_list);
-       spin_unlock(&xfs_mount_list_lock);
-}
-#else /* !CONFIG_HOTPLUG_CPU */
-static inline void xfs_mount_list_add(struct xfs_mount *mp) {}
-static inline void xfs_mount_list_del(struct xfs_mount *mp) {}
-#endif
-
 enum xfs_dax_mode {
        XFS_DAX_INODE = 0,
        XFS_DAX_ALWAYS = 1,
@@ -1135,9 +1113,8 @@ xfs_inodegc_init_percpu(
 
        for_each_possible_cpu(cpu) {
                gc = per_cpu_ptr(mp->m_inodegc, cpu);
-#if defined(DEBUG) || defined(XFS_WARN)
                gc->cpu = cpu;
-#endif
+               gc->mp = mp;
                init_llist_head(&gc->list);
                gc->items = 0;
                gc->error = 0;
@@ -1168,7 +1145,6 @@ xfs_fs_put_super(
        xfs_freesb(mp);
        xchk_mount_stats_free(mp);
        free_percpu(mp->m_stats.xs_stats);
-       xfs_mount_list_del(mp);
        xfs_inodegc_free_percpu(mp);
        xfs_destroy_percpu_counters(mp);
        xfs_destroy_mount_workqueues(mp);
@@ -1577,13 +1553,6 @@ xfs_fs_fill_super(
        if (error)
                goto out_destroy_counters;
 
-       /*
-        * All percpu data structures requiring cleanup when a cpu goes offline
-        * must be allocated before adding this @mp to the cpu-dead handler's
-        * mount list.
-        */
-       xfs_mount_list_add(mp);
-
        /* Allocate stats memory before we do operations that might use it */
        mp->m_stats.xs_stats = alloc_percpu(struct xfsstats);
        if (!mp->m_stats.xs_stats) {
@@ -1781,7 +1750,6 @@ xfs_fs_fill_super(
  out_free_stats:
        free_percpu(mp->m_stats.xs_stats);
  out_destroy_inodegc:
-       xfs_mount_list_del(mp);
        xfs_inodegc_free_percpu(mp);
  out_destroy_counters:
        xfs_destroy_percpu_counters(mp);
@@ -2065,7 +2033,7 @@ static struct file_system_type xfs_fs_type = {
        .init_fs_context        = xfs_init_fs_context,
        .parameters             = xfs_fs_parameters,
        .kill_sb                = xfs_kill_sb,
-       .fs_flags               = FS_REQUIRES_DEV | FS_ALLOW_IDMAP | FS_MGTIME,
+       .fs_flags               = FS_REQUIRES_DEV | FS_ALLOW_IDMAP,
 };
 MODULE_ALIAS_FS("xfs");
 
@@ -2326,49 +2294,6 @@ xfs_destroy_workqueues(void)
        destroy_workqueue(xfs_alloc_wq);
 }
 
-#ifdef CONFIG_HOTPLUG_CPU
-static int
-xfs_cpu_dead(
-       unsigned int            cpu)
-{
-       struct xfs_mount        *mp, *n;
-
-       spin_lock(&xfs_mount_list_lock);
-       list_for_each_entry_safe(mp, n, &xfs_mount_list, m_mount_list) {
-               spin_unlock(&xfs_mount_list_lock);
-               xfs_inodegc_cpu_dead(mp, cpu);
-               xlog_cil_pcp_dead(mp->m_log, cpu);
-               spin_lock(&xfs_mount_list_lock);
-       }
-       spin_unlock(&xfs_mount_list_lock);
-       return 0;
-}
-
-static int __init
-xfs_cpu_hotplug_init(void)
-{
-       int     error;
-
-       error = cpuhp_setup_state_nocalls(CPUHP_XFS_DEAD, "xfs:dead", NULL,
-                       xfs_cpu_dead);
-       if (error < 0)
-               xfs_alert(NULL,
-"Failed to initialise CPU hotplug, error %d. XFS is non-functional.",
-                       error);
-       return error;
-}
-
-static void
-xfs_cpu_hotplug_destroy(void)
-{
-       cpuhp_remove_state_nocalls(CPUHP_XFS_DEAD);
-}
-
-#else /* !CONFIG_HOTPLUG_CPU */
-static inline int xfs_cpu_hotplug_init(void) { return 0; }
-static inline void xfs_cpu_hotplug_destroy(void) {}
-#endif
-
 STATIC int __init
 init_xfs_fs(void)
 {
@@ -2385,13 +2310,9 @@ init_xfs_fs(void)
 
        xfs_dir_startup();
 
-       error = xfs_cpu_hotplug_init();
-       if (error)
-               goto out;
-
        error = xfs_init_caches();
        if (error)
-               goto out_destroy_hp;
+               goto out;
 
        error = xfs_init_workqueues();
        if (error)
@@ -2475,8 +2396,6 @@ init_xfs_fs(void)
        xfs_destroy_workqueues();
  out_destroy_caches:
        xfs_destroy_caches();
- out_destroy_hp:
-       xfs_cpu_hotplug_destroy();
  out:
        return error;
 }
@@ -2500,7 +2419,6 @@ exit_xfs_fs(void)
        xfs_destroy_workqueues();
        xfs_destroy_caches();
        xfs_uuid_table_free();
-       xfs_cpu_hotplug_destroy();
 }
 
 module_init(init_xfs_fs);
index 902c7f6..3926cf7 100644 (file)
@@ -3824,6 +3824,51 @@ TRACE_EVENT(xfs_iunlink_update_dinode,
                  __entry->new_ptr)
 );
 
+TRACE_EVENT(xfs_iunlink_reload_next,
+       TP_PROTO(struct xfs_inode *ip),
+       TP_ARGS(ip),
+       TP_STRUCT__entry(
+               __field(dev_t, dev)
+               __field(xfs_agnumber_t, agno)
+               __field(xfs_agino_t, agino)
+               __field(xfs_agino_t, prev_agino)
+               __field(xfs_agino_t, next_agino)
+       ),
+       TP_fast_assign(
+               __entry->dev = ip->i_mount->m_super->s_dev;
+               __entry->agno = XFS_INO_TO_AGNO(ip->i_mount, ip->i_ino);
+               __entry->agino = XFS_INO_TO_AGINO(ip->i_mount, ip->i_ino);
+               __entry->prev_agino = ip->i_prev_unlinked;
+               __entry->next_agino = ip->i_next_unlinked;
+       ),
+       TP_printk("dev %d:%d agno 0x%x agino 0x%x prev_unlinked 0x%x next_unlinked 0x%x",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 __entry->agno,
+                 __entry->agino,
+                 __entry->prev_agino,
+                 __entry->next_agino)
+);
+
+TRACE_EVENT(xfs_inode_reload_unlinked_bucket,
+       TP_PROTO(struct xfs_inode *ip),
+       TP_ARGS(ip),
+       TP_STRUCT__entry(
+               __field(dev_t, dev)
+               __field(xfs_agnumber_t, agno)
+               __field(xfs_agino_t, agino)
+       ),
+       TP_fast_assign(
+               __entry->dev = ip->i_mount->m_super->s_dev;
+               __entry->agno = XFS_INO_TO_AGNO(ip->i_mount, ip->i_ino);
+               __entry->agino = XFS_INO_TO_AGINO(ip->i_mount, ip->i_ino);
+       ),
+       TP_printk("dev %d:%d agno 0x%x agino 0x%x bucket %u",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 __entry->agno,
+                 __entry->agino,
+                 __entry->agino % XFS_AGI_UNLINKED_BUCKETS)
+);
+
 DECLARE_EVENT_CLASS(xfs_ag_inode_class,
        TP_PROTO(struct xfs_inode *ip),
        TP_ARGS(ip),
index 43e5c21..a3975f3 100644 (file)
@@ -46,6 +46,17 @@ xfs_attr_grab_log_assist(
        if (xfs_sb_version_haslogxattrs(&mp->m_sb))
                return 0;
 
+       /*
+        * Check if the filesystem featureset is new enough to set this log
+        * incompat feature bit.  Strictly speaking, the minimum requirement is
+        * a V5 filesystem for the superblock field, but we'll require rmap
+        * or reflink to avoid having to deal with really old kernels.
+        */
+       if (!xfs_has_reflink(mp) && !xfs_has_rmapbt(mp)) {
+               error = -EOPNOTSUPP;
+               goto drop_incompat;
+       }
+
        /* Enable log-assisted xattrs. */
        error = xfs_add_incompat_log_feature(mp,
                        XFS_SB_FEAT_INCOMPAT_LOG_XATTRS);
index 4da0279..6dcf4d5 100644 (file)
@@ -76,7 +76,7 @@ static inline void hugetlb_free_pgd_range(struct mmu_gather *tlb,
 
 #ifndef __HAVE_ARCH_HUGE_SET_HUGE_PTE_AT
 static inline void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
-               pte_t *ptep, pte_t pte)
+               pte_t *ptep, pte_t pte, unsigned long sz)
 {
        set_pte_at(mm, addr, ptep, pte);
 }
index cecd2b7..430f0ae 100644 (file)
@@ -36,6 +36,7 @@ struct ms_hyperv_info {
        u32 nested_features;
        u32 max_vp_index;
        u32 max_lp_index;
+       u8 vtl;
        union {
                u32 isolation_config_a;
                struct {
@@ -54,7 +55,6 @@ struct ms_hyperv_info {
                };
        };
        u64 shared_gpa_boundary;
-       u8 vtl;
 };
 extern struct ms_hyperv_info ms_hyperv;
 extern bool hv_nested;
index 9c59409..67d8dd2 100644 (file)
  * are handled as text/data or they can be discarded (which
  * often happens at runtime)
  */
-#ifdef CONFIG_HOTPLUG_CPU
-#define CPU_KEEP(sec)    *(.cpu##sec)
-#define CPU_DISCARD(sec)
-#else
-#define CPU_KEEP(sec)
-#define CPU_DISCARD(sec) *(.cpu##sec)
-#endif
 
 #if defined(CONFIG_MEMORY_HOTPLUG)
 #define MEM_KEEP(sec)    *(.mem##sec)
index bb3cb00..e748bc9 100644 (file)
@@ -82,6 +82,8 @@ struct timer_map {
        struct arch_timer_context *emul_ptimer;
 };
 
+void get_timer_map(struct kvm_vcpu *vcpu, struct timer_map *map);
+
 struct arch_timer_cpu {
        struct arch_timer_context timers[NR_KVM_TIMERS];
 
@@ -145,4 +147,9 @@ u64 timer_get_cval(struct arch_timer_context *ctxt);
 void kvm_timer_cpu_up(void);
 void kvm_timer_cpu_down(void);
 
+static inline bool has_cntpoff(void)
+{
+       return (has_vhe() && cpus_have_final_cap(ARM64_HAS_ECV_CNTPOFF));
+}
+
 #endif
index a73246c..afd94c9 100644 (file)
@@ -1480,6 +1480,15 @@ static inline int lpit_read_residency_count_address(u64 *address)
 }
 #endif
 
+#ifdef CONFIG_ACPI_PROCESSOR_IDLE
+#ifndef arch_get_idle_state_flags
+static inline unsigned int arch_get_idle_state_flags(u32 arch_flags)
+{
+       return 0;
+}
+#endif
+#endif /* CONFIG_ACPI_PROCESSOR_IDLE */
+
 #ifdef CONFIG_ACPI_PPTT
 int acpi_pptt_cpu_is_thread(unsigned int cpu);
 int find_acpi_cpu_topology(unsigned int cpu, int level);
index 2dd175f..29cc102 100644 (file)
@@ -42,11 +42,13 @@ struct aer_capability_regs {
 
 #if defined(CONFIG_PCIEAER)
 int pci_aer_clear_nonfatal_status(struct pci_dev *dev);
+int pcie_aer_is_native(struct pci_dev *dev);
 #else
 static inline int pci_aer_clear_nonfatal_status(struct pci_dev *dev)
 {
        return -EINVAL;
 }
+static inline int pcie_aer_is_native(struct pci_dev *dev) { return 0; }
 #endif
 
 void cper_print_aer(struct pci_dev *dev, int aer_severity,
index 18f5744..b83ef19 100644 (file)
@@ -459,8 +459,6 @@ raw_atomic_read_acquire(const atomic_t *v)
 {
 #if defined(arch_atomic_read_acquire)
        return arch_atomic_read_acquire(v);
-#elif defined(arch_atomic_read)
-       return arch_atomic_read(v);
 #else
        int ret;
 
@@ -508,8 +506,6 @@ raw_atomic_set_release(atomic_t *v, int i)
 {
 #if defined(arch_atomic_set_release)
        arch_atomic_set_release(v, i);
-#elif defined(arch_atomic_set)
-       arch_atomic_set(v, i);
 #else
        if (__native_word(atomic_t)) {
                smp_store_release(&(v)->counter, i);
@@ -2575,8 +2571,6 @@ raw_atomic64_read_acquire(const atomic64_t *v)
 {
 #if defined(arch_atomic64_read_acquire)
        return arch_atomic64_read_acquire(v);
-#elif defined(arch_atomic64_read)
-       return arch_atomic64_read(v);
 #else
        s64 ret;
 
@@ -2624,8 +2618,6 @@ raw_atomic64_set_release(atomic64_t *v, s64 i)
 {
 #if defined(arch_atomic64_set_release)
        arch_atomic64_set_release(v, i);
-#elif defined(arch_atomic64_set)
-       arch_atomic64_set(v, i);
 #else
        if (__native_word(atomic64_t)) {
                smp_store_release(&(v)->counter, i);
@@ -4657,4 +4649,4 @@ raw_atomic64_dec_if_positive(atomic64_t *v)
 }
 
 #endif /* _LINUX_ATOMIC_FALLBACK_H */
-// 202b45c7db600ce36198eb1f1fc2c2d5268ace2d
+// 2fdd6702823fa842f9cea57a002e6e4476ae780c
index 024e8b2..49f8b69 100644 (file)
@@ -1307,7 +1307,7 @@ static inline int bpf_trampoline_unlink_prog(struct bpf_tramp_link *link,
 static inline struct bpf_trampoline *bpf_trampoline_get(u64 key,
                                                        struct bpf_attach_target_info *tgt_info)
 {
-       return ERR_PTR(-EOPNOTSUPP);
+       return NULL;
 }
 static inline void bpf_trampoline_put(struct bpf_trampoline *tr) {}
 #define DEFINE_BPF_DISPATCHER(name)
index a3462a9..a9cb10b 100644 (file)
@@ -49,7 +49,7 @@ word                                                  \
        ____BTF_ID(symbol, word)
 
 #define __ID(prefix) \
-       __PASTE(prefix, __COUNTER__)
+       __PASTE(__PASTE(prefix, __COUNTER__), __LINE__)
 
 /*
  * The BTF_ID defines unique symbol for each ID pointing
index 5f2301e..f3b3593 100644 (file)
@@ -467,19 +467,17 @@ union ceph_mds_request_args {
 } __attribute__ ((packed));
 
 union ceph_mds_request_args_ext {
-       union {
-               union ceph_mds_request_args old;
-               struct {
-                       __le32 mode;
-                       __le32 uid;
-                       __le32 gid;
-                       struct ceph_timespec mtime;
-                       struct ceph_timespec atime;
-                       __le64 size, old_size;       /* old_size needed by truncate */
-                       __le32 mask;                 /* CEPH_SETATTR_* */
-                       struct ceph_timespec btime;
-               } __attribute__ ((packed)) setattr_ext;
-       };
+       union ceph_mds_request_args old;
+       struct {
+               __le32 mode;
+               __le32 uid;
+               __le32 gid;
+               struct ceph_timespec mtime;
+               struct ceph_timespec atime;
+               __le64 size, old_size;       /* old_size needed by truncate */
+               __le32 mask;                 /* CEPH_SETATTR_* */
+               struct ceph_timespec btime;
+       } __attribute__ ((packed)) setattr_ext;
 };
 
 #define CEPH_MDS_FLAG_REPLAY           1 /* this is a replayed op */
index 06dda85..068f773 100644 (file)
@@ -90,7 +90,6 @@ enum cpuhp_state {
        CPUHP_FS_BUFF_DEAD,
        CPUHP_PRINTK_DEAD,
        CPUHP_MM_MEMCQ_DEAD,
-       CPUHP_XFS_DEAD,
        CPUHP_PERCPU_CNT_DEAD,
        CPUHP_RADIX_DEAD,
        CPUHP_PAGE_ALLOC,
index 4aeb3fa..b528f06 100644 (file)
@@ -1508,47 +1508,18 @@ static inline bool fsuidgid_has_mapping(struct super_block *sb,
               kgid_has_mapping(fs_userns, kgid);
 }
 
-struct timespec64 current_mgtime(struct inode *inode);
 struct timespec64 current_time(struct inode *inode);
 struct timespec64 inode_set_ctime_current(struct inode *inode);
 
-/*
- * Multigrain timestamps
- *
- * Conditionally use fine-grained ctime and mtime timestamps when there
- * are users actively observing them via getattr. The primary use-case
- * for this is NFS clients that use the ctime to distinguish between
- * different states of the file, and that are often fooled by multiple
- * operations that occur in the same coarse-grained timer tick.
- *
- * The kernel always keeps normalized struct timespec64 values in the ctime,
- * which means that only the first 30 bits of the value are used. Use the
- * 31st bit of the ctime's tv_nsec field as a flag to indicate that the value
- * has been queried since it was last updated.
- */
-#define I_CTIME_QUERIED                (1L<<30)
-
 /**
  * inode_get_ctime - fetch the current ctime from the inode
  * @inode: inode from which to fetch ctime
  *
- * Grab the current ctime tv_nsec field from the inode, mask off the
- * I_CTIME_QUERIED flag and return it. This is mostly intended for use by
- * internal consumers of the ctime that aren't concerned with ensuring a
- * fine-grained update on the next change (e.g. when preparing to store
- * the value in the backing store for later retrieval).
- *
- * This is safe to call regardless of whether the underlying filesystem
- * is using multigrain timestamps.
+ * Grab the current ctime from the inode and return it.
  */
 static inline struct timespec64 inode_get_ctime(const struct inode *inode)
 {
-       struct timespec64 ctime;
-
-       ctime.tv_sec = inode->__i_ctime.tv_sec;
-       ctime.tv_nsec = inode->__i_ctime.tv_nsec & ~I_CTIME_QUERIED;
-
-       return ctime;
+       return inode->__i_ctime;
 }
 
 /**
@@ -2334,7 +2305,6 @@ struct file_system_type {
 #define FS_USERNS_MOUNT                8       /* Can be mounted by userns root */
 #define FS_DISALLOW_NOTIFY_PERM        16      /* Disable fanotify permission events */
 #define FS_ALLOW_IDMAP         32      /* FS has been updated to handle vfs idmappings. */
-#define FS_MGTIME              64      /* FS uses multigrain timestamps */
 #define FS_RENAME_DOES_D_MOVE  32768   /* FS will handle d_move() during rename() internally. */
        int (*init_fs_context)(struct fs_context *);
        const struct fs_parameter_spec *parameters;
@@ -2358,17 +2328,6 @@ struct file_system_type {
 
 #define MODULE_ALIAS_FS(NAME) MODULE_ALIAS("fs-" NAME)
 
-/**
- * is_mgtime: is this inode using multigrain timestamps
- * @inode: inode to test for multigrain timestamps
- *
- * Return true if the inode uses multigrain timestamps, false otherwise.
- */
-static inline bool is_mgtime(const struct inode *inode)
-{
-       return inode->i_sb->s_type->fs_flags & FS_MGTIME;
-}
-
 extern struct dentry *mount_bdev(struct file_system_type *fs_type,
        int flags, const char *dev_name, void *data,
        int (*fill_super)(struct super_block *, void *, int));
@@ -3054,7 +3013,6 @@ extern void page_put_link(void *);
 extern int page_symlink(struct inode *inode, const char *symname, int len);
 extern const struct inode_operations page_symlink_inode_operations;
 extern void kfree_link(void *);
-void fill_mg_cmtime(struct kstat *stat, u32 request_mask, struct inode *inode);
 void generic_fillattr(struct mnt_idmap *, u32, struct inode *, struct kstat *);
 void generic_fill_statx_attr(struct inode *inode, struct kstat *stat);
 extern int vfs_getattr_nosec(const struct path *, struct kstat *, u32, unsigned int);
index 5b26260..a30686e 100644 (file)
@@ -984,7 +984,9 @@ static inline void huge_ptep_modify_prot_commit(struct vm_area_struct *vma,
                                                unsigned long addr, pte_t *ptep,
                                                pte_t old_pte, pte_t pte)
 {
-       set_huge_pte_at(vma->vm_mm, addr, ptep, pte);
+       unsigned long psize = huge_page_size(hstate_vma(vma));
+
+       set_huge_pte_at(vma->vm_mm, addr, ptep, pte, psize);
 }
 #endif
 
@@ -1173,7 +1175,7 @@ static inline pte_t huge_ptep_clear_flush(struct vm_area_struct *vma,
 }
 
 static inline void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
-                                  pte_t *ptep, pte_t pte)
+                                  pte_t *ptep, pte_t pte, unsigned long sz)
 {
 }
 
index 1b9b15a..cdc684e 100644 (file)
@@ -189,6 +189,8 @@ struct team {
        struct net_device *dev; /* associated netdevice */
        struct team_pcpu_stats __percpu *pcpu_stats;
 
+       const struct header_ops *header_ops_cache;
+
        struct mutex lock; /* used for overall locking, e.g. port lists write */
 
        /*
index a92bce4..4a1dc88 100644 (file)
@@ -569,8 +569,12 @@ enum
  *     2) rcu_report_dead() reports the final quiescent states.
  *
  * _ IRQ_POLL: irq_poll_cpu_dead() migrates the queue
+ *
+ * _ (HR)TIMER_SOFTIRQ: (hr)timers_dead_cpu() migrates the queue
  */
-#define SOFTIRQ_HOTPLUG_SAFE_MASK (BIT(RCU_SOFTIRQ) | BIT(IRQ_POLL_SOFTIRQ))
+#define SOFTIRQ_HOTPLUG_SAFE_MASK (BIT(TIMER_SOFTIRQ) | BIT(IRQ_POLL_SOFTIRQ) |\
+                                  BIT(HRTIMER_SOFTIRQ) | BIT(RCU_SOFTIRQ))
+
 
 /* map softirq index to softirq name. update 'softirq_to_name' in
  * kernel/softirq.c when adding a new softirq.
index 3df5499..842623d 100644 (file)
@@ -54,7 +54,7 @@ extern p4d_t kasan_early_shadow_p4d[MAX_PTRS_PER_P4D];
 int kasan_populate_early_shadow(const void *shadow_start,
                                const void *shadow_end);
 
-#ifndef __HAVE_ARCH_SHADOW_MAP
+#ifndef kasan_mem_to_shadow
 static inline void *kasan_mem_to_shadow(const void *addr)
 {
        return (void *)((unsigned long)addr >> KASAN_SHADOW_SCALE_SHIFT)
index bf4913f..2a7d2af 100644 (file)
@@ -192,6 +192,7 @@ enum {
        ATA_PFLAG_UNLOADING     = (1 << 9), /* driver is being unloaded */
        ATA_PFLAG_UNLOADED      = (1 << 10), /* driver is unloaded */
 
+       ATA_PFLAG_RESUMING      = (1 << 16),  /* port is being resumed */
        ATA_PFLAG_SUSPENDED     = (1 << 17), /* port is suspended (power) */
        ATA_PFLAG_PM_PENDING    = (1 << 18), /* PM operation pending */
        ATA_PFLAG_INIT_GTM_VALID = (1 << 19), /* initial gtm data valid */
@@ -259,7 +260,7 @@ enum {
         * advised to wait only for the following duration before
         * doing SRST.
         */
-       ATA_TMOUT_PMP_SRST_WAIT = 5000,
+       ATA_TMOUT_PMP_SRST_WAIT = 10000,
 
        /* When the LPM policy is set to ATA_LPM_MAX_POWER, there might
         * be a spurious PHY event, so ignore the first PHY event that
@@ -318,9 +319,10 @@ enum {
        ATA_EH_ENABLE_LINK      = (1 << 3),
        ATA_EH_PARK             = (1 << 5), /* unload heads and stop I/O */
        ATA_EH_GET_SUCCESS_SENSE = (1 << 6), /* Get sense data for successful cmd */
+       ATA_EH_SET_ACTIVE       = (1 << 7), /* Set a device to active power mode */
 
        ATA_EH_PERDEV_MASK      = ATA_EH_REVALIDATE | ATA_EH_PARK |
-                                 ATA_EH_GET_SUCCESS_SENSE,
+                                 ATA_EH_GET_SUCCESS_SENSE | ATA_EH_SET_ACTIVE,
        ATA_EH_ALL_ACTIONS      = ATA_EH_REVALIDATE | ATA_EH_RESET |
                                  ATA_EH_ENABLE_LINK,
 
@@ -357,7 +359,7 @@ enum {
        /* This should match the actual table size of
         * ata_eh_cmd_timeout_table in libata-eh.c.
         */
-       ATA_EH_CMD_TIMEOUT_TABLE_SIZE = 7,
+       ATA_EH_CMD_TIMEOUT_TABLE_SIZE = 8,
 
        /* Horkage types. May be set by libata or controller on drives
           (some horkage may be drive/controller pair dependent */
@@ -1148,6 +1150,7 @@ extern int ata_std_bios_param(struct scsi_device *sdev,
                              struct block_device *bdev,
                              sector_t capacity, int geom[]);
 extern void ata_scsi_unlock_native_capacity(struct scsi_device *sdev);
+extern int ata_scsi_slave_alloc(struct scsi_device *sdev);
 extern int ata_scsi_slave_config(struct scsi_device *sdev);
 extern void ata_scsi_slave_destroy(struct scsi_device *sdev);
 extern int ata_scsi_change_queue_depth(struct scsi_device *sdev,
@@ -1396,6 +1399,7 @@ extern const struct attribute_group *ata_common_sdev_groups[];
        .this_id                = ATA_SHT_THIS_ID,              \
        .emulated               = ATA_SHT_EMULATED,             \
        .proc_name              = drv_name,                     \
+       .slave_alloc            = ata_scsi_slave_alloc,         \
        .slave_destroy          = ata_scsi_slave_destroy,       \
        .bios_param             = ata_std_bios_param,           \
        .unlock_native_capacity = ata_scsi_unlock_native_capacity,\
index e41c70a..d01e850 100644 (file)
@@ -428,6 +428,8 @@ struct ma_wr_state {
 #define MAS_ROOT       ((struct maple_enode *)5UL)
 #define MAS_NONE       ((struct maple_enode *)9UL)
 #define MAS_PAUSE      ((struct maple_enode *)17UL)
+#define MAS_OVERFLOW   ((struct maple_enode *)33UL)
+#define MAS_UNDERFLOW  ((struct maple_enode *)65UL)
 #define MA_ERROR(err) \
                ((struct maple_enode *)(((unsigned long)err << 2) | 2UL))
 
@@ -511,6 +513,15 @@ static inline bool mas_is_paused(const struct ma_state *mas)
        return mas->node == MAS_PAUSE;
 }
 
+/* Check if the mas is pointing to a node or not */
+static inline bool mas_is_active(struct ma_state *mas)
+{
+       if ((unsigned long)mas->node >= MAPLE_RESERVED_RANGE)
+               return true;
+
+       return false;
+}
+
 /**
  * mas_reset() - Reset a Maple Tree operation state.
  * @mas: Maple Tree operation state.
index ab94ad4..e4e24da 100644 (file)
@@ -920,7 +920,7 @@ unsigned long mem_cgroup_get_zone_lru_size(struct lruvec *lruvec,
        return READ_ONCE(mz->lru_zone_size[zone_idx][lru]);
 }
 
-void mem_cgroup_handle_over_high(void);
+void mem_cgroup_handle_over_high(gfp_t gfp_mask);
 
 unsigned long mem_cgroup_get_max(struct mem_cgroup *memcg);
 
@@ -1458,7 +1458,7 @@ static inline void mem_cgroup_unlock_pages(void)
        rcu_read_unlock();
 }
 
-static inline void mem_cgroup_handle_over_high(void)
+static inline void mem_cgroup_handle_over_high(gfp_t gfp_mask)
 {
 }
 
index 625f491..fb31312 100644 (file)
@@ -9,6 +9,7 @@ struct ip_ct_sctp {
        enum sctp_conntrack state;
 
        __be32 vtag[IP_CT_DIR_MAX];
+       u8 init[IP_CT_DIR_MAX];
        u8 last_dir;
        u8 flags;
 };
index 20eeba8..cd628c4 100644 (file)
@@ -48,6 +48,7 @@ struct nfs_client {
 #define NFS_CS_NOPING          6               /* - don't ping on connect */
 #define NFS_CS_DS              7               /* - Server is a DS */
 #define NFS_CS_REUSEPORT       8               /* - reuse src port on reconnect */
+#define NFS_CS_PNFS            9               /* - Server used for pnfs */
        struct sockaddr_storage cl_addr;        /* server identifier */
        size_t                  cl_addrlen;
        char *                  cl_hostname;    /* hostname of server */
index aa9f4c6..1c315f8 100644 (file)
@@ -157,7 +157,9 @@ extern      void nfs_unlock_request(struct nfs_page *req);
 extern void nfs_unlock_and_release_request(struct nfs_page *);
 extern struct nfs_page *nfs_page_group_lock_head(struct nfs_page *req);
 extern int nfs_page_group_lock_subrequests(struct nfs_page *head);
-extern void nfs_join_page_group(struct nfs_page *head, struct inode *inode);
+extern void nfs_join_page_group(struct nfs_page *head,
+                               struct nfs_commit_info *cinfo,
+                               struct inode *inode);
 extern int nfs_page_group_lock(struct nfs_page *);
 extern void nfs_page_group_unlock(struct nfs_page *);
 extern bool nfs_page_group_sync_on_bit(struct nfs_page *, unsigned int);
index 1fba072..af7639c 100644 (file)
@@ -206,6 +206,14 @@ static inline int pmd_young(pmd_t pmd)
 #endif
 
 #ifndef set_ptes
+
+#ifndef pte_next_pfn
+static inline pte_t pte_next_pfn(pte_t pte)
+{
+       return __pte(pte_val(pte) + (1UL << PFN_PTE_SHIFT));
+}
+#endif
+
 /**
  * set_ptes - Map consecutive pages to a contiguous range of addresses.
  * @mm: Address space to map the pages into.
@@ -231,7 +239,7 @@ static inline void set_ptes(struct mm_struct *mm, unsigned long addr,
                if (--nr == 0)
                        break;
                ptep++;
-               pte = __pte(pte_val(pte) + (1UL << PFN_PTE_SHIFT));
+               pte = pte_next_pfn(pte);
        }
        arch_leave_lazy_mmu_mode();
 }
index fd692b4..07071e6 100644 (file)
@@ -285,7 +285,9 @@ static inline void dqstats_dec(unsigned int type)
 #define DQ_FAKE_B      3       /* no limits only usage */
 #define DQ_READ_B      4       /* dquot was read into memory */
 #define DQ_ACTIVE_B    5       /* dquot is active (dquot_release not called) */
-#define DQ_LASTSET_B   6       /* Following 6 bits (see QIF_) are reserved\
+#define DQ_RELEASING_B 6       /* dquot is in releasing_dquots list waiting
+                                * to be cleaned up */
+#define DQ_LASTSET_B   7       /* Following 6 bits (see QIF_) are reserved\
                                 * for the mask of entries set via SETQUOTA\
                                 * quotactl. They are set under dq_data_lock\
                                 * and the quota format handling dquot can\
index 11a4bec..4fa4ef0 100644 (file)
@@ -57,7 +57,7 @@ static inline bool dquot_is_busy(struct dquot *dquot)
 {
        if (test_bit(DQ_MOD_B, &dquot->dq_flags))
                return true;
-       if (atomic_read(&dquot->dq_count) > 1)
+       if (atomic_read(&dquot->dq_count) > 0)
                return true;
        return false;
 }
index 2851894..f8f3e95 100644 (file)
@@ -55,7 +55,7 @@ static inline void resume_user_mode_work(struct pt_regs *regs)
        }
 #endif
 
-       mem_cgroup_handle_over_high();
+       mem_cgroup_handle_over_high(GFP_KERNEL);
        blkcg_maybe_throttle_current();
 
        rseq_handle_notify_resume(NULL, regs);
index 987a59d..e9bd2f6 100644 (file)
@@ -512,8 +512,8 @@ do {                                                                        \
 
 static inline void do_write_seqcount_begin_nested(seqcount_t *s, int subclass)
 {
-       do_raw_write_seqcount_begin(s);
        seqcount_acquire(&s->dep_map, subclass, 0, _RET_IP_);
+       do_raw_write_seqcount_begin(s);
 }
 
 /**
index 5b4fb3c..2f8dc47 100644 (file)
@@ -779,7 +779,9 @@ xdr_stream_decode_uint32_array(struct xdr_stream *xdr,
 
        if (unlikely(xdr_stream_decode_u32(xdr, &len) < 0))
                return -EBADMSG;
-       p = xdr_inline_decode(xdr, size_mul(len, sizeof(*p)));
+       if (U32_MAX >= SIZE_MAX / sizeof(*p) && len > SIZE_MAX / sizeof(*p))
+               return -EBADMSG;
+       p = xdr_inline_decode(xdr, len * sizeof(*p));
        if (unlikely(!p))
                return -EBADMSG;
        if (array == NULL)
index b453662..ecde031 100644 (file)
@@ -172,14 +172,23 @@ static inline bool is_swiotlb_buffer(struct device *dev, phys_addr_t paddr)
        if (!mem)
                return false;
 
-       if (IS_ENABLED(CONFIG_SWIOTLB_DYNAMIC)) {
-               /* Pairs with smp_wmb() in swiotlb_find_slots() and
-                * swiotlb_dyn_alloc(), which modify the RCU lists.
-                */
-               smp_rmb();
-               return swiotlb_find_pool(dev, paddr);
-       }
+#ifdef CONFIG_SWIOTLB_DYNAMIC
+       /*
+        * All SWIOTLB buffer addresses must have been returned by
+        * swiotlb_tbl_map_single() and passed to a device driver.
+        * If a SWIOTLB address is checked on another CPU, then it was
+        * presumably loaded by the device driver from an unspecified private
+        * data structure. Make sure that this load is ordered before reading
+        * dev->dma_uses_io_tlb here and mem->pools in swiotlb_find_pool().
+        *
+        * This barrier pairs with smp_mb() in swiotlb_find_slots().
+        */
+       smp_rmb();
+       return READ_ONCE(dev->dma_uses_io_tlb) &&
+               swiotlb_find_pool(dev, paddr);
+#else
        return paddr >= mem->defpool.start && paddr < mem->defpool.end;
+#endif
 }
 
 static inline bool is_swiotlb_force_bounce(struct device *dev)
index e6359f7..c33348b 100644 (file)
@@ -350,7 +350,7 @@ struct hci_dev {
        struct list_head list;
        struct mutex    lock;
 
-       char            name[8];
+       const char      *name;
        unsigned long   flags;
        __u16           id;
        __u8            bus;
index 3a4b684..7192346 100644 (file)
@@ -5941,6 +5941,7 @@ void wiphy_delayed_work_cancel(struct wiphy *wiphy,
  * @event_lock: (private) lock for event list
  * @owner_nlportid: (private) owner socket port ID
  * @nl_owner_dead: (private) owner socket went away
+ * @cqm_rssi_work: (private) CQM RSSI reporting work
  * @cqm_config: (private) nl80211 RSSI monitor state
  * @pmsr_list: (private) peer measurement requests
  * @pmsr_lock: (private) peer measurements requests/results lock
@@ -6013,7 +6014,8 @@ struct wireless_dev {
        } wext;
 #endif
 
-       struct cfg80211_cqm_config *cqm_config;
+       struct wiphy_work cqm_rssi_work;
+       struct cfg80211_cqm_config __rcu *cqm_config;
 
        struct list_head pmsr_list;
        spinlock_t pmsr_lock;
@@ -7231,7 +7233,7 @@ struct cfg80211_rx_assoc_resp {
        int uapsd_queues;
        const u8 *ap_mld_addr;
        struct {
-               const u8 *addr;
+               u8 addr[ETH_ALEN] __aligned(2);
                struct cfg80211_bss *bss;
                u16 status;
        } links[IEEE80211_MLD_MAX_NUM_LINKS];
index f0c1386..15de07d 100644 (file)
@@ -154,6 +154,7 @@ struct fib_info {
        int                     fib_nhs;
        bool                    fib_nh_is_v6;
        bool                    nh_updated;
+       bool                    pfsrc_removed;
        struct nexthop          *nh;
        struct rcu_head         rcu;
        struct fib_nh           fib_nh[];
index 9f70b43..4d43adf 100644 (file)
@@ -103,9 +103,10 @@ struct mana_txq {
 
 /* skb data and frags dma mappings */
 struct mana_skb_head {
-       dma_addr_t dma_handle[MAX_SKB_FRAGS + 1];
+       /* GSO pkts may have 2 SGEs for the linear part*/
+       dma_addr_t dma_handle[MAX_SKB_FRAGS + 2];
 
-       u32 size[MAX_SKB_FRAGS + 1];
+       u32 size[MAX_SKB_FRAGS + 2];
 };
 
 #define MANA_HEADROOM sizeof(struct mana_skb_head)
index 6da6888..07022bb 100644 (file)
@@ -539,7 +539,7 @@ static inline int neigh_output(struct neighbour *n, struct sk_buff *skb,
            READ_ONCE(hh->hh_len))
                return neigh_hh_output(hh, skb);
 
-       return n->output(n, skb);
+       return READ_ONCE(n->output)(n, skb);
 }
 
 static inline struct neighbour *
index dd40c75..7c81635 100644 (file)
@@ -1682,7 +1682,7 @@ struct nft_trans_gc {
        struct net              *net;
        struct nft_set          *set;
        u32                     seq;
-       u                     count;
+       u16                     count;
        void                    *priv[NFT_TRANS_GC_BATCHCOUNT];
        struct rcu_head         rcu;
 };
@@ -1700,8 +1700,9 @@ void nft_trans_gc_queue_sync_done(struct nft_trans_gc *trans);
 
 void nft_trans_gc_elem_add(struct nft_trans_gc *gc, void *priv);
 
-struct nft_trans_gc *nft_trans_gc_catchall(struct nft_trans_gc *gc,
-                                          unsigned int gc_seq);
+struct nft_trans_gc *nft_trans_gc_catchall_async(struct nft_trans_gc *gc,
+                                                unsigned int gc_seq);
+struct nft_trans_gc *nft_trans_gc_catchall_sync(struct nft_trans_gc *gc);
 
 void nft_setelem_data_deactivate(const struct net *net,
                                 const struct nft_set *set,
index 9423153..8e77514 100644 (file)
  * page_pool_alloc_pages() call.  Drivers should use
  * page_pool_dev_alloc_pages() replacing dev_alloc_pages().
  *
- * API keeps track of in-flight pages, in order to let API user know
+ * The API keeps track of in-flight pages, in order to let API users know
  * when it is safe to free a page_pool object.  Thus, API users
  * must call page_pool_put_page() to free the page, or attach
- * the page to a page_pool-aware objects like skbs marked with
+ * the page to a page_pool-aware object like skbs marked with
  * skb_mark_for_recycle().
  *
- * API user must call page_pool_put_page() once on a page, as it
+ * API users must call page_pool_put_page() once on a page, as it
  * will either recycle the page, or in case of refcnt > 1, it will
  * release the DMA mapping and in-flight state accounting.
  */
index 91688d0..7b1a720 100644 (file)
@@ -348,12 +348,14 @@ ssize_t tcp_splice_read(struct socket *sk, loff_t *ppos,
 struct sk_buff *tcp_stream_alloc_skb(struct sock *sk, gfp_t gfp,
                                     bool force_schedule);
 
-static inline void tcp_dec_quickack_mode(struct sock *sk,
-                                        const unsigned int pkts)
+static inline void tcp_dec_quickack_mode(struct sock *sk)
 {
        struct inet_connection_sock *icsk = inet_csk(sk);
 
        if (icsk->icsk_ack.quick) {
+               /* How many ACKs S/ACKing new data have we sent? */
+               const unsigned int pkts = inet_csk_ack_scheduled(sk) ? 1 : 0;
+
                if (pkts >= icsk->icsk_ack.quick) {
                        icsk->icsk_ack.quick = 0;
                        /* Leaving quickack mode we deflate ATO. */
index ec09359..4498f84 100644 (file)
@@ -157,6 +157,9 @@ enum scsi_disposition {
 #define SCSI_3          4        /* SPC */
 #define SCSI_SPC_2      5
 #define SCSI_SPC_3      6
+#define SCSI_SPC_4     7
+#define SCSI_SPC_5     8
+#define SCSI_SPC_6     14
 
 /*
  * INQ PERIPHERAL QUALIFIERS
index b9230b6..fd41fda 100644 (file)
@@ -161,6 +161,10 @@ struct scsi_device {
                                 * pass settings from slave_alloc to scsi
                                 * core. */
        unsigned int eh_timeout; /* Error handling timeout */
+
+       bool manage_system_start_stop; /* Let HLD (sd) manage system start/stop */
+       bool manage_runtime_start_stop; /* Let HLD (sd) manage runtime start/stop */
+
        unsigned removable:1;
        unsigned changed:1;     /* Data invalid due to media change */
        unsigned busy:1;        /* Used to prevent races */
@@ -193,7 +197,6 @@ struct scsi_device {
        unsigned use_192_bytes_for_3f:1; /* ask for 192 bytes from page 0x3f */
        unsigned no_start_on_add:1;     /* do not issue start on add */
        unsigned allow_restart:1; /* issue START_UNIT in error handler */
-       unsigned manage_start_stop:1;   /* Let HLD (sd) manage start/stop */
        unsigned no_start_on_resume:1; /* Do not issue START_STOP_UNIT on resume */
        unsigned start_stop_pwr_cond:1; /* Set power cond. in START_STOP_UNIT */
        unsigned no_uld_attach:1; /* disable connecting to upper level drivers */
index 49f768d..4c2dc81 100644 (file)
@@ -764,7 +764,7 @@ scsi_template_proc_dir(const struct scsi_host_template *sht);
 #define scsi_template_proc_dir(sht) NULL
 #endif
 extern void scsi_scan_host(struct Scsi_Host *);
-extern void scsi_rescan_device(struct scsi_device *);
+extern int scsi_rescan_device(struct scsi_device *sdev);
 extern void scsi_remove_host(struct Scsi_Host *);
 extern struct Scsi_Host *scsi_host_get(struct Scsi_Host *);
 extern int scsi_host_busy(struct Scsi_Host *shost);
index fa2337a..37f9d3f 100644 (file)
@@ -1126,6 +1126,8 @@ struct snd_soc_pcm_runtime {
        unsigned int pop_wait:1;
        unsigned int fe_compr:1; /* for Dynamic PCM */
 
+       bool initialized;
+
        int num_components;
        struct snd_soc_component *components[]; /* CPU/Codec/Platform */
 };
index 44a3f56..0577f0c 100644 (file)
@@ -6,26 +6,26 @@
 #define _TRACE_XEN_H
 
 #include <linux/tracepoint.h>
-#include <asm/paravirt_types.h>
+#include <asm/xen/hypervisor.h>
 #include <asm/xen/trace_types.h>
 
 struct multicall_entry;
 
 /* Multicalls */
 DECLARE_EVENT_CLASS(xen_mc__batch,
-           TP_PROTO(enum paravirt_lazy_mode mode),
+           TP_PROTO(enum xen_lazy_mode mode),
            TP_ARGS(mode),
            TP_STRUCT__entry(
-                   __field(enum paravirt_lazy_mode, mode)
+                   __field(enum xen_lazy_mode, mode)
                    ),
            TP_fast_assign(__entry->mode = mode),
            TP_printk("start batch LAZY_%s",
-                     (__entry->mode == PARAVIRT_LAZY_MMU) ? "MMU" :
-                     (__entry->mode == PARAVIRT_LAZY_CPU) ? "CPU" : "NONE")
+                     (__entry->mode == XEN_LAZY_MMU) ? "MMU" :
+                     (__entry->mode == XEN_LAZY_CPU) ? "CPU" : "NONE")
        );
 #define DEFINE_XEN_MC_BATCH(name)                      \
        DEFINE_EVENT(xen_mc__batch, name,               \
-               TP_PROTO(enum paravirt_lazy_mode mode), \
+               TP_PROTO(enum xen_lazy_mode mode),      \
                     TP_ARGS(mode))
 
 DEFINE_XEN_MC_BATCH(xen_mc_batch);
index 8d7402c..eaf9f24 100644 (file)
@@ -44,6 +44,16 @@ extern "C" {
 #define NOUVEAU_GETPARAM_PTIMER_TIME     14
 #define NOUVEAU_GETPARAM_HAS_BO_USAGE    15
 #define NOUVEAU_GETPARAM_HAS_PAGEFLIP    16
+
+/**
+ * @NOUVEAU_GETPARAM_EXEC_PUSH_MAX
+ *
+ * Query the maximum amount of IBs that can be pushed through a single
+ * &drm_nouveau_exec structure and hence a single &DRM_IOCTL_NOUVEAU_EXEC
+ * ioctl().
+ */
+#define NOUVEAU_GETPARAM_EXEC_PUSH_MAX   17
+
 struct drm_nouveau_getparam {
        __u64 param;
        __u64 value;
index 8790b39..0448700 100644 (file)
@@ -1962,7 +1962,9 @@ union bpf_attr {
  *             performed again, if the helper is used in combination with
  *             direct packet access.
  *     Return
- *             0 on success, or a negative error in case of failure.
+ *             0 on success, or a negative error in case of failure. Positive
+ *             error indicates a potential drop or congestion in the target
+ *             device. The particular positive error codes are not defined.
  *
  * u64 bpf_get_current_pid_tgid(void)
  *     Description
index 7c3fc39..5c6c426 100644 (file)
                struct TAG { MEMBERS } ATTRS NAME; \
        }
 
+#ifdef __cplusplus
+/* sizeof(struct{}) is 1 in C++, not 0, can't use C version of the macro. */
+#define __DECLARE_FLEX_ARRAY(T, member)        \
+       T member[0]
+#else
 /**
  * __DECLARE_FLEX_ARRAY() - Declare a flexible array usable in a union
  *
@@ -49,3 +54,5 @@
 #ifndef __counted_by
 #define __counted_by(m)
 #endif
+
+#endif /* _UAPI_LINUX_STDDEF_H */
index 43ef24d..9995695 100644 (file)
@@ -7,18 +7,6 @@
 extern struct shared_info *HYPERVISOR_shared_info;
 extern struct start_info *xen_start_info;
 
-/* Lazy mode for batching updates / context switch */
-enum paravirt_lazy_mode {
-       PARAVIRT_LAZY_NONE,
-       PARAVIRT_LAZY_MMU,
-       PARAVIRT_LAZY_CPU,
-};
-
-static inline enum paravirt_lazy_mode paravirt_get_lazy_mode(void)
-{
-       return PARAVIRT_LAZY_NONE;
-}
-
 #ifdef CONFIG_XEN
 void __init xen_early_init(void);
 #else
index 95d5e28..23932b0 100644 (file)
@@ -105,8 +105,7 @@ int irq_from_virq(unsigned int cpu, unsigned int virq);
 evtchn_port_t evtchn_from_irq(unsigned irq);
 
 int xen_set_callback_via(uint64_t via);
-void xen_evtchn_do_upcall(struct pt_regs *regs);
-int xen_hvm_evtchn_do_upcall(void);
+int xen_evtchn_do_upcall(void);
 
 /* Bind a pirq for a physical interrupt to an irq. */
 int xen_bind_pirq_gsi_to_irq(unsigned gsi,
index f6a69a5..08e3b17 100644 (file)
@@ -243,7 +243,7 @@ int io_linkat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
        struct io_link *lnk = io_kiocb_to_cmd(req, struct io_link);
        const char __user *oldf, *newf;
 
-       if (sqe->rw_flags || sqe->buf_index || sqe->splice_fd_in)
+       if (sqe->buf_index || sqe->splice_fd_in)
                return -EINVAL;
        if (unlikely(req->flags & REQ_F_FIXED_FILE))
                return -EBADF;
index 1ecc8c7..522196d 100644 (file)
@@ -1151,9 +1151,6 @@ struct io_wq *io_wq_create(unsigned bounded, struct io_wq_data *data)
        wq = kzalloc(sizeof(struct io_wq), GFP_KERNEL);
        if (!wq)
                return ERR_PTR(-ENOMEM);
-       ret = cpuhp_state_add_instance_nocalls(io_wq_online, &wq->cpuhp_node);
-       if (ret)
-               goto err_wq;
 
        refcount_inc(&data->hash->refs);
        wq->hash = data->hash;
@@ -1186,13 +1183,14 @@ struct io_wq *io_wq_create(unsigned bounded, struct io_wq_data *data)
        wq->task = get_task_struct(data->task);
        atomic_set(&wq->worker_refs, 1);
        init_completion(&wq->worker_done);
+       ret = cpuhp_state_add_instance_nocalls(io_wq_online, &wq->cpuhp_node);
+       if (ret)
+               goto err;
+
        return wq;
 err:
        io_wq_put_hash(data->hash);
-       cpuhp_state_remove_instance_nocalls(io_wq_online, &wq->cpuhp_node);
-
        free_cpumask_var(wq->cpu_mask);
-err_wq:
        kfree(wq);
        return ERR_PTR(ret);
 }
index 783ed0f..d839a80 100644 (file)
@@ -2686,7 +2686,7 @@ static void *__io_uaddr_map(struct page ***pages, unsigned short *npages,
 {
        struct page **page_array;
        unsigned int nr_pages;
-       int ret;
+       int ret, i;
 
        *npages = 0;
 
@@ -2716,6 +2716,20 @@ err:
         */
        if (page_array[0] != page_array[ret - 1])
                goto err;
+
+       /*
+        * Can't support mapping user allocated ring memory on 32-bit archs
+        * where it could potentially reside in highmem. Just fail those with
+        * -EINVAL, just like we did on kernels that didn't support this
+        * feature.
+        */
+       for (i = 0; i < nr_pages; i++) {
+               if (PageHighMem(page_array[i])) {
+                       ret = -EINVAL;
+                       goto err;
+               }
+       }
+
        *pages = page_array;
        *npages = nr_pages;
        return page_to_virt(page_array[0]);
index 547c305..0bc1456 100644 (file)
@@ -86,20 +86,33 @@ bool __io_alloc_req_refill(struct io_ring_ctx *ctx);
 bool io_match_task_safe(struct io_kiocb *head, struct task_struct *task,
                        bool cancel_all);
 
-#define io_lockdep_assert_cq_locked(ctx)                               \
-       do {                                                            \
-               lockdep_assert(in_task());                              \
-                                                                       \
-               if (ctx->flags & IORING_SETUP_IOPOLL) {                 \
-                       lockdep_assert_held(&ctx->uring_lock);          \
-               } else if (!ctx->task_complete) {                       \
-                       lockdep_assert_held(&ctx->completion_lock);     \
-               } else if (ctx->submitter_task->flags & PF_EXITING) {   \
-                       lockdep_assert(current_work());                 \
-               } else {                                                \
-                       lockdep_assert(current == ctx->submitter_task); \
-               }                                                       \
-       } while (0)
+#if defined(CONFIG_PROVE_LOCKING)
+static inline void io_lockdep_assert_cq_locked(struct io_ring_ctx *ctx)
+{
+       lockdep_assert(in_task());
+
+       if (ctx->flags & IORING_SETUP_IOPOLL) {
+               lockdep_assert_held(&ctx->uring_lock);
+       } else if (!ctx->task_complete) {
+               lockdep_assert_held(&ctx->completion_lock);
+       } else if (ctx->submitter_task) {
+               /*
+                * ->submitter_task may be NULL and we can still post a CQE,
+                * if the ring has been setup with IORING_SETUP_R_DISABLED.
+                * Not from an SQE, as those cannot be submitted, but via
+                * updating tagged resources.
+                */
+               if (ctx->submitter_task->flags & PF_EXITING)
+                       lockdep_assert(current_work());
+               else
+                       lockdep_assert(current == ctx->submitter_task);
+       }
+}
+#else
+static inline void io_lockdep_assert_cq_locked(struct io_ring_ctx *ctx)
+{
+}
+#endif
 
 static inline void io_req_task_work_add(struct io_kiocb *req)
 {
index 556f4df..9123138 100644 (file)
@@ -477,7 +477,7 @@ static int io_pin_pbuf_ring(struct io_uring_buf_reg *reg,
 {
        struct io_uring_buf_ring *br;
        struct page **pages;
-       int nr_pages;
+       int i, nr_pages;
 
        pages = io_pin_pages(reg->ring_addr,
                             flex_array_size(br, bufs, reg->ring_entries),
@@ -485,6 +485,17 @@ static int io_pin_pbuf_ring(struct io_uring_buf_reg *reg,
        if (IS_ERR(pages))
                return PTR_ERR(pages);
 
+       /*
+        * Apparently some 32-bit boxes (ARM) will return highmem pages,
+        * which then need to be mapped. We could support that, but it'd
+        * complicate the code and slowdown the common cases quite a bit.
+        * So just error out, returning -EINVAL just like we did on kernels
+        * that didn't support mapped buffer rings.
+        */
+       for (i = 0; i < nr_pages; i++)
+               if (PageHighMem(pages[i]))
+                       goto error_unpin;
+
        br = page_address(pages[0]);
 #ifdef SHM_COLOUR
        /*
@@ -496,13 +507,8 @@ static int io_pin_pbuf_ring(struct io_uring_buf_reg *reg,
         * should use IOU_PBUF_RING_MMAP instead, and liburing will handle
         * this transparently.
         */
-       if ((reg->ring_addr | (unsigned long) br) & (SHM_COLOUR - 1)) {
-               int i;
-
-               for (i = 0; i < nr_pages; i++)
-                       unpin_user_page(pages[i]);
-               return -EINVAL;
-       }
+       if ((reg->ring_addr | (unsigned long) br) & (SHM_COLOUR - 1))
+               goto error_unpin;
 #endif
        bl->buf_pages = pages;
        bl->buf_nr_pages = nr_pages;
@@ -510,6 +516,11 @@ static int io_pin_pbuf_ring(struct io_uring_buf_reg *reg,
        bl->is_mapped = 1;
        bl->is_mmap = 0;
        return 0;
+error_unpin:
+       for (i = 0; i < nr_pages; i++)
+               unpin_user_page(pages[i]);
+       kvfree(pages);
+       return -EINVAL;
 }
 
 static int io_alloc_pbuf_ring(struct io_uring_buf_reg *reg,
index 1095bbe..8090d7f 100644 (file)
@@ -8501,7 +8501,7 @@ bool btf_nested_type_is_trusted(struct bpf_verifier_log *log,
        tname = btf_name_by_offset(btf, walk_type->name_off);
 
        ret = snprintf(safe_tname, sizeof(safe_tname), "%s%s", tname, suffix);
-       if (ret < 0)
+       if (ret >= sizeof(safe_tname))
                return false;
 
        safe_id = btf_find_by_name_kind(btf, safe_tname, BTF_INFO_KIND(walk_type->info));
index 5b2741a..03b3d44 100644 (file)
@@ -785,7 +785,8 @@ found:
  *                          to descendants
  * @cgrp: The cgroup which descendants to traverse
  * @link: A link for which to replace BPF program
- * @type: Type of attach operation
+ * @new_prog: &struct bpf_prog for the target BPF program with its refcnt
+ *            incremented
  *
  * Must be called with cgroup_mutex held.
  */
@@ -1334,7 +1335,7 @@ int cgroup_bpf_prog_query(const union bpf_attr *attr,
  * __cgroup_bpf_run_filter_skb() - Run a program for packet filtering
  * @sk: The socket sending or receiving traffic
  * @skb: The skb that is being sent or received
- * @type: The type of program to be executed
+ * @atype: The type of program to be executed
  *
  * If no socket is passed, or the socket is not of type INET or INET6,
  * this function does nothing and returns 0.
@@ -1424,7 +1425,7 @@ EXPORT_SYMBOL(__cgroup_bpf_run_filter_skb);
 /**
  * __cgroup_bpf_run_filter_sk() - Run a program on a sock
  * @sk: sock structure to manipulate
- * @type: The type of program to be executed
+ * @atype: The type of program to be executed
  *
  * socket is passed is expected to be of type INET or INET6.
  *
@@ -1449,7 +1450,7 @@ EXPORT_SYMBOL(__cgroup_bpf_run_filter_sk);
  *                                       provided by user sockaddr
  * @sk: sock struct that will use sockaddr
  * @uaddr: sockaddr struct provided by user
- * @type: The type of program to be executed
+ * @atype: The type of program to be executed
  * @t_ctx: Pointer to attach type specific context
  * @flags: Pointer to u32 which contains higher bits of BPF program
  *         return value (OR'ed together).
@@ -1496,7 +1497,7 @@ EXPORT_SYMBOL(__cgroup_bpf_run_filter_sock_addr);
  * @sock_ops: bpf_sock_ops_kern struct to pass to program. Contains
  * sk with connection information (IP addresses, etc.) May not contain
  * cgroup info if it is a req sock.
- * @type: The type of program to be executed
+ * @atype: The type of program to be executed
  *
  * socket passed is expected to be of type INET or INET6.
  *
@@ -1670,7 +1671,7 @@ const struct bpf_verifier_ops cg_dev_verifier_ops = {
  * @ppos: value-result argument: value is position at which read from or write
  *     to sysctl is happening, result is new position if program overrode it,
  *     initial value otherwise
- * @type: type of program to be executed
+ * @atype: type of program to be executed
  *
  * Program is run when sysctl is being accessed, either read or written, and
  * can allow or deny such access.
index 9c49ae5..d93ddac 100644 (file)
@@ -459,8 +459,7 @@ static void notrace irq_work_raise(struct bpf_mem_cache *c)
  * Typical case will be between 11K and 116K closer to 11K.
  * bpf progs can and should share bpf_mem_cache when possible.
  */
-
-static void prefill_mem_cache(struct bpf_mem_cache *c, int cpu)
+static void init_refill_work(struct bpf_mem_cache *c)
 {
        init_irq_work(&c->refill_work, bpf_mem_refill);
        if (c->unit_size <= 256) {
@@ -476,7 +475,10 @@ static void prefill_mem_cache(struct bpf_mem_cache *c, int cpu)
                c->high_watermark = max(96 * 256 / c->unit_size, 3);
        }
        c->batch = max((c->high_watermark - c->low_watermark) / 4 * 3, 1);
+}
 
+static void prefill_mem_cache(struct bpf_mem_cache *c, int cpu)
+{
        /* To avoid consuming memory assume that 1st run of bpf
         * prog won't be doing more than 4 map_update_elem from
         * irq disabled region
@@ -484,6 +486,31 @@ static void prefill_mem_cache(struct bpf_mem_cache *c, int cpu)
        alloc_bulk(c, c->unit_size <= 256 ? 4 : 1, cpu_to_node(cpu), false);
 }
 
+static int check_obj_size(struct bpf_mem_cache *c, unsigned int idx)
+{
+       struct llist_node *first;
+       unsigned int obj_size;
+
+       /* For per-cpu allocator, the size of free objects in free list doesn't
+        * match with unit_size and now there is no way to get the size of
+        * per-cpu pointer saved in free object, so just skip the checking.
+        */
+       if (c->percpu_size)
+               return 0;
+
+       first = c->free_llist.first;
+       if (!first)
+               return 0;
+
+       obj_size = ksize(first);
+       if (obj_size != c->unit_size) {
+               WARN_ONCE(1, "bpf_mem_cache[%u]: unexpected object size %u, expect %u\n",
+                         idx, obj_size, c->unit_size);
+               return -EINVAL;
+       }
+       return 0;
+}
+
 /* When size != 0 bpf_mem_cache for each cpu.
  * This is typical bpf hash map use case when all elements have equal size.
  *
@@ -494,10 +521,10 @@ static void prefill_mem_cache(struct bpf_mem_cache *c, int cpu)
 int bpf_mem_alloc_init(struct bpf_mem_alloc *ma, int size, bool percpu)
 {
        static u16 sizes[NUM_CACHES] = {96, 192, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096};
+       int cpu, i, err, unit_size, percpu_size = 0;
        struct bpf_mem_caches *cc, __percpu *pcc;
        struct bpf_mem_cache *c, __percpu *pc;
        struct obj_cgroup *objcg = NULL;
-       int cpu, i, unit_size, percpu_size = 0;
 
        if (size) {
                pc = __alloc_percpu_gfp(sizeof(*pc), 8, GFP_KERNEL);
@@ -521,6 +548,7 @@ int bpf_mem_alloc_init(struct bpf_mem_alloc *ma, int size, bool percpu)
                        c->objcg = objcg;
                        c->percpu_size = percpu_size;
                        c->tgt = c;
+                       init_refill_work(c);
                        prefill_mem_cache(c, cpu);
                }
                ma->cache = pc;
@@ -534,6 +562,7 @@ int bpf_mem_alloc_init(struct bpf_mem_alloc *ma, int size, bool percpu)
        pcc = __alloc_percpu_gfp(sizeof(*cc), 8, GFP_KERNEL);
        if (!pcc)
                return -ENOMEM;
+       err = 0;
 #ifdef CONFIG_MEMCG_KMEM
        objcg = get_obj_cgroup_from_current();
 #endif
@@ -544,11 +573,30 @@ int bpf_mem_alloc_init(struct bpf_mem_alloc *ma, int size, bool percpu)
                        c->unit_size = sizes[i];
                        c->objcg = objcg;
                        c->tgt = c;
+
+                       init_refill_work(c);
+                       /* Another bpf_mem_cache will be used when allocating
+                        * c->unit_size in bpf_mem_alloc(), so doesn't prefill
+                        * for the bpf_mem_cache because these free objects will
+                        * never be used.
+                        */
+                       if (i != bpf_mem_cache_idx(c->unit_size))
+                               continue;
                        prefill_mem_cache(c, cpu);
+                       err = check_obj_size(c, i);
+                       if (err)
+                               goto out;
                }
        }
+
+out:
        ma->caches = pcc;
-       return 0;
+       /* refill_work is either zeroed or initialized, so it is safe to
+        * call irq_work_sync().
+        */
+       if (err)
+               bpf_mem_alloc_destroy(ma);
+       return err;
 }
 
 static void drain_mem_cache(struct bpf_mem_cache *c)
@@ -916,3 +964,35 @@ void notrace *bpf_mem_cache_alloc_flags(struct bpf_mem_alloc *ma, gfp_t flags)
 
        return !ret ? NULL : ret + LLIST_NODE_SZ;
 }
+
+static __init int bpf_mem_cache_adjust_size(void)
+{
+       unsigned int size;
+
+       /* Adjusting the indexes in size_index() according to the object_size
+        * of underlying slab cache, so bpf_mem_alloc() will select a
+        * bpf_mem_cache with unit_size equal to the object_size of
+        * the underlying slab cache.
+        *
+        * The maximal value of KMALLOC_MIN_SIZE and __kmalloc_minalign() is
+        * 256-bytes, so only do adjustment for [8-bytes, 192-bytes].
+        */
+       for (size = 192; size >= 8; size -= 8) {
+               unsigned int kmalloc_size, index;
+
+               kmalloc_size = kmalloc_size_roundup(size);
+               if (kmalloc_size == size)
+                       continue;
+
+               if (kmalloc_size <= 192)
+                       index = size_index[(kmalloc_size - 1) / 8];
+               else
+                       index = fls(kmalloc_size - 1) - 1;
+               /* Only overwrite if necessary */
+               if (size_index[(size - 1) / 8] != index)
+                       size_index[(size - 1) / 8] = index;
+       }
+
+       return 0;
+}
+subsys_initcall(bpf_mem_cache_adjust_size);
index 32d2c48..007d98c 100644 (file)
@@ -253,6 +253,9 @@ int bpf_mprog_attach(struct bpf_mprog_entry *entry,
                        goto out;
                }
                idx = tidx;
+       } else if (bpf_mprog_total(entry) == bpf_mprog_max()) {
+               ret = -ERANGE;
+               goto out;
        }
        if (flags & BPF_F_BEFORE) {
                tidx = bpf_mprog_pos_before(entry, &rtuple);
index 3e4f2ec..87d6693 100644 (file)
@@ -199,12 +199,14 @@ static int __bpf_prog_dev_bound_init(struct bpf_prog *prog, struct net_device *n
        offload->netdev = netdev;
 
        ondev = bpf_offload_find_netdev(offload->netdev);
+       /* When program is offloaded require presence of "true"
+        * bpf_offload_netdev, avoid the one created for !ondev case below.
+        */
+       if (bpf_prog_is_offloaded(prog->aux) && (!ondev || !ondev->offdev)) {
+               err = -EINVAL;
+               goto err_free;
+       }
        if (!ondev) {
-               if (bpf_prog_is_offloaded(prog->aux)) {
-                       err = -EINVAL;
-                       goto err_free;
-               }
-
                /* When only binding to the device, explicitly
                 * create an entry in the hashtable.
                 */
index 8d2ddcb..d869f51 100644 (file)
@@ -98,7 +98,12 @@ static long __queue_map_get(struct bpf_map *map, void *value, bool delete)
        int err = 0;
        void *ptr;
 
-       raw_spin_lock_irqsave(&qs->lock, flags);
+       if (in_nmi()) {
+               if (!raw_spin_trylock_irqsave(&qs->lock, flags))
+                       return -EBUSY;
+       } else {
+               raw_spin_lock_irqsave(&qs->lock, flags);
+       }
 
        if (queue_stack_map_is_empty(qs)) {
                memset(value, 0, qs->map.value_size);
@@ -128,7 +133,12 @@ static long __stack_map_get(struct bpf_map *map, void *value, bool delete)
        void *ptr;
        u32 index;
 
-       raw_spin_lock_irqsave(&qs->lock, flags);
+       if (in_nmi()) {
+               if (!raw_spin_trylock_irqsave(&qs->lock, flags))
+                       return -EBUSY;
+       } else {
+               raw_spin_lock_irqsave(&qs->lock, flags);
+       }
 
        if (queue_stack_map_is_empty(qs)) {
                memset(value, 0, qs->map.value_size);
@@ -193,7 +203,12 @@ static long queue_stack_map_push_elem(struct bpf_map *map, void *value,
        if (flags & BPF_NOEXIST || flags > BPF_EXIST)
                return -EINVAL;
 
-       raw_spin_lock_irqsave(&qs->lock, irq_flags);
+       if (in_nmi()) {
+               if (!raw_spin_trylock_irqsave(&qs->lock, irq_flags))
+                       return -EBUSY;
+       } else {
+               raw_spin_lock_irqsave(&qs->lock, irq_flags);
+       }
 
        if (queue_stack_map_is_full(qs)) {
                if (!replace) {
index bb78212..c0c7d13 100644 (file)
@@ -4047,11 +4047,9 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int regno)
                                bitmap_from_u64(mask, bt_reg_mask(bt));
                                for_each_set_bit(i, mask, 32) {
                                        reg = &st->frame[0]->regs[i];
-                                       if (reg->type != SCALAR_VALUE) {
-                                               bt_clear_reg(bt, i);
-                                               continue;
-                                       }
-                                       reg->precise = true;
+                                       bt_clear_reg(bt, i);
+                                       if (reg->type == SCALAR_VALUE)
+                                               reg->precise = true;
                                }
                                return 0;
                        }
index 03a7932..2f675ef 100644 (file)
@@ -740,6 +740,17 @@ subsys_initcall(crash_notes_memory_init);
 #define pr_fmt(fmt) "crash hp: " fmt
 
 /*
+ * Different than kexec/kdump loading/unloading/jumping/shrinking which
+ * usually rarely happen, there will be many crash hotplug events notified
+ * during one short period, e.g one memory board is hot added and memory
+ * regions are online. So mutex lock  __crash_hotplug_lock is used to
+ * serialize the crash hotplug handling specifically.
+ */
+DEFINE_MUTEX(__crash_hotplug_lock);
+#define crash_hotplug_lock() mutex_lock(&__crash_hotplug_lock)
+#define crash_hotplug_unlock() mutex_unlock(&__crash_hotplug_lock)
+
+/*
  * This routine utilized when the crash_hotplug sysfs node is read.
  * It reflects the kernel's ability/permission to update the crash
  * elfcorehdr directly.
@@ -748,9 +759,11 @@ int crash_check_update_elfcorehdr(void)
 {
        int rc = 0;
 
+       crash_hotplug_lock();
        /* Obtain lock while reading crash information */
        if (!kexec_trylock()) {
                pr_info("kexec_trylock() failed, elfcorehdr may be inaccurate\n");
+               crash_hotplug_unlock();
                return 0;
        }
        if (kexec_crash_image) {
@@ -761,6 +774,7 @@ int crash_check_update_elfcorehdr(void)
        }
        /* Release lock now that update complete */
        kexec_unlock();
+       crash_hotplug_unlock();
 
        return rc;
 }
@@ -783,9 +797,11 @@ static void crash_handle_hotplug_event(unsigned int hp_action, unsigned int cpu)
 {
        struct kimage *image;
 
+       crash_hotplug_lock();
        /* Obtain lock while changing crash information */
        if (!kexec_trylock()) {
                pr_info("kexec_trylock() failed, elfcorehdr may be inaccurate\n");
+               crash_hotplug_unlock();
                return;
        }
 
@@ -852,6 +868,7 @@ static void crash_handle_hotplug_event(unsigned int hp_action, unsigned int cpu)
 out:
        /* Release lock now that update complete */
        kexec_unlock();
+       crash_hotplug_unlock();
 }
 
 static int crash_memhp_notifier(struct notifier_block *nb, unsigned long val, void *v)
index 394494a..0163767 100644 (file)
@@ -399,14 +399,13 @@ void __init swiotlb_init_remap(bool addressing_limit, unsigned int flags,
        }
 
        mem->areas = memblock_alloc(array_size(sizeof(struct io_tlb_area),
-               default_nareas), SMP_CACHE_BYTES);
+               nareas), SMP_CACHE_BYTES);
        if (!mem->areas) {
                pr_warn("%s: Failed to allocate mem->areas.\n", __func__);
                return;
        }
 
-       swiotlb_init_io_tlb_pool(mem, __pa(tlb), nslabs, false,
-                                default_nareas);
+       swiotlb_init_io_tlb_pool(mem, __pa(tlb), nslabs, false, nareas);
        add_mem_pool(&io_tlb_default_mem, mem);
 
        if (flags & SWIOTLB_VERBOSE)
@@ -729,9 +728,6 @@ static void swiotlb_dyn_alloc(struct work_struct *work)
        }
 
        add_mem_pool(mem, pool);
-
-       /* Pairs with smp_rmb() in is_swiotlb_buffer(). */
-       smp_wmb();
 }
 
 /**
@@ -1152,9 +1148,26 @@ static int swiotlb_find_slots(struct device *dev, phys_addr_t orig_addr,
        spin_unlock_irqrestore(&dev->dma_io_tlb_lock, flags);
 
 found:
-       dev->dma_uses_io_tlb = true;
-       /* Pairs with smp_rmb() in is_swiotlb_buffer() */
-       smp_wmb();
+       WRITE_ONCE(dev->dma_uses_io_tlb, true);
+
+       /*
+        * The general barrier orders reads and writes against a presumed store
+        * of the SWIOTLB buffer address by a device driver (to a driver private
+        * data structure). It serves two purposes.
+        *
+        * First, the store to dev->dma_uses_io_tlb must be ordered before the
+        * presumed store. This guarantees that the returned buffer address
+        * cannot be passed to another CPU before updating dev->dma_uses_io_tlb.
+        *
+        * Second, the load from mem->pools must be ordered before the same
+        * presumed store. This guarantees that the returned buffer address
+        * cannot be observed by another CPU before an update of the RCU list
+        * that was made by swiotlb_dyn_alloc() on a third CPU (cf. multicopy
+        * atomicity).
+        *
+        * See also the comment in is_swiotlb_buffer().
+        */
+       smp_mb();
 
        *retpool = pool;
        return index;
index fee14a4..6500ef9 100644 (file)
@@ -609,7 +609,7 @@ int pidfd_create(struct pid *pid, unsigned int flags)
 }
 
 /**
- * pidfd_open() - Open new pid file descriptor.
+ * sys_pidfd_open() - Open new pid file descriptor.
  *
  * @pid:   pid for which to retrieve a pidfd
  * @flags: flags to pass
index 87e9f7e..0f12e0a 100644 (file)
@@ -2647,7 +2647,7 @@ static int prepare_image(struct memory_bitmap *new_bm, struct memory_bitmap *bm,
        memory_bm_free(bm, PG_UNSAFE_KEEP);
 
        /* Make a copy of zero_bm so it can be created in safe pages */
-       error = memory_bm_create(&tmp, GFP_ATOMIC, PG_ANY);
+       error = memory_bm_create(&tmp, GFP_ATOMIC, PG_SAFE);
        if (error)
                goto Free;
 
@@ -2660,7 +2660,7 @@ static int prepare_image(struct memory_bitmap *new_bm, struct memory_bitmap *bm,
                goto Free;
 
        duplicate_memory_bitmap(zero_bm, &tmp);
-       memory_bm_free(&tmp, PG_UNSAFE_KEEP);
+       memory_bm_free(&tmp, PG_UNSAFE_CLEAR);
        /* At this point zero_bm is in safe pages and it can be used for restoring. */
 
        if (nr_highmem > 0) {
index 7e0b4dd..0b3af15 100644 (file)
@@ -3740,12 +3740,18 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
 
        seq = prb_next_seq(prb);
 
+       /* Flush the consoles so that records up to @seq are printed. */
+       console_lock();
+       console_unlock();
+
        for (;;) {
                diff = 0;
 
                /*
                 * Hold the console_lock to guarantee safe access to
-                * console->seq.
+                * console->seq. Releasing console_lock flushes more
+                * records in case @seq is still not printed on all
+                * usable consoles.
                 */
                console_lock();
 
index 2299a5c..802551e 100644 (file)
@@ -9269,7 +9269,7 @@ void __init init_idle(struct task_struct *idle, int cpu)
         * PF_KTHREAD should already be set at this point; regardless, make it
         * look like a proper per-CPU kthread.
         */
-       idle->flags |= PF_IDLE | PF_KTHREAD | PF_NO_SETAFFINITY;
+       idle->flags |= PF_KTHREAD | PF_NO_SETAFFINITY;
        kthread_set_per_cpu(idle, cpu);
 
 #ifdef CONFIG_SMP
index 4492608..458d359 100644 (file)
@@ -350,7 +350,8 @@ static void sugov_update_single_freq(struct update_util_data *hook, u64 time,
         * Except when the rq is capped by uclamp_max.
         */
        if (!uclamp_rq_is_capped(cpu_rq(sg_cpu->cpu)) &&
-           sugov_cpu_is_busy(sg_cpu) && next_f < sg_policy->next_freq) {
+           sugov_cpu_is_busy(sg_cpu) && next_f < sg_policy->next_freq &&
+           !sg_policy->need_freq_update) {
                next_f = sg_policy->next_freq;
 
                /* Restore cached freq as next_freq has changed */
index a286e72..42c40cf 100644 (file)
@@ -101,6 +101,7 @@ static inline int __cpupri_find(struct cpupri *cp, struct task_struct *p,
 
        if (lowest_mask) {
                cpumask_and(lowest_mask, &p->cpus_mask, vec->mask);
+               cpumask_and(lowest_mask, lowest_mask, cpu_active_mask);
 
                /*
                 * We have to ensure that we have at least one bit
index cb22592..ef7490c 100644 (file)
@@ -664,6 +664,10 @@ void avg_vruntime_update(struct cfs_rq *cfs_rq, s64 delta)
        cfs_rq->avg_vruntime -= cfs_rq->avg_load * delta;
 }
 
+/*
+ * Specifically: avg_runtime() + 0 must result in entity_eligible() := true
+ * For this to be so, the result of this function must have a left bias.
+ */
 u64 avg_vruntime(struct cfs_rq *cfs_rq)
 {
        struct sched_entity *curr = cfs_rq->curr;
@@ -677,8 +681,12 @@ u64 avg_vruntime(struct cfs_rq *cfs_rq)
                load += weight;
        }
 
-       if (load)
+       if (load) {
+               /* sign flips effective floor / ceil */
+               if (avg < 0)
+                       avg -= (load - 1);
                avg = div_s64(avg, load);
+       }
 
        return cfs_rq->min_vruntime + avg;
 }
@@ -4919,10 +4927,12 @@ static inline void update_misfit_status(struct task_struct *p, struct rq *rq) {}
 static void
 place_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
 {
-       u64 vslice = calc_delta_fair(se->slice, se);
-       u64 vruntime = avg_vruntime(cfs_rq);
+       u64 vslice, vruntime = avg_vruntime(cfs_rq);
        s64 lag = 0;
 
+       se->slice = sysctl_sched_base_slice;
+       vslice = calc_delta_fair(se->slice, se);
+
        /*
         * Due to how V is constructed as the weighted average of entities,
         * adding tasks with positive lag, or removing tasks with negative lag
index 342f58a..5007b25 100644 (file)
@@ -373,6 +373,7 @@ EXPORT_SYMBOL_GPL(play_idle_precise);
 
 void cpu_startup_entry(enum cpuhp_state state)
 {
+       current->flags |= PF_IDLE;
        arch_cpu_idle_prepare();
        cpuhp_online_idle(state);
        while (1)
index 065e1ef..95a7e1b 100644 (file)
@@ -78,6 +78,7 @@ int task_work_add(struct task_struct *task, struct callback_head *work,
  * task_work_cancel_match - cancel a pending work added by task_work_add()
  * @task: the task which should execute the work
  * @match: match function to call
+ * @data: data to be passed in to match function
  *
  * RETURNS:
  * The found work or NULL if not found.
index a7264b2..868008f 100644 (file)
@@ -2853,6 +2853,17 @@ static int get_modules_for_addrs(struct module ***mods, unsigned long *addrs, u3
        return arr.mods_cnt;
 }
 
+static int addrs_check_error_injection_list(unsigned long *addrs, u32 cnt)
+{
+       u32 i;
+
+       for (i = 0; i < cnt; i++) {
+               if (!within_error_injection_list(addrs[i]))
+                       return -EINVAL;
+       }
+       return 0;
+}
+
 int bpf_kprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *prog)
 {
        struct bpf_kprobe_multi_link *link = NULL;
@@ -2930,6 +2941,11 @@ int bpf_kprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr
                        goto error;
        }
 
+       if (prog->kprobe_override && addrs_check_error_injection_list(addrs, cnt)) {
+               err = -EINVAL;
+               goto error;
+       }
+
        link = kzalloc(sizeof(*link), GFP_KERNEL);
        if (!link) {
                err = -ENOMEM;
@@ -3207,8 +3223,10 @@ int bpf_uprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr
                rcu_read_lock();
                task = get_pid_task(find_vpid(pid), PIDTYPE_PID);
                rcu_read_unlock();
-               if (!task)
+               if (!task) {
+                       err = -ESRCH;
                        goto error_path_put;
+               }
        }
 
        err = -ENOMEM;
index a1651ed..515cafd 100644 (file)
@@ -354,6 +354,11 @@ static void rb_init_page(struct buffer_data_page *bpage)
        local_set(&bpage->commit, 0);
 }
 
+static __always_inline unsigned int rb_page_commit(struct buffer_page *bpage)
+{
+       return local_read(&bpage->page->commit);
+}
+
 static void free_buffer_page(struct buffer_page *bpage)
 {
        free_page((unsigned long)bpage->page);
@@ -1132,6 +1137,9 @@ __poll_t ring_buffer_poll_wait(struct trace_buffer *buffer, int cpu,
        if (full) {
                poll_wait(filp, &work->full_waiters, poll_table);
                work->full_waiters_pending = true;
+               if (!cpu_buffer->shortest_full ||
+                   cpu_buffer->shortest_full > full)
+                       cpu_buffer->shortest_full = full;
        } else {
                poll_wait(filp, &work->waiters, poll_table);
                work->waiters_pending = true;
@@ -2003,7 +2011,7 @@ rb_remove_pages(struct ring_buffer_per_cpu *cpu_buffer, unsigned long nr_pages)
                         * Increment overrun to account for the lost events.
                         */
                        local_add(page_entries, &cpu_buffer->overrun);
-                       local_sub(BUF_PAGE_SIZE, &cpu_buffer->entries_bytes);
+                       local_sub(rb_page_commit(to_remove_page), &cpu_buffer->entries_bytes);
                        local_inc(&cpu_buffer->pages_lost);
                }
 
@@ -2367,11 +2375,6 @@ rb_reader_event(struct ring_buffer_per_cpu *cpu_buffer)
                               cpu_buffer->reader_page->read);
 }
 
-static __always_inline unsigned rb_page_commit(struct buffer_page *bpage)
-{
-       return local_read(&bpage->page->commit);
-}
-
 static struct ring_buffer_event *
 rb_iter_head_event(struct ring_buffer_iter *iter)
 {
@@ -2517,7 +2520,7 @@ rb_handle_head_page(struct ring_buffer_per_cpu *cpu_buffer,
                 * the counters.
                 */
                local_add(entries, &cpu_buffer->overrun);
-               local_sub(BUF_PAGE_SIZE, &cpu_buffer->entries_bytes);
+               local_sub(rb_page_commit(next_page), &cpu_buffer->entries_bytes);
                local_inc(&cpu_buffer->pages_lost);
 
                /*
@@ -2660,9 +2663,6 @@ rb_reset_tail(struct ring_buffer_per_cpu *cpu_buffer,
 
        event = __rb_page_index(tail_page, tail);
 
-       /* account for padding bytes */
-       local_add(BUF_PAGE_SIZE - tail, &cpu_buffer->entries_bytes);
-
        /*
         * Save the original length to the meta data.
         * This will be used by the reader to add lost event
@@ -2676,7 +2676,8 @@ rb_reset_tail(struct ring_buffer_per_cpu *cpu_buffer,
         * write counter enough to allow another writer to slip
         * in on this page.
         * We put in a discarded commit instead, to make sure
-        * that this space is not used again.
+        * that this space is not used again, and this space will
+        * not be accounted into 'entries_bytes'.
         *
         * If we are less than the minimum size, we don't need to
         * worry about it.
@@ -2701,6 +2702,9 @@ rb_reset_tail(struct ring_buffer_per_cpu *cpu_buffer,
        /* time delta must be non zero */
        event->time_delta = 1;
 
+       /* account for padding bytes */
+       local_add(BUF_PAGE_SIZE - tail, &cpu_buffer->entries_bytes);
+
        /* Make sure the padding is visible before the tail_page->write update */
        smp_wmb();
 
@@ -4215,7 +4219,7 @@ u64 ring_buffer_oldest_event_ts(struct trace_buffer *buffer, int cpu)
 EXPORT_SYMBOL_GPL(ring_buffer_oldest_event_ts);
 
 /**
- * ring_buffer_bytes_cpu - get the number of bytes consumed in a cpu buffer
+ * ring_buffer_bytes_cpu - get the number of bytes unconsumed in a cpu buffer
  * @buffer: The ring buffer
  * @cpu: The per CPU buffer to read from.
  */
@@ -4723,6 +4727,7 @@ static void rb_advance_reader(struct ring_buffer_per_cpu *cpu_buffer)
 
        length = rb_event_length(event);
        cpu_buffer->reader_page->read += length;
+       cpu_buffer->read_bytes += length;
 }
 
 static void rb_advance_iter(struct ring_buffer_iter *iter)
@@ -5816,7 +5821,7 @@ int ring_buffer_read_page(struct trace_buffer *buffer,
        } else {
                /* update the entry counter */
                cpu_buffer->read += rb_page_entries(reader);
-               cpu_buffer->read_bytes += BUF_PAGE_SIZE;
+               cpu_buffer->read_bytes += rb_page_commit(reader);
 
                /* swap the pages */
                rb_init_page(bpage);
index 91951d0..f49d6dd 100644 (file)
@@ -2770,6 +2770,7 @@ void trace_event_eval_update(struct trace_eval_map **map, int len)
                                update_event_fields(call, map[i]);
                        }
                }
+               cond_resched();
        }
        up_write(&trace_event_sem);
 }
index 6f04665..b87f411 100644 (file)
@@ -127,8 +127,13 @@ struct user_event_enabler {
 /* Bit 7 is for freeing status of enablement */
 #define ENABLE_VAL_FREEING_BIT 7
 
-/* Only duplicate the bit value */
-#define ENABLE_VAL_DUP_MASK ENABLE_VAL_BIT_MASK
+/* Bit 8 is for marking 32-bit on 64-bit */
+#define ENABLE_VAL_32_ON_64_BIT 8
+
+#define ENABLE_VAL_COMPAT_MASK (1 << ENABLE_VAL_32_ON_64_BIT)
+
+/* Only duplicate the bit and compat values */
+#define ENABLE_VAL_DUP_MASK (ENABLE_VAL_BIT_MASK | ENABLE_VAL_COMPAT_MASK)
 
 #define ENABLE_BITOPS(e) (&(e)->values)
 
@@ -174,6 +179,30 @@ struct user_event_validator {
        int                     flags;
 };
 
+static inline void align_addr_bit(unsigned long *addr, int *bit,
+                                 unsigned long *flags)
+{
+       if (IS_ALIGNED(*addr, sizeof(long))) {
+#ifdef __BIG_ENDIAN
+               /* 32 bit on BE 64 bit requires a 32 bit offset when aligned. */
+               if (test_bit(ENABLE_VAL_32_ON_64_BIT, flags))
+                       *bit += 32;
+#endif
+               return;
+       }
+
+       *addr = ALIGN_DOWN(*addr, sizeof(long));
+
+       /*
+        * We only support 32 and 64 bit values. The only time we need
+        * to align is a 32 bit value on a 64 bit kernel, which on LE
+        * is always 32 bits, and on BE requires no change when unaligned.
+        */
+#ifdef __LITTLE_ENDIAN
+       *bit += 32;
+#endif
+}
+
 typedef void (*user_event_func_t) (struct user_event *user, struct iov_iter *i,
                                   void *tpdata, bool *faulted);
 
@@ -482,6 +511,7 @@ static int user_event_enabler_write(struct user_event_mm *mm,
        unsigned long *ptr;
        struct page *page;
        void *kaddr;
+       int bit = ENABLE_BIT(enabler);
        int ret;
 
        lockdep_assert_held(&event_mutex);
@@ -497,6 +527,8 @@ static int user_event_enabler_write(struct user_event_mm *mm,
                     test_bit(ENABLE_VAL_FREEING_BIT, ENABLE_BITOPS(enabler))))
                return -EBUSY;
 
+       align_addr_bit(&uaddr, &bit, ENABLE_BITOPS(enabler));
+
        ret = pin_user_pages_remote(mm->mm, uaddr, 1, FOLL_WRITE | FOLL_NOFAULT,
                                    &page, NULL);
 
@@ -515,9 +547,9 @@ static int user_event_enabler_write(struct user_event_mm *mm,
 
        /* Update bit atomically, user tracers must be atomic as well */
        if (enabler->event && enabler->event->status)
-               set_bit(ENABLE_BIT(enabler), ptr);
+               set_bit(bit, ptr);
        else
-               clear_bit(ENABLE_BIT(enabler), ptr);
+               clear_bit(bit, ptr);
 
        kunmap_local(kaddr);
        unpin_user_pages_dirty_lock(&page, 1, true);
@@ -849,6 +881,12 @@ static struct user_event_enabler
        enabler->event = user;
        enabler->addr = uaddr;
        enabler->values = reg->enable_bit;
+
+#if BITS_PER_LONG >= 64
+       if (reg->enable_size == 4)
+               set_bit(ENABLE_VAL_32_ON_64_BIT, ENABLE_BITOPS(enabler));
+#endif
+
 retry:
        /* Prevents state changes from racing with new enablers */
        mutex_lock(&event_mutex);
@@ -2377,7 +2415,8 @@ static long user_unreg_get(struct user_unreg __user *ureg,
 }
 
 static int user_event_mm_clear_bit(struct user_event_mm *user_mm,
-                                  unsigned long uaddr, unsigned char bit)
+                                  unsigned long uaddr, unsigned char bit,
+                                  unsigned long flags)
 {
        struct user_event_enabler enabler;
        int result;
@@ -2385,7 +2424,7 @@ static int user_event_mm_clear_bit(struct user_event_mm *user_mm,
 
        memset(&enabler, 0, sizeof(enabler));
        enabler.addr = uaddr;
-       enabler.values = bit;
+       enabler.values = bit | flags;
 retry:
        /* Prevents state changes from racing with new enablers */
        mutex_lock(&event_mutex);
@@ -2415,6 +2454,7 @@ static long user_events_ioctl_unreg(unsigned long uarg)
        struct user_event_mm *mm = current->user_event_mm;
        struct user_event_enabler *enabler, *next;
        struct user_unreg reg;
+       unsigned long flags;
        long ret;
 
        ret = user_unreg_get(ureg, &reg);
@@ -2425,6 +2465,7 @@ static long user_events_ioctl_unreg(unsigned long uarg)
        if (!mm)
                return -ENOENT;
 
+       flags = 0;
        ret = -ENOENT;
 
        /*
@@ -2441,6 +2482,9 @@ static long user_events_ioctl_unreg(unsigned long uarg)
                    ENABLE_BIT(enabler) == reg.disable_bit) {
                        set_bit(ENABLE_VAL_FREEING_BIT, ENABLE_BITOPS(enabler));
 
+                       /* We must keep compat flags for the clear */
+                       flags |= enabler->values & ENABLE_VAL_COMPAT_MASK;
+
                        if (!test_bit(ENABLE_VAL_FAULTING_BIT, ENABLE_BITOPS(enabler)))
                                user_event_enabler_destroy(enabler, true);
 
@@ -2454,7 +2498,7 @@ static long user_events_ioctl_unreg(unsigned long uarg)
        /* Ensure bit is now cleared for user, regardless of event status */
        if (!ret)
                ret = user_event_mm_clear_bit(mm, reg.disable_addr,
-                                             reg.disable_bit);
+                                             reg.disable_bit, flags);
 
        return ret;
 }
index c85825e..b9f053a 100644 (file)
@@ -6535,9 +6535,6 @@ void __init workqueue_init_early(void)
 
        BUG_ON(!zalloc_cpumask_var_node(&pt->pod_cpus[0], GFP_KERNEL, NUMA_NO_NODE));
 
-       wq_update_pod_attrs_buf = alloc_workqueue_attrs();
-       BUG_ON(!wq_update_pod_attrs_buf);
-
        pt->nr_pods = 1;
        cpumask_copy(pt->pod_cpus[0], cpu_possible_mask);
        pt->pod_node[0] = NUMA_NO_NODE;
@@ -6605,13 +6602,13 @@ static void __init wq_cpu_intensive_thresh_init(void)
        unsigned long thresh;
        unsigned long bogo;
 
+       pwq_release_worker = kthread_create_worker(0, "pool_workqueue_release");
+       BUG_ON(IS_ERR(pwq_release_worker));
+
        /* if the user set it to a specific value, keep it */
        if (wq_cpu_intensive_thresh_us != ULONG_MAX)
                return;
 
-       pwq_release_worker = kthread_create_worker(0, "pool_workqueue_release");
-       BUG_ON(IS_ERR(pwq_release_worker));
-
        /*
         * The default of 10ms is derived from the fact that most modern (as of
         * 2023) processors can do a lot in 10ms and that it's just below what
index 1a19a0a..e28db8e 100644 (file)
@@ -28,7 +28,7 @@ static int count_argc(const char *str)
 
 /**
  * argv_free - free an argv
- * @argv - the argument vector to be freed
+ * @argv: the argument vector to be freed
  *
  * Frees an argv and the strings it points to.
  */
@@ -46,7 +46,7 @@ EXPORT_SYMBOL(argv_free);
  * @str: the string to be split
  * @argcp: returned argument count
  *
- * Returns an array of pointers to strings which are split out from
+ * Returns: an array of pointers to strings which are split out from
  * @str.  This is performed by strictly splitting on white-space; no
  * quote processing is performed.  Multiple whitespace characters are
  * considered to be a single argument separator.  The returned array
index ee1ff0c..0e00a84 100644 (file)
@@ -256,6 +256,22 @@ bool mas_is_err(struct ma_state *mas)
        return xa_is_err(mas->node);
 }
 
+static __always_inline bool mas_is_overflow(struct ma_state *mas)
+{
+       if (unlikely(mas->node == MAS_OVERFLOW))
+               return true;
+
+       return false;
+}
+
+static __always_inline bool mas_is_underflow(struct ma_state *mas)
+{
+       if (unlikely(mas->node == MAS_UNDERFLOW))
+               return true;
+
+       return false;
+}
+
 static inline bool mas_searchable(struct ma_state *mas)
 {
        if (mas_is_none(mas))
@@ -4415,10 +4431,13 @@ no_entry:
  *
  * @mas: The maple state
  * @max: The minimum starting range
+ * @empty: Can be empty
+ * @set_underflow: Set the @mas->node to underflow state on limit.
  *
  * Return: The entry in the previous slot which is possibly NULL
  */
-static void *mas_prev_slot(struct ma_state *mas, unsigned long min, bool empty)
+static void *mas_prev_slot(struct ma_state *mas, unsigned long min, bool empty,
+                          bool set_underflow)
 {
        void *entry;
        void __rcu **slots;
@@ -4435,7 +4454,6 @@ retry:
        if (unlikely(mas_rewalk_if_dead(mas, node, save_point)))
                goto retry;
 
-again:
        if (mas->min <= min) {
                pivot = mas_safe_min(mas, pivots, mas->offset);
 
@@ -4443,9 +4461,10 @@ again:
                        goto retry;
 
                if (pivot <= min)
-                       return NULL;
+                       goto underflow;
        }
 
+again:
        if (likely(mas->offset)) {
                mas->offset--;
                mas->last = mas->index - 1;
@@ -4457,7 +4476,7 @@ again:
                }
 
                if (mas_is_none(mas))
-                       return NULL;
+                       goto underflow;
 
                mas->last = mas->max;
                node = mas_mn(mas);
@@ -4474,10 +4493,19 @@ again:
        if (likely(entry))
                return entry;
 
-       if (!empty)
+       if (!empty) {
+               if (mas->index <= min)
+                       goto underflow;
+
                goto again;
+       }
 
        return entry;
+
+underflow:
+       if (set_underflow)
+               mas->node = MAS_UNDERFLOW;
+       return NULL;
 }
 
 /*
@@ -4567,10 +4595,13 @@ no_entry:
  * @mas: The maple state
  * @max: The maximum starting range
  * @empty: Can be empty
+ * @set_overflow: Should @mas->node be set to overflow when the limit is
+ * reached.
  *
  * Return: The entry in the next slot which is possibly NULL
  */
-static void *mas_next_slot(struct ma_state *mas, unsigned long max, bool empty)
+static void *mas_next_slot(struct ma_state *mas, unsigned long max, bool empty,
+                          bool set_overflow)
 {
        void __rcu **slots;
        unsigned long *pivots;
@@ -4589,22 +4620,22 @@ retry:
        if (unlikely(mas_rewalk_if_dead(mas, node, save_point)))
                goto retry;
 
-again:
        if (mas->max >= max) {
                if (likely(mas->offset < data_end))
                        pivot = pivots[mas->offset];
                else
-                       return NULL; /* must be mas->max */
+                       goto overflow;
 
                if (unlikely(mas_rewalk_if_dead(mas, node, save_point)))
                        goto retry;
 
                if (pivot >= max)
-                       return NULL;
+                       goto overflow;
        }
 
        if (likely(mas->offset < data_end)) {
                mas->index = pivots[mas->offset] + 1;
+again:
                mas->offset++;
                if (likely(mas->offset < data_end))
                        mas->last = pivots[mas->offset];
@@ -4616,8 +4647,11 @@ again:
                        goto retry;
                }
 
-               if (mas_is_none(mas))
+               if (WARN_ON_ONCE(mas_is_none(mas))) {
+                       mas->node = MAS_OVERFLOW;
                        return NULL;
+                       goto overflow;
+               }
 
                mas->offset = 0;
                mas->index = mas->min;
@@ -4636,12 +4670,20 @@ again:
                return entry;
 
        if (!empty) {
-               if (!mas->offset)
-                       data_end = 2;
+               if (mas->last >= max)
+                       goto overflow;
+
+               mas->index = mas->last + 1;
+               /* Node cannot end on NULL, so it's safe to short-cut here */
                goto again;
        }
 
        return entry;
+
+overflow:
+       if (set_overflow)
+               mas->node = MAS_OVERFLOW;
+       return NULL;
 }
 
 /*
@@ -4651,17 +4693,20 @@ again:
  *
  * Set the @mas->node to the next entry and the range_start to
  * the beginning value for the entry.  Does not check beyond @limit.
- * Sets @mas->index and @mas->last to the limit if it is hit.
+ * Sets @mas->index and @mas->last to the range, Does not update @mas->index and
+ * @mas->last on overflow.
  * Restarts on dead nodes.
  *
  * Return: the next entry or %NULL.
  */
 static inline void *mas_next_entry(struct ma_state *mas, unsigned long limit)
 {
-       if (mas->last >= limit)
+       if (mas->last >= limit) {
+               mas->node = MAS_OVERFLOW;
                return NULL;
+       }
 
-       return mas_next_slot(mas, limit, false);
+       return mas_next_slot(mas, limit, false, true);
 }
 
 /*
@@ -4837,7 +4882,7 @@ void *mas_walk(struct ma_state *mas)
 {
        void *entry;
 
-       if (mas_is_none(mas) || mas_is_paused(mas) || mas_is_ptr(mas))
+       if (!mas_is_active(mas) || !mas_is_start(mas))
                mas->node = MAS_START;
 retry:
        entry = mas_state_walk(mas);
@@ -5294,14 +5339,22 @@ static inline void mte_destroy_walk(struct maple_enode *enode,
 
 static void mas_wr_store_setup(struct ma_wr_state *wr_mas)
 {
-       if (mas_is_start(wr_mas->mas))
-               return;
+       if (!mas_is_active(wr_mas->mas)) {
+               if (mas_is_start(wr_mas->mas))
+                       return;
 
-       if (unlikely(mas_is_paused(wr_mas->mas)))
-               goto reset;
+               if (unlikely(mas_is_paused(wr_mas->mas)))
+                       goto reset;
 
-       if (unlikely(mas_is_none(wr_mas->mas)))
-               goto reset;
+               if (unlikely(mas_is_none(wr_mas->mas)))
+                       goto reset;
+
+               if (unlikely(mas_is_overflow(wr_mas->mas)))
+                       goto reset;
+
+               if (unlikely(mas_is_underflow(wr_mas->mas)))
+                       goto reset;
+       }
 
        /*
         * A less strict version of mas_is_span_wr() where we allow spanning
@@ -5595,8 +5648,25 @@ static inline bool mas_next_setup(struct ma_state *mas, unsigned long max,
 {
        bool was_none = mas_is_none(mas);
 
-       if (mas_is_none(mas) || mas_is_paused(mas))
+       if (unlikely(mas->last >= max)) {
+               mas->node = MAS_OVERFLOW;
+               return true;
+       }
+
+       if (mas_is_active(mas))
+               return false;
+
+       if (mas_is_none(mas) || mas_is_paused(mas)) {
+               mas->node = MAS_START;
+       } else if (mas_is_overflow(mas)) {
+               /* Overflowed before, but the max changed */
                mas->node = MAS_START;
+       } else if (mas_is_underflow(mas)) {
+               mas->node = MAS_START;
+               *entry = mas_walk(mas);
+               if (*entry)
+                       return true;
+       }
 
        if (mas_is_start(mas))
                *entry = mas_walk(mas); /* Retries on dead nodes handled by mas_walk */
@@ -5615,6 +5685,7 @@ static inline bool mas_next_setup(struct ma_state *mas, unsigned long max,
 
        if (mas_is_none(mas))
                return true;
+
        return false;
 }
 
@@ -5637,7 +5708,7 @@ void *mas_next(struct ma_state *mas, unsigned long max)
                return entry;
 
        /* Retries on dead nodes handled by mas_next_slot */
-       return mas_next_slot(mas, max, false);
+       return mas_next_slot(mas, max, false, true);
 }
 EXPORT_SYMBOL_GPL(mas_next);
 
@@ -5660,7 +5731,7 @@ void *mas_next_range(struct ma_state *mas, unsigned long max)
                return entry;
 
        /* Retries on dead nodes handled by mas_next_slot */
-       return mas_next_slot(mas, max, true);
+       return mas_next_slot(mas, max, true, true);
 }
 EXPORT_SYMBOL_GPL(mas_next_range);
 
@@ -5691,18 +5762,31 @@ EXPORT_SYMBOL_GPL(mt_next);
 static inline bool mas_prev_setup(struct ma_state *mas, unsigned long min,
                void **entry)
 {
-       if (mas->index <= min)
-               goto none;
+       if (unlikely(mas->index <= min)) {
+               mas->node = MAS_UNDERFLOW;
+               return true;
+       }
 
-       if (mas_is_none(mas) || mas_is_paused(mas))
+       if (mas_is_active(mas))
+               return false;
+
+       if (mas_is_overflow(mas)) {
                mas->node = MAS_START;
+               *entry = mas_walk(mas);
+               if (*entry)
+                       return true;
+       }
 
-       if (mas_is_start(mas)) {
-               mas_walk(mas);
-               if (!mas->index)
-                       goto none;
+       if (mas_is_none(mas) || mas_is_paused(mas)) {
+               mas->node = MAS_START;
+       } else if (mas_is_underflow(mas)) {
+               /* underflowed before but the min changed */
+               mas->node = MAS_START;
        }
 
+       if (mas_is_start(mas))
+               mas_walk(mas);
+
        if (unlikely(mas_is_ptr(mas))) {
                if (!mas->index)
                        goto none;
@@ -5747,7 +5831,7 @@ void *mas_prev(struct ma_state *mas, unsigned long min)
        if (mas_prev_setup(mas, min, &entry))
                return entry;
 
-       return mas_prev_slot(mas, min, false);
+       return mas_prev_slot(mas, min, false, true);
 }
 EXPORT_SYMBOL_GPL(mas_prev);
 
@@ -5770,7 +5854,7 @@ void *mas_prev_range(struct ma_state *mas, unsigned long min)
        if (mas_prev_setup(mas, min, &entry))
                return entry;
 
-       return mas_prev_slot(mas, min, true);
+       return mas_prev_slot(mas, min, true, true);
 }
 EXPORT_SYMBOL_GPL(mas_prev_range);
 
@@ -5828,24 +5912,35 @@ EXPORT_SYMBOL_GPL(mas_pause);
 static inline bool mas_find_setup(struct ma_state *mas, unsigned long max,
                void **entry)
 {
-       *entry = NULL;
+       if (mas_is_active(mas)) {
+               if (mas->last < max)
+                       return false;
 
-       if (unlikely(mas_is_none(mas))) {
+               return true;
+       }
+
+       if (mas_is_paused(mas)) {
                if (unlikely(mas->last >= max))
                        return true;
 
-               mas->index = mas->last;
+               mas->index = ++mas->last;
                mas->node = MAS_START;
-       } else if (unlikely(mas_is_paused(mas))) {
+       } else if (mas_is_none(mas)) {
                if (unlikely(mas->last >= max))
                        return true;
 
+               mas->index = mas->last;
                mas->node = MAS_START;
-               mas->index = ++mas->last;
-       } else if (unlikely(mas_is_ptr(mas)))
-               goto ptr_out_of_range;
+       } else if (mas_is_overflow(mas) || mas_is_underflow(mas)) {
+               if (mas->index > max) {
+                       mas->node = MAS_OVERFLOW;
+                       return true;
+               }
+
+               mas->node = MAS_START;
+       }
 
-       if (unlikely(mas_is_start(mas))) {
+       if (mas_is_start(mas)) {
                /* First run or continue */
                if (mas->index > max)
                        return true;
@@ -5895,7 +5990,7 @@ void *mas_find(struct ma_state *mas, unsigned long max)
                return entry;
 
        /* Retries on dead nodes handled by mas_next_slot */
-       return mas_next_slot(mas, max, false);
+       return mas_next_slot(mas, max, false, false);
 }
 EXPORT_SYMBOL_GPL(mas_find);
 
@@ -5913,13 +6008,13 @@ EXPORT_SYMBOL_GPL(mas_find);
  */
 void *mas_find_range(struct ma_state *mas, unsigned long max)
 {
-       void *entry;
+       void *entry = NULL;
 
        if (mas_find_setup(mas, max, &entry))
                return entry;
 
        /* Retries on dead nodes handled by mas_next_slot */
-       return mas_next_slot(mas, max, true);
+       return mas_next_slot(mas, max, true, false);
 }
 EXPORT_SYMBOL_GPL(mas_find_range);
 
@@ -5934,26 +6029,36 @@ EXPORT_SYMBOL_GPL(mas_find_range);
 static inline bool mas_find_rev_setup(struct ma_state *mas, unsigned long min,
                void **entry)
 {
-       *entry = NULL;
-
-       if (unlikely(mas_is_none(mas))) {
-               if (mas->index <= min)
-                       goto none;
+       if (mas_is_active(mas)) {
+               if (mas->index > min)
+                       return false;
 
-               mas->last = mas->index;
-               mas->node = MAS_START;
+               return true;
        }
 
-       if (unlikely(mas_is_paused(mas))) {
+       if (mas_is_paused(mas)) {
                if (unlikely(mas->index <= min)) {
                        mas->node = MAS_NONE;
                        return true;
                }
                mas->node = MAS_START;
                mas->last = --mas->index;
+       } else if (mas_is_none(mas)) {
+               if (mas->index <= min)
+                       goto none;
+
+               mas->last = mas->index;
+               mas->node = MAS_START;
+       } else if (mas_is_underflow(mas) || mas_is_overflow(mas)) {
+               if (mas->last <= min) {
+                       mas->node = MAS_UNDERFLOW;
+                       return true;
+               }
+
+               mas->node = MAS_START;
        }
 
-       if (unlikely(mas_is_start(mas))) {
+       if (mas_is_start(mas)) {
                /* First run or continue */
                if (mas->index < min)
                        return true;
@@ -6004,13 +6109,13 @@ none:
  */
 void *mas_find_rev(struct ma_state *mas, unsigned long min)
 {
-       void *entry;
+       void *entry = NULL;
 
        if (mas_find_rev_setup(mas, min, &entry))
                return entry;
 
        /* Retries on dead nodes handled by mas_prev_slot */
-       return mas_prev_slot(mas, min, false);
+       return mas_prev_slot(mas, min, false, false);
 
 }
 EXPORT_SYMBOL_GPL(mas_find_rev);
@@ -6030,13 +6135,13 @@ EXPORT_SYMBOL_GPL(mas_find_rev);
  */
 void *mas_find_range_rev(struct ma_state *mas, unsigned long min)
 {
-       void *entry;
+       void *entry = NULL;
 
        if (mas_find_rev_setup(mas, min, &entry))
                return entry;
 
        /* Retries on dead nodes handled by mas_prev_slot */
-       return mas_prev_slot(mas, min, true);
+       return mas_prev_slot(mas, min, true, false);
 }
 EXPORT_SYMBOL_GPL(mas_find_range_rev);
 
index c65566b..68b45c8 100644 (file)
@@ -265,7 +265,8 @@ EXPORT_SYMBOL(sg_free_table);
  * @table:     The sg table header to use
  * @nents:     Number of entries in sg list
  * @max_ents:  The maximum number of entries the allocator returns per call
- * @nents_first_chunk: Number of entries int the (preallocated) first
+ * @first_chunk: first SGL if preallocated (may be %NULL)
+ * @nents_first_chunk: Number of entries in the (preallocated) first
  *     scatterlist chunk, 0 means no such preallocated chunk provided by user
  * @gfp_mask:  GFP allocation mask
  * @alloc_fn:  Allocator to use
@@ -788,6 +789,7 @@ EXPORT_SYMBOL(__sg_page_iter_dma_next);
  * @miter: sg mapping iter to be started
  * @sgl: sg list to iterate over
  * @nents: number of sg entries
+ * @flags: sg iterator flags
  *
  * Description:
  *   Starts mapping iterator @miter.
index 0674aeb..0695916 100644 (file)
@@ -2166,7 +2166,7 @@ static noinline void __init next_prev_test(struct maple_tree *mt)
        MT_BUG_ON(mt, val != NULL);
        MT_BUG_ON(mt, mas.index != 0);
        MT_BUG_ON(mt, mas.last != 5);
-       MT_BUG_ON(mt, mas.node != MAS_NONE);
+       MT_BUG_ON(mt, mas.node != MAS_UNDERFLOW);
 
        mas.index = 0;
        mas.last = 5;
@@ -2917,6 +2917,7 @@ static noinline void __init check_empty_area_fill(struct maple_tree *mt)
  *             exists  MAS_NONE        active          range
  *             exists  active          active          range
  *             DNE     active          active          set to last range
+ *             ERANGE  active          MAS_OVERFLOW    last range
  *
  * Function    ENTRY   Start           Result          index & last
  * mas_prev()
@@ -2945,6 +2946,7 @@ static noinline void __init check_empty_area_fill(struct maple_tree *mt)
  *             any     MAS_ROOT        MAS_NONE        0
  *             exists  active          active          range
  *             DNE     active          active          last range
+ *             ERANGE  active          MAS_UNDERFLOW   last range
  *
  * Function    ENTRY   Start           Result          index & last
  * mas_find()
@@ -2955,7 +2957,7 @@ static noinline void __init check_empty_area_fill(struct maple_tree *mt)
  *             DNE     MAS_START       MAS_NONE        0
  *             DNE     MAS_PAUSE       MAS_NONE        0
  *             DNE     MAS_ROOT        MAS_NONE        0
- *             DNE     MAS_NONE        MAS_NONE        0
+ *             DNE     MAS_NONE        MAS_NONE        1
  *                             if index ==  0
  *             exists  MAS_START       MAS_ROOT        0
  *             exists  MAS_PAUSE       MAS_ROOT        0
@@ -2967,7 +2969,7 @@ static noinline void __init check_empty_area_fill(struct maple_tree *mt)
  *             DNE     MAS_START       active          set to max
  *             exists  MAS_PAUSE       active          range
  *             DNE     MAS_PAUSE       active          set to max
- *             exists  MAS_NONE        active          range
+ *             exists  MAS_NONE        active          range (start at last)
  *             exists  active          active          range
  *             DNE     active          active          last range (max < last)
  *
@@ -2992,7 +2994,7 @@ static noinline void __init check_empty_area_fill(struct maple_tree *mt)
  *             DNE     MAS_START       active          set to min
  *             exists  MAS_PAUSE       active          range
  *             DNE     MAS_PAUSE       active          set to min
- *             exists  MAS_NONE        active          range
+ *             exists  MAS_NONE        active          range (start at index)
  *             exists  active          active          range
  *             DNE     active          active          last range (min > index)
  *
@@ -3039,10 +3041,10 @@ static noinline void __init check_state_handling(struct maple_tree *mt)
        mtree_store_range(mt, 0, 0, ptr, GFP_KERNEL);
 
        mas_lock(&mas);
-       /* prev: Start -> none */
+       /* prev: Start -> underflow*/
        entry = mas_prev(&mas, 0);
        MT_BUG_ON(mt, entry != NULL);
-       MT_BUG_ON(mt, mas.node != MAS_NONE);
+       MT_BUG_ON(mt, mas.node != MAS_UNDERFLOW);
 
        /* prev: Start -> root */
        mas_set(&mas, 10);
@@ -3069,7 +3071,7 @@ static noinline void __init check_state_handling(struct maple_tree *mt)
        MT_BUG_ON(mt, entry != NULL);
        MT_BUG_ON(mt, mas.node != MAS_NONE);
 
-       /* next: start -> none */
+       /* next: start -> none*/
        mas_set(&mas, 10);
        entry = mas_next(&mas, ULONG_MAX);
        MT_BUG_ON(mt, mas.index != 1);
@@ -3268,25 +3270,46 @@ static noinline void __init check_state_handling(struct maple_tree *mt)
        MT_BUG_ON(mt, mas.last != 0x2500);
        MT_BUG_ON(mt, !mas_active(mas));
 
-       /* next:active -> active out of range*/
+       /* next:active -> active beyond data */
        entry = mas_next(&mas, 0x2999);
        MT_BUG_ON(mt, entry != NULL);
        MT_BUG_ON(mt, mas.index != 0x2501);
        MT_BUG_ON(mt, mas.last != 0x2fff);
        MT_BUG_ON(mt, !mas_active(mas));
 
-       /* Continue after out of range*/
+       /* Continue after last range ends after max */
        entry = mas_next(&mas, ULONG_MAX);
        MT_BUG_ON(mt, entry != ptr3);
        MT_BUG_ON(mt, mas.index != 0x3000);
        MT_BUG_ON(mt, mas.last != 0x3500);
        MT_BUG_ON(mt, !mas_active(mas));
 
-       /* next:active -> active out of range*/
+       /* next:active -> active continued */
+       entry = mas_next(&mas, ULONG_MAX);
+       MT_BUG_ON(mt, entry != NULL);
+       MT_BUG_ON(mt, mas.index != 0x3501);
+       MT_BUG_ON(mt, mas.last != ULONG_MAX);
+       MT_BUG_ON(mt, !mas_active(mas));
+
+       /* next:active -> overflow  */
        entry = mas_next(&mas, ULONG_MAX);
        MT_BUG_ON(mt, entry != NULL);
        MT_BUG_ON(mt, mas.index != 0x3501);
        MT_BUG_ON(mt, mas.last != ULONG_MAX);
+       MT_BUG_ON(mt, mas.node != MAS_OVERFLOW);
+
+       /* next:overflow -> overflow  */
+       entry = mas_next(&mas, ULONG_MAX);
+       MT_BUG_ON(mt, entry != NULL);
+       MT_BUG_ON(mt, mas.index != 0x3501);
+       MT_BUG_ON(mt, mas.last != ULONG_MAX);
+       MT_BUG_ON(mt, mas.node != MAS_OVERFLOW);
+
+       /* prev:overflow -> active  */
+       entry = mas_prev(&mas, 0);
+       MT_BUG_ON(mt, entry != ptr3);
+       MT_BUG_ON(mt, mas.index != 0x3000);
+       MT_BUG_ON(mt, mas.last != 0x3500);
        MT_BUG_ON(mt, !mas_active(mas));
 
        /* next: none -> active, skip value at location */
@@ -3307,11 +3330,46 @@ static noinline void __init check_state_handling(struct maple_tree *mt)
        MT_BUG_ON(mt, mas.last != 0x1500);
        MT_BUG_ON(mt, !mas_active(mas));
 
-       /* prev:active -> active out of range*/
+       /* prev:active -> active spanning end range */
+       entry = mas_prev(&mas, 0x0100);
+       MT_BUG_ON(mt, entry != NULL);
+       MT_BUG_ON(mt, mas.index != 0);
+       MT_BUG_ON(mt, mas.last != 0x0FFF);
+       MT_BUG_ON(mt, !mas_active(mas));
+
+       /* prev:active -> underflow */
+       entry = mas_prev(&mas, 0);
+       MT_BUG_ON(mt, entry != NULL);
+       MT_BUG_ON(mt, mas.index != 0);
+       MT_BUG_ON(mt, mas.last != 0x0FFF);
+       MT_BUG_ON(mt, mas.node != MAS_UNDERFLOW);
+
+       /* prev:underflow -> underflow */
        entry = mas_prev(&mas, 0);
        MT_BUG_ON(mt, entry != NULL);
        MT_BUG_ON(mt, mas.index != 0);
        MT_BUG_ON(mt, mas.last != 0x0FFF);
+       MT_BUG_ON(mt, mas.node != MAS_UNDERFLOW);
+
+       /* next:underflow -> active */
+       entry = mas_next(&mas, ULONG_MAX);
+       MT_BUG_ON(mt, entry != ptr);
+       MT_BUG_ON(mt, mas.index != 0x1000);
+       MT_BUG_ON(mt, mas.last != 0x1500);
+       MT_BUG_ON(mt, !mas_active(mas));
+
+       /* prev:first value -> underflow */
+       entry = mas_prev(&mas, 0x1000);
+       MT_BUG_ON(mt, entry != NULL);
+       MT_BUG_ON(mt, mas.index != 0x1000);
+       MT_BUG_ON(mt, mas.last != 0x1500);
+       MT_BUG_ON(mt, mas.node != MAS_UNDERFLOW);
+
+       /* find:underflow -> first value */
+       entry = mas_find(&mas, ULONG_MAX);
+       MT_BUG_ON(mt, entry != ptr);
+       MT_BUG_ON(mt, mas.index != 0x1000);
+       MT_BUG_ON(mt, mas.last != 0x1500);
        MT_BUG_ON(mt, !mas_active(mas));
 
        /* prev: pause ->active */
@@ -3325,14 +3383,14 @@ static noinline void __init check_state_handling(struct maple_tree *mt)
        MT_BUG_ON(mt, mas.last != 0x2500);
        MT_BUG_ON(mt, !mas_active(mas));
 
-       /* prev:active -> active out of range*/
+       /* prev:active -> active spanning min */
        entry = mas_prev(&mas, 0x1600);
        MT_BUG_ON(mt, entry != NULL);
        MT_BUG_ON(mt, mas.index != 0x1501);
        MT_BUG_ON(mt, mas.last != 0x1FFF);
        MT_BUG_ON(mt, !mas_active(mas));
 
-       /* prev: active ->active, continue*/
+       /* prev: active ->active, continue */
        entry = mas_prev(&mas, 0);
        MT_BUG_ON(mt, entry != ptr);
        MT_BUG_ON(mt, mas.index != 0x1000);
@@ -3379,7 +3437,7 @@ static noinline void __init check_state_handling(struct maple_tree *mt)
        MT_BUG_ON(mt, mas.last != 0x2FFF);
        MT_BUG_ON(mt, !mas_active(mas));
 
-       /* find: none ->active */
+       /* find: overflow ->active */
        entry = mas_find(&mas, 0x5000);
        MT_BUG_ON(mt, entry != ptr3);
        MT_BUG_ON(mt, mas.index != 0x3000);
@@ -3778,7 +3836,6 @@ static int __init maple_tree_seed(void)
        check_empty_area_fill(&tree);
        mtree_destroy(&tree);
 
-
        mt_init_flags(&tree, MT_FLAGS_ALLOC_RANGE);
        check_state_handling(&tree);
        mtree_destroy(&tree);
index c4b455b..dcf1ca6 100644 (file)
@@ -148,6 +148,8 @@ static void damon_do_test_apply_three_regions(struct kunit *test,
                KUNIT_EXPECT_EQ(test, r->ar.start, expected[i * 2]);
                KUNIT_EXPECT_EQ(test, r->ar.end, expected[i * 2 + 1]);
        }
+
+       damon_destroy_target(t);
 }
 
 /*
index 4c81a9d..cf8a9fc 100644 (file)
@@ -341,13 +341,14 @@ static void damon_hugetlb_mkold(pte_t *pte, struct mm_struct *mm,
        bool referenced = false;
        pte_t entry = huge_ptep_get(pte);
        struct folio *folio = pfn_folio(pte_pfn(entry));
+       unsigned long psize = huge_page_size(hstate_vma(vma));
 
        folio_get(folio);
 
        if (pte_young(entry)) {
                referenced = true;
                entry = pte_mkold(entry);
-               set_huge_pte_at(mm, addr, pte, entry);
+               set_huge_pte_at(mm, addr, pte, entry, psize);
        }
 
 #ifdef CONFIG_MMU_NOTIFIER
index 582f531..f0a15ce 100644 (file)
@@ -3475,13 +3475,11 @@ skip:
  */
 static vm_fault_t filemap_map_folio_range(struct vm_fault *vmf,
                        struct folio *folio, unsigned long start,
-                       unsigned long addr, unsigned int nr_pages)
+                       unsigned long addr, unsigned int nr_pages,
+                       unsigned int *mmap_miss)
 {
        vm_fault_t ret = 0;
-       struct vm_area_struct *vma = vmf->vma;
-       struct file *file = vma->vm_file;
        struct page *page = folio_page(folio, start);
-       unsigned int mmap_miss = READ_ONCE(file->f_ra.mmap_miss);
        unsigned int count = 0;
        pte_t *old_ptep = vmf->pte;
 
@@ -3489,8 +3487,7 @@ static vm_fault_t filemap_map_folio_range(struct vm_fault *vmf,
                if (PageHWPoison(page + count))
                        goto skip;
 
-               if (mmap_miss > 0)
-                       mmap_miss--;
+               (*mmap_miss)++;
 
                /*
                 * NOTE: If there're PTE markers, we'll leave them to be
@@ -3506,7 +3503,7 @@ skip:
                if (count) {
                        set_pte_range(vmf, folio, page, count, addr);
                        folio_ref_add(folio, count);
-                       if (in_range(vmf->address, addr, count))
+                       if (in_range(vmf->address, addr, count * PAGE_SIZE))
                                ret = VM_FAULT_NOPAGE;
                }
 
@@ -3520,12 +3517,40 @@ skip:
        if (count) {
                set_pte_range(vmf, folio, page, count, addr);
                folio_ref_add(folio, count);
-               if (in_range(vmf->address, addr, count))
+               if (in_range(vmf->address, addr, count * PAGE_SIZE))
                        ret = VM_FAULT_NOPAGE;
        }
 
        vmf->pte = old_ptep;
-       WRITE_ONCE(file->f_ra.mmap_miss, mmap_miss);
+
+       return ret;
+}
+
+static vm_fault_t filemap_map_order0_folio(struct vm_fault *vmf,
+               struct folio *folio, unsigned long addr,
+               unsigned int *mmap_miss)
+{
+       vm_fault_t ret = 0;
+       struct page *page = &folio->page;
+
+       if (PageHWPoison(page))
+               return ret;
+
+       (*mmap_miss)++;
+
+       /*
+        * NOTE: If there're PTE markers, we'll leave them to be
+        * handled in the specific fault path, and it'll prohibit
+        * the fault-around logic.
+        */
+       if (!pte_none(ptep_get(vmf->pte)))
+               return ret;
+
+       if (vmf->address == addr)
+               ret = VM_FAULT_NOPAGE;
+
+       set_pte_range(vmf, folio, page, 1, addr);
+       folio_ref_inc(folio);
 
        return ret;
 }
@@ -3541,7 +3566,7 @@ vm_fault_t filemap_map_pages(struct vm_fault *vmf,
        XA_STATE(xas, &mapping->i_pages, start_pgoff);
        struct folio *folio;
        vm_fault_t ret = 0;
-       int nr_pages = 0;
+       unsigned int nr_pages = 0, mmap_miss = 0, mmap_miss_saved;
 
        rcu_read_lock();
        folio = next_uptodate_folio(&xas, mapping, end_pgoff);
@@ -3569,25 +3594,27 @@ vm_fault_t filemap_map_pages(struct vm_fault *vmf,
                end = folio->index + folio_nr_pages(folio) - 1;
                nr_pages = min(end, end_pgoff) - xas.xa_index + 1;
 
-               /*
-                * NOTE: If there're PTE markers, we'll leave them to be
-                * handled in the specific fault path, and it'll prohibit the
-                * fault-around logic.
-                */
-               if (!pte_none(ptep_get(vmf->pte)))
-                       goto unlock;
-
-               ret |= filemap_map_folio_range(vmf, folio,
-                               xas.xa_index - folio->index, addr, nr_pages);
+               if (!folio_test_large(folio))
+                       ret |= filemap_map_order0_folio(vmf,
+                                       folio, addr, &mmap_miss);
+               else
+                       ret |= filemap_map_folio_range(vmf, folio,
+                                       xas.xa_index - folio->index, addr,
+                                       nr_pages, &mmap_miss);
 
-unlock:
                folio_unlock(folio);
                folio_put(folio);
-               folio = next_uptodate_folio(&xas, mapping, end_pgoff);
-       } while (folio);
+       } while ((folio = next_uptodate_folio(&xas, mapping, end_pgoff)) != NULL);
        pte_unmap_unlock(vmf->pte, vmf->ptl);
 out:
        rcu_read_unlock();
+
+       mmap_miss_saved = READ_ONCE(file->f_ra.mmap_miss);
+       if (mmap_miss >= mmap_miss_saved)
+               WRITE_ONCE(file->f_ra.mmap_miss, 0);
+       else
+               WRITE_ONCE(file->f_ra.mmap_miss, mmap_miss_saved - mmap_miss);
+
        return ret;
 }
 EXPORT_SYMBOL(filemap_map_pages);
index ba6d39b..52d2607 100644 (file)
@@ -4980,7 +4980,7 @@ static bool is_hugetlb_entry_hwpoisoned(pte_t pte)
 
 static void
 hugetlb_install_folio(struct vm_area_struct *vma, pte_t *ptep, unsigned long addr,
-                     struct folio *new_folio, pte_t old)
+                     struct folio *new_folio, pte_t old, unsigned long sz)
 {
        pte_t newpte = make_huge_pte(vma, &new_folio->page, 1);
 
@@ -4988,7 +4988,7 @@ hugetlb_install_folio(struct vm_area_struct *vma, pte_t *ptep, unsigned long add
        hugepage_add_new_anon_rmap(new_folio, vma, addr);
        if (userfaultfd_wp(vma) && huge_pte_uffd_wp(old))
                newpte = huge_pte_mkuffd_wp(newpte);
-       set_huge_pte_at(vma->vm_mm, addr, ptep, newpte);
+       set_huge_pte_at(vma->vm_mm, addr, ptep, newpte, sz);
        hugetlb_count_add(pages_per_huge_page(hstate_vma(vma)), vma->vm_mm);
        folio_set_hugetlb_migratable(new_folio);
 }
@@ -5065,7 +5065,7 @@ again:
                } else if (unlikely(is_hugetlb_entry_hwpoisoned(entry))) {
                        if (!userfaultfd_wp(dst_vma))
                                entry = huge_pte_clear_uffd_wp(entry);
-                       set_huge_pte_at(dst, addr, dst_pte, entry);
+                       set_huge_pte_at(dst, addr, dst_pte, entry, sz);
                } else if (unlikely(is_hugetlb_entry_migration(entry))) {
                        swp_entry_t swp_entry = pte_to_swp_entry(entry);
                        bool uffd_wp = pte_swp_uffd_wp(entry);
@@ -5080,18 +5080,18 @@ again:
                                entry = swp_entry_to_pte(swp_entry);
                                if (userfaultfd_wp(src_vma) && uffd_wp)
                                        entry = pte_swp_mkuffd_wp(entry);
-                               set_huge_pte_at(src, addr, src_pte, entry);
+                               set_huge_pte_at(src, addr, src_pte, entry, sz);
                        }
                        if (!userfaultfd_wp(dst_vma))
                                entry = huge_pte_clear_uffd_wp(entry);
-                       set_huge_pte_at(dst, addr, dst_pte, entry);
+                       set_huge_pte_at(dst, addr, dst_pte, entry, sz);
                } else if (unlikely(is_pte_marker(entry))) {
                        pte_marker marker = copy_pte_marker(
                                pte_to_swp_entry(entry), dst_vma);
 
                        if (marker)
                                set_huge_pte_at(dst, addr, dst_pte,
-                                               make_pte_marker(marker));
+                                               make_pte_marker(marker), sz);
                } else {
                        entry = huge_ptep_get(src_pte);
                        pte_folio = page_folio(pte_page(entry));
@@ -5145,7 +5145,7 @@ again:
                                        goto again;
                                }
                                hugetlb_install_folio(dst_vma, dst_pte, addr,
-                                                     new_folio, src_pte_old);
+                                                     new_folio, src_pte_old, sz);
                                spin_unlock(src_ptl);
                                spin_unlock(dst_ptl);
                                continue;
@@ -5166,7 +5166,7 @@ again:
                        if (!userfaultfd_wp(dst_vma))
                                entry = huge_pte_clear_uffd_wp(entry);
 
-                       set_huge_pte_at(dst, addr, dst_pte, entry);
+                       set_huge_pte_at(dst, addr, dst_pte, entry, sz);
                        hugetlb_count_add(npages, dst);
                }
                spin_unlock(src_ptl);
@@ -5184,7 +5184,8 @@ again:
 }
 
 static void move_huge_pte(struct vm_area_struct *vma, unsigned long old_addr,
-                         unsigned long new_addr, pte_t *src_pte, pte_t *dst_pte)
+                         unsigned long new_addr, pte_t *src_pte, pte_t *dst_pte,
+                         unsigned long sz)
 {
        struct hstate *h = hstate_vma(vma);
        struct mm_struct *mm = vma->vm_mm;
@@ -5202,7 +5203,7 @@ static void move_huge_pte(struct vm_area_struct *vma, unsigned long old_addr,
                spin_lock_nested(src_ptl, SINGLE_DEPTH_NESTING);
 
        pte = huge_ptep_get_and_clear(mm, old_addr, src_pte);
-       set_huge_pte_at(mm, new_addr, dst_pte, pte);
+       set_huge_pte_at(mm, new_addr, dst_pte, pte, sz);
 
        if (src_ptl != dst_ptl)
                spin_unlock(src_ptl);
@@ -5259,7 +5260,7 @@ int move_hugetlb_page_tables(struct vm_area_struct *vma,
                if (!dst_pte)
                        break;
 
-               move_huge_pte(vma, old_addr, new_addr, src_pte, dst_pte);
+               move_huge_pte(vma, old_addr, new_addr, src_pte, dst_pte, sz);
        }
 
        if (shared_pmd)
@@ -5337,7 +5338,8 @@ static void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct
                        if (pte_swp_uffd_wp_any(pte) &&
                            !(zap_flags & ZAP_FLAG_DROP_MARKER))
                                set_huge_pte_at(mm, address, ptep,
-                                               make_pte_marker(PTE_MARKER_UFFD_WP));
+                                               make_pte_marker(PTE_MARKER_UFFD_WP),
+                                               sz);
                        else
                                huge_pte_clear(mm, address, ptep, sz);
                        spin_unlock(ptl);
@@ -5371,7 +5373,8 @@ static void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct
                if (huge_pte_uffd_wp(pte) &&
                    !(zap_flags & ZAP_FLAG_DROP_MARKER))
                        set_huge_pte_at(mm, address, ptep,
-                                       make_pte_marker(PTE_MARKER_UFFD_WP));
+                                       make_pte_marker(PTE_MARKER_UFFD_WP),
+                                       sz);
                hugetlb_count_sub(pages_per_huge_page(h), mm);
                page_remove_rmap(page, vma, true);
 
@@ -5676,7 +5679,7 @@ retry_avoidcopy:
                hugepage_add_new_anon_rmap(new_folio, vma, haddr);
                if (huge_pte_uffd_wp(pte))
                        newpte = huge_pte_mkuffd_wp(newpte);
-               set_huge_pte_at(mm, haddr, ptep, newpte);
+               set_huge_pte_at(mm, haddr, ptep, newpte, huge_page_size(h));
                folio_set_hugetlb_migratable(new_folio);
                /* Make the old page be freed below */
                new_folio = old_folio;
@@ -5972,7 +5975,7 @@ static vm_fault_t hugetlb_no_page(struct mm_struct *mm,
         */
        if (unlikely(pte_marker_uffd_wp(old_pte)))
                new_pte = huge_pte_mkuffd_wp(new_pte);
-       set_huge_pte_at(mm, haddr, ptep, new_pte);
+       set_huge_pte_at(mm, haddr, ptep, new_pte, huge_page_size(h));
 
        hugetlb_count_add(pages_per_huge_page(h), mm);
        if ((flags & FAULT_FLAG_WRITE) && !(vma->vm_flags & VM_SHARED)) {
@@ -6261,7 +6264,8 @@ int hugetlb_mfill_atomic_pte(pte_t *dst_pte,
                }
 
                _dst_pte = make_pte_marker(PTE_MARKER_POISONED);
-               set_huge_pte_at(dst_mm, dst_addr, dst_pte, _dst_pte);
+               set_huge_pte_at(dst_mm, dst_addr, dst_pte, _dst_pte,
+                               huge_page_size(h));
 
                /* No need to invalidate - it was non-present before */
                update_mmu_cache(dst_vma, dst_addr, dst_pte);
@@ -6412,7 +6416,7 @@ int hugetlb_mfill_atomic_pte(pte_t *dst_pte,
        if (wp_enabled)
                _dst_pte = huge_pte_mkuffd_wp(_dst_pte);
 
-       set_huge_pte_at(dst_mm, dst_addr, dst_pte, _dst_pte);
+       set_huge_pte_at(dst_mm, dst_addr, dst_pte, _dst_pte, huge_page_size(h));
 
        hugetlb_count_add(pages_per_huge_page(h), dst_mm);
 
@@ -6598,7 +6602,7 @@ long hugetlb_change_protection(struct vm_area_struct *vma,
                        else if (uffd_wp_resolve)
                                newpte = pte_swp_clear_uffd_wp(newpte);
                        if (!pte_same(pte, newpte))
-                               set_huge_pte_at(mm, address, ptep, newpte);
+                               set_huge_pte_at(mm, address, ptep, newpte, psize);
                } else if (unlikely(is_pte_marker(pte))) {
                        /* No other markers apply for now. */
                        WARN_ON_ONCE(!pte_marker_uffd_wp(pte));
@@ -6623,7 +6627,8 @@ long hugetlb_change_protection(struct vm_area_struct *vma,
                        if (unlikely(uffd_wp))
                                /* Safe to modify directly (none->non-present). */
                                set_huge_pte_at(mm, address, ptep,
-                                               make_pte_marker(PTE_MARKER_UFFD_WP));
+                                               make_pte_marker(PTE_MARKER_UFFD_WP),
+                                               psize);
                }
                spin_unlock(ptl);
        }
index f70e3d7..d37831b 100644 (file)
@@ -291,7 +291,7 @@ struct kasan_stack_ring {
 
 #if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS)
 
-#ifndef __HAVE_ARCH_SHADOW_MAP
+#ifndef kasan_shadow_to_mem
 static inline const void *kasan_shadow_to_mem(const void *shadow_addr)
 {
        return (void *)(((unsigned long)shadow_addr - KASAN_SHADOW_OFFSET)
@@ -299,15 +299,13 @@ static inline const void *kasan_shadow_to_mem(const void *shadow_addr)
 }
 #endif
 
+#ifndef addr_has_metadata
 static __always_inline bool addr_has_metadata(const void *addr)
 {
-#ifdef __HAVE_ARCH_SHADOW_MAP
-       return (kasan_mem_to_shadow((void *)addr) != NULL);
-#else
        return (kasan_reset_tag(addr) >=
                kasan_shadow_to_mem((void *)KASAN_SHADOW_START));
-#endif
 }
+#endif
 
 /**
  * kasan_check_range - Check memory region, and report if invalid access.
index a4d3282..5b009b2 100644 (file)
@@ -2555,7 +2555,7 @@ static unsigned long calculate_high_delay(struct mem_cgroup *memcg,
  * Scheduled by try_charge() to be executed from the userland return path
  * and reclaims memory over the high limit.
  */
-void mem_cgroup_handle_over_high(void)
+void mem_cgroup_handle_over_high(gfp_t gfp_mask)
 {
        unsigned long penalty_jiffies;
        unsigned long pflags;
@@ -2583,7 +2583,7 @@ retry_reclaim:
         */
        nr_reclaimed = reclaim_high(memcg,
                                    in_retry ? SWAP_CLUSTER_MAX : nr_pages,
-                                   GFP_KERNEL);
+                                   gfp_mask);
 
        /*
         * memory.high is breached and reclaim is unable to keep up. Throttle
@@ -2819,7 +2819,7 @@ done_restock:
        if (current->memcg_nr_pages_over_high > MEMCG_CHARGE_BATCH &&
            !(current->flags & PF_MEMALLOC) &&
            gfpflags_allow_blocking(gfp_mask)) {
-               mem_cgroup_handle_over_high();
+               mem_cgroup_handle_over_high(gfp_mask);
        }
        return 0;
 }
@@ -3867,6 +3867,13 @@ static ssize_t mem_cgroup_write(struct kernfs_open_file *of,
                case _MEMSWAP:
                        ret = mem_cgroup_resize_max(memcg, nr_pages, true);
                        break;
+               case _KMEM:
+                       pr_warn_once("kmem.limit_in_bytes is deprecated and will be removed. "
+                                    "Writing any value to this file has no effect. "
+                                    "Please report your usecase to linux-mm@kvack.org if you "
+                                    "depend on this functionality.\n");
+                       ret = 0;
+                       break;
                case _TCP:
                        ret = memcg_update_tcp_max(memcg, nr_pages);
                        break;
@@ -5078,6 +5085,12 @@ static struct cftype mem_cgroup_legacy_files[] = {
        },
 #endif
        {
+               .name = "kmem.limit_in_bytes",
+               .private = MEMFILE_PRIVATE(_KMEM, RES_LIMIT),
+               .write = mem_cgroup_write,
+               .read_u64 = mem_cgroup_read_u64,
+       },
+       {
                .name = "kmem.usage_in_bytes",
                .private = MEMFILE_PRIVATE(_KMEM, RES_USAGE),
                .read_u64 = mem_cgroup_read_u64,
index 42b5567..f1b00d6 100644 (file)
@@ -426,6 +426,7 @@ struct queue_pages {
        unsigned long start;
        unsigned long end;
        struct vm_area_struct *first;
+       bool has_unmovable;
 };
 
 /*
@@ -446,9 +447,8 @@ static inline bool queue_folio_required(struct folio *folio,
 /*
  * queue_folios_pmd() has three possible return values:
  * 0 - folios are placed on the right node or queued successfully, or
- *     special page is met, i.e. huge zero page.
- * 1 - there is unmovable folio, and MPOL_MF_MOVE* & MPOL_MF_STRICT were
- *     specified.
+ *     special page is met, i.e. zero page, or unmovable page is found
+ *     but continue walking (indicated by queue_pages.has_unmovable).
  * -EIO - is migration entry or only MPOL_MF_STRICT was specified and an
  *        existing folio was already on a node that does not follow the
  *        policy.
@@ -479,7 +479,7 @@ static int queue_folios_pmd(pmd_t *pmd, spinlock_t *ptl, unsigned long addr,
        if (flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL)) {
                if (!vma_migratable(walk->vma) ||
                    migrate_folio_add(folio, qp->pagelist, flags)) {
-                       ret = 1;
+                       qp->has_unmovable = true;
                        goto unlock;
                }
        } else
@@ -495,9 +495,8 @@ unlock:
  *
  * queue_folios_pte_range() has three possible return values:
  * 0 - folios are placed on the right node or queued successfully, or
- *     special page is met, i.e. zero page.
- * 1 - there is unmovable folio, and MPOL_MF_MOVE* & MPOL_MF_STRICT were
- *     specified.
+ *     special page is met, i.e. zero page, or unmovable page is found
+ *     but continue walking (indicated by queue_pages.has_unmovable).
  * -EIO - only MPOL_MF_STRICT was specified and an existing folio was already
  *        on a node that does not follow the policy.
  */
@@ -508,7 +507,6 @@ static int queue_folios_pte_range(pmd_t *pmd, unsigned long addr,
        struct folio *folio;
        struct queue_pages *qp = walk->private;
        unsigned long flags = qp->flags;
-       bool has_unmovable = false;
        pte_t *pte, *mapped_pte;
        pte_t ptent;
        spinlock_t *ptl;
@@ -538,11 +536,12 @@ static int queue_folios_pte_range(pmd_t *pmd, unsigned long addr,
                if (!queue_folio_required(folio, qp))
                        continue;
                if (flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL)) {
-                       /* MPOL_MF_STRICT must be specified if we get here */
-                       if (!vma_migratable(vma)) {
-                               has_unmovable = true;
-                               break;
-                       }
+                       /*
+                        * MPOL_MF_STRICT must be specified if we get here.
+                        * Continue walking vmas due to MPOL_MF_MOVE* flags.
+                        */
+                       if (!vma_migratable(vma))
+                               qp->has_unmovable = true;
 
                        /*
                         * Do not abort immediately since there may be
@@ -550,16 +549,13 @@ static int queue_folios_pte_range(pmd_t *pmd, unsigned long addr,
                         * need migrate other LRU pages.
                         */
                        if (migrate_folio_add(folio, qp->pagelist, flags))
-                               has_unmovable = true;
+                               qp->has_unmovable = true;
                } else
                        break;
        }
        pte_unmap_unlock(mapped_pte, ptl);
        cond_resched();
 
-       if (has_unmovable)
-               return 1;
-
        return addr != end ? -EIO : 0;
 }
 
@@ -599,7 +595,7 @@ static int queue_folios_hugetlb(pte_t *pte, unsigned long hmask,
                 * Detecting misplaced folio but allow migrating folios which
                 * have been queued.
                 */
-               ret = 1;
+               qp->has_unmovable = true;
                goto unlock;
        }
 
@@ -620,7 +616,7 @@ static int queue_folios_hugetlb(pte_t *pte, unsigned long hmask,
                         * Failed to isolate folio but allow migrating pages
                         * which have been queued.
                         */
-                       ret = 1;
+                       qp->has_unmovable = true;
        }
 unlock:
        spin_unlock(ptl);
@@ -756,12 +752,15 @@ queue_pages_range(struct mm_struct *mm, unsigned long start, unsigned long end,
                .start = start,
                .end = end,
                .first = NULL,
+               .has_unmovable = false,
        };
        const struct mm_walk_ops *ops = lock_vma ?
                        &queue_pages_lock_vma_walk_ops : &queue_pages_walk_ops;
 
        err = walk_page_range(mm, start, end, ops, &qp);
 
+       if (qp.has_unmovable)
+               err = 1;
        if (!qp.first)
                /* whole range in hole */
                err = -EFAULT;
@@ -1358,7 +1357,7 @@ static long do_mbind(unsigned long start, unsigned long len,
                                putback_movable_pages(&pagelist);
                }
 
-               if ((ret > 0) || (nr_failed && (flags & MPOL_MF_STRICT)))
+               if (((ret > 0) || nr_failed) && (flags & MPOL_MF_STRICT))
                        err = -EIO;
        } else {
 up_out:
index b7fa020..2053b54 100644 (file)
@@ -243,7 +243,9 @@ static bool remove_migration_pte(struct folio *folio,
 
 #ifdef CONFIG_HUGETLB_PAGE
                if (folio_test_hugetlb(folio)) {
-                       unsigned int shift = huge_page_shift(hstate_vma(vma));
+                       struct hstate *h = hstate_vma(vma);
+                       unsigned int shift = huge_page_shift(h);
+                       unsigned long psize = huge_page_size(h);
 
                        pte = arch_make_huge_pte(pte, shift, vma->vm_flags);
                        if (folio_test_anon(folio))
@@ -251,7 +253,8 @@ static bool remove_migration_pte(struct folio *folio,
                                                       rmap_flags);
                        else
                                page_dup_file_rmap(new, true);
-                       set_huge_pte_at(vma->vm_mm, pvmw.address, pvmw.pte, pte);
+                       set_huge_pte_at(vma->vm_mm, pvmw.address, pvmw.pte, pte,
+                                       psize);
                } else
 #endif
                {
index 0c5be12..95546f3 100644 (file)
@@ -2400,7 +2400,7 @@ void free_unref_page(struct page *page, unsigned int order)
        struct per_cpu_pages *pcp;
        struct zone *zone;
        unsigned long pfn = page_to_pfn(page);
-       int migratetype;
+       int migratetype, pcpmigratetype;
 
        if (!free_unref_page_prepare(page, pfn, order))
                return;
@@ -2408,24 +2408,24 @@ void free_unref_page(struct page *page, unsigned int order)
        /*
         * We only track unmovable, reclaimable and movable on pcp lists.
         * Place ISOLATE pages on the isolated list because they are being
-        * offlined but treat HIGHATOMIC as movable pages so we can get those
-        * areas back if necessary. Otherwise, we may have to free
+        * offlined but treat HIGHATOMIC and CMA as movable pages so we can
+        * get those areas back if necessary. Otherwise, we may have to free
         * excessively into the page allocator
         */
-       migratetype = get_pcppage_migratetype(page);
+       migratetype = pcpmigratetype = get_pcppage_migratetype(page);
        if (unlikely(migratetype >= MIGRATE_PCPTYPES)) {
                if (unlikely(is_migrate_isolate(migratetype))) {
                        free_one_page(page_zone(page), page, pfn, order, migratetype, FPI_NONE);
                        return;
                }
-               migratetype = MIGRATE_MOVABLE;
+               pcpmigratetype = MIGRATE_MOVABLE;
        }
 
        zone = page_zone(page);
        pcp_trylock_prepare(UP_flags);
        pcp = pcp_spin_trylock(zone->per_cpu_pageset);
        if (pcp) {
-               free_unref_page_commit(zone, pcp, page, migratetype, order);
+               free_unref_page_commit(zone, pcp, page, pcpmigratetype, order);
                pcp_spin_unlock(pcp);
        } else {
                free_one_page(zone, page, pfn, order, migratetype, FPI_NONE);
index ec7f8e6..9f795b9 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -1480,6 +1480,7 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,
        struct mmu_notifier_range range;
        enum ttu_flags flags = (enum ttu_flags)(long)arg;
        unsigned long pfn;
+       unsigned long hsz = 0;
 
        /*
         * When racing against e.g. zap_pte_range() on another cpu,
@@ -1511,6 +1512,9 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,
                 */
                adjust_range_if_pmd_sharing_possible(vma, &range.start,
                                                     &range.end);
+
+               /* We need the huge page size for set_huge_pte_at() */
+               hsz = huge_page_size(hstate_vma(vma));
        }
        mmu_notifier_invalidate_range_start(&range);
 
@@ -1628,7 +1632,8 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,
                        pteval = swp_entry_to_pte(make_hwpoison_entry(subpage));
                        if (folio_test_hugetlb(folio)) {
                                hugetlb_count_sub(folio_nr_pages(folio), mm);
-                               set_huge_pte_at(mm, address, pvmw.pte, pteval);
+                               set_huge_pte_at(mm, address, pvmw.pte, pteval,
+                                               hsz);
                        } else {
                                dec_mm_counter(mm, mm_counter(&folio->page));
                                set_pte_at(mm, address, pvmw.pte, pteval);
@@ -1820,6 +1825,7 @@ static bool try_to_migrate_one(struct folio *folio, struct vm_area_struct *vma,
        struct mmu_notifier_range range;
        enum ttu_flags flags = (enum ttu_flags)(long)arg;
        unsigned long pfn;
+       unsigned long hsz = 0;
 
        /*
         * When racing against e.g. zap_pte_range() on another cpu,
@@ -1855,6 +1861,9 @@ static bool try_to_migrate_one(struct folio *folio, struct vm_area_struct *vma,
                 */
                adjust_range_if_pmd_sharing_possible(vma, &range.start,
                                                     &range.end);
+
+               /* We need the huge page size for set_huge_pte_at() */
+               hsz = huge_page_size(hstate_vma(vma));
        }
        mmu_notifier_invalidate_range_start(&range);
 
@@ -2020,7 +2029,8 @@ static bool try_to_migrate_one(struct folio *folio, struct vm_area_struct *vma,
                        pteval = swp_entry_to_pte(make_hwpoison_entry(subpage));
                        if (folio_test_hugetlb(folio)) {
                                hugetlb_count_sub(folio_nr_pages(folio), mm);
-                               set_huge_pte_at(mm, address, pvmw.pte, pteval);
+                               set_huge_pte_at(mm, address, pvmw.pte, pteval,
+                                               hsz);
                        } else {
                                dec_mm_counter(mm, mm_counter(&folio->page));
                                set_pte_at(mm, address, pvmw.pte, pteval);
@@ -2044,7 +2054,8 @@ static bool try_to_migrate_one(struct folio *folio, struct vm_area_struct *vma,
 
                        if (arch_unmap_one(mm, vma, address, pteval) < 0) {
                                if (folio_test_hugetlb(folio))
-                                       set_huge_pte_at(mm, address, pvmw.pte, pteval);
+                                       set_huge_pte_at(mm, address, pvmw.pte,
+                                                       pteval, hsz);
                                else
                                        set_pte_at(mm, address, pvmw.pte, pteval);
                                ret = false;
@@ -2058,7 +2069,8 @@ static bool try_to_migrate_one(struct folio *folio, struct vm_area_struct *vma,
                        if (anon_exclusive &&
                            page_try_share_anon_rmap(subpage)) {
                                if (folio_test_hugetlb(folio))
-                                       set_huge_pte_at(mm, address, pvmw.pte, pteval);
+                                       set_huge_pte_at(mm, address, pvmw.pte,
+                                                       pteval, hsz);
                                else
                                        set_pte_at(mm, address, pvmw.pte, pteval);
                                ret = false;
@@ -2090,7 +2102,8 @@ static bool try_to_migrate_one(struct folio *folio, struct vm_area_struct *vma,
                        if (pte_uffd_wp(pteval))
                                swp_pte = pte_swp_mkuffd_wp(swp_pte);
                        if (folio_test_hugetlb(folio))
-                               set_huge_pte_at(mm, address, pvmw.pte, swp_pte);
+                               set_huge_pte_at(mm, address, pvmw.pte, swp_pte,
+                                               hsz);
                        else
                                set_pte_at(mm, address, pvmw.pte, swp_pte);
                        trace_set_migration_pte(address, pte_val(swp_pte),
index 02e62fc..69595d3 100644 (file)
@@ -4586,7 +4586,7 @@ static struct file_system_type shmem_fs_type = {
 #endif
        .kill_sb        = kill_litter_super,
 #ifdef CONFIG_SHMEM
-       .fs_flags       = FS_USERNS_MOUNT | FS_ALLOW_IDMAP | FS_MGTIME,
+       .fs_flags       = FS_USERNS_MOUNT | FS_ALLOW_IDMAP,
 #else
        .fs_flags       = FS_USERNS_MOUNT,
 #endif
index cd71f95..8fda308 100644 (file)
@@ -479,7 +479,7 @@ void slab_kmem_cache_release(struct kmem_cache *s)
 
 void kmem_cache_destroy(struct kmem_cache *s)
 {
-       int refcnt;
+       int err = -EBUSY;
        bool rcu_set;
 
        if (unlikely(!s) || !kasan_check_byte(s))
@@ -490,17 +490,17 @@ void kmem_cache_destroy(struct kmem_cache *s)
 
        rcu_set = s->flags & SLAB_TYPESAFE_BY_RCU;
 
-       refcnt = --s->refcount;
-       if (refcnt)
+       s->refcount--;
+       if (s->refcount)
                goto out_unlock;
 
-       WARN(shutdown_cache(s),
-            "%s %s: Slab cache still has objects when called from %pS",
+       err = shutdown_cache(s);
+       WARN(err, "%s %s: Slab cache still has objects when called from %pS",
             __func__, s->name, (void *)_RET_IP_);
 out_unlock:
        mutex_unlock(&slab_mutex);
        cpus_read_unlock();
-       if (!refcnt && !rcu_set)
+       if (!err && !rcu_set)
                kmem_cache_release(s);
 }
 EXPORT_SYMBOL(kmem_cache_destroy);
@@ -745,24 +745,24 @@ struct kmem_cache *kmalloc_slab(size_t size, gfp_t flags, unsigned long caller)
 
 size_t kmalloc_size_roundup(size_t size)
 {
-       struct kmem_cache *c;
+       if (size && size <= KMALLOC_MAX_CACHE_SIZE) {
+               /*
+                * The flags don't matter since size_index is common to all.
+                * Neither does the caller for just getting ->object_size.
+                */
+               return kmalloc_slab(size, GFP_KERNEL, 0)->object_size;
+       }
 
-       /* Short-circuit the 0 size case. */
-       if (unlikely(size == 0))
-               return 0;
-       /* Short-circuit saturated "too-large" case. */
-       if (unlikely(size == SIZE_MAX))
-               return SIZE_MAX;
        /* Above the smaller buckets, size is a multiple of page size. */
-       if (size > KMALLOC_MAX_CACHE_SIZE)
+       if (size && size <= KMALLOC_MAX_SIZE)
                return PAGE_SIZE << get_order(size);
 
        /*
-        * The flags don't matter since size_index is common to all.
-        * Neither does the caller for just getting ->object_size.
+        * Return 'size' for 0 - kmalloc() returns ZERO_SIZE_PTR
+        * and very large size - kmalloc() may fail.
         */
-       c = kmalloc_slab(size, GFP_KERNEL, 0);
-       return c ? c->object_size : 0;
+       return size;
+
 }
 EXPORT_SYMBOL(kmalloc_size_roundup);
 
index ef8599d..a3fedb3 100644 (file)
@@ -111,7 +111,7 @@ static int vmap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
                        pte_t entry = pfn_pte(pfn, prot);
 
                        entry = arch_make_huge_pte(entry, ilog2(size), 0);
-                       set_huge_pte_at(&init_mm, addr, pte, entry);
+                       set_huge_pte_at(&init_mm, addr, pte, entry, size);
                        pfn += PFN_DOWN(size);
                        continue;
                }
index 412b140..083c693 100644 (file)
@@ -1219,6 +1219,19 @@ bool zswap_store(struct folio *folio)
                return false;
 
        /*
+        * If this is a duplicate, it must be removed before attempting to store
+        * it, otherwise, if the store fails the old page won't be removed from
+        * the tree, and it might be written back overriding the new data.
+        */
+       spin_lock(&tree->lock);
+       dupentry = zswap_rb_search(&tree->rbroot, offset);
+       if (dupentry) {
+               zswap_duplicate_entry++;
+               zswap_invalidate_entry(tree, dupentry);
+       }
+       spin_unlock(&tree->lock);
+
+       /*
         * XXX: zswap reclaim does not work with cgroups yet. Without a
         * cgroup-aware entry LRU, we will push out entries system-wide based on
         * local cgroup limits.
@@ -1333,7 +1346,14 @@ insert_entry:
 
        /* map */
        spin_lock(&tree->lock);
+       /*
+        * A duplicate entry should have been removed at the beginning of this
+        * function. Since the swap entry should be pinned, if a duplicate is
+        * found again here it means that something went wrong in the swap
+        * cache.
+        */
        while (zswap_rb_insert(&tree->rbroot, entry, &dupentry) == -EEXIST) {
+               WARN_ON(1);
                zswap_duplicate_entry++;
                zswap_invalidate_entry(tree, dupentry);
        }
index d3a9843..fdb6666 100644 (file)
@@ -10,7 +10,7 @@ menuconfig HAMRADIO
          If you want to connect your Linux box to an amateur radio, answer Y
          here. You want to read <https://www.tapr.org/>
          and more specifically about AX.25 on Linux
-         <http://www.linux-ax25.org/>.
+         <https://linux-ax25.in-berlin.de>.
 
          Note that the answer to this question won't directly affect the
          kernel: saying N will just cause the configurator to skip all
@@ -61,7 +61,7 @@ config AX25_DAMA_SLAVE
          configuration. Linux cannot yet act as a DAMA server.  This option
          only compiles DAMA slave support into the kernel.  It still needs to
          be enabled at runtime.  For more about DAMA see
-         <http://www.linux-ax25.org>.  If unsure, say Y.
+         <https://linux-ax25.in-berlin.de>.  If unsure, say Y.
 
 # placeholder until implemented
 config AX25_DAMA_MASTER
@@ -87,9 +87,9 @@ config NETROM
          A comprehensive listing of all the software for Linux amateur radio
          users as well as information about how to configure an AX.25 port is
          contained in the Linux Ham Wiki, available from
-         <http://www.linux-ax25.org>. You also might want to check out the
-         file <file:Documentation/networking/ax25.rst>. More information about
-         digital amateur radio in general is on the WWW at
+         <https://linux-ax25.in-berlin.de>. You also might want to check out
+         the file <file:Documentation/networking/ax25.rst>. More information
+         about digital amateur radio in general is on the WWW at
          <https://www.tapr.org/>.
 
          To compile this driver as a module, choose M here: the
@@ -106,9 +106,9 @@ config ROSE
          A comprehensive listing of all the software for Linux amateur radio
          users as well as information about how to configure an AX.25 port is
          contained in the Linux Ham Wiki, available from
-         <http://www.linux-ax25.org>.  You also might want to check out the
-         file <file:Documentation/networking/ax25.rst>. More information about
-         digital amateur radio in general is on the WWW at
+         <https://linux-ax25.in-berlin.de>.  You also might want to check out
+         the file <file:Documentation/networking/ax25.rst>. More information
+         about digital amateur radio in general is on the WWW at
          <https://www.tapr.org/>.
 
          To compile this driver as a module, choose M here: the
index 9d5057c..7a6f203 100644 (file)
@@ -2413,34 +2413,41 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type,
        if (!test_bit(HCI_CONN_AUTH, &conn->flags))
                goto auth;
 
-       /* An authenticated FIPS approved combination key has sufficient
-        * security for security level 4. */
-       if (conn->key_type == HCI_LK_AUTH_COMBINATION_P256 &&
-           sec_level == BT_SECURITY_FIPS)
-               goto encrypt;
-
-       /* An authenticated combination key has sufficient security for
-          security level 3. */
-       if ((conn->key_type == HCI_LK_AUTH_COMBINATION_P192 ||
-            conn->key_type == HCI_LK_AUTH_COMBINATION_P256) &&
-           sec_level == BT_SECURITY_HIGH)
-               goto encrypt;
-
-       /* An unauthenticated combination key has sufficient security for
-          security level 1 and 2. */
-       if ((conn->key_type == HCI_LK_UNAUTH_COMBINATION_P192 ||
-            conn->key_type == HCI_LK_UNAUTH_COMBINATION_P256) &&
-           (sec_level == BT_SECURITY_MEDIUM || sec_level == BT_SECURITY_LOW))
-               goto encrypt;
-
-       /* A combination key has always sufficient security for the security
-          levels 1 or 2. High security level requires the combination key
-          is generated using maximum PIN code length (16).
-          For pre 2.1 units. */
-       if (conn->key_type == HCI_LK_COMBINATION &&
-           (sec_level == BT_SECURITY_MEDIUM || sec_level == BT_SECURITY_LOW ||
-            conn->pin_length == 16))
-               goto encrypt;
+       switch (conn->key_type) {
+       case HCI_LK_AUTH_COMBINATION_P256:
+               /* An authenticated FIPS approved combination key has
+                * sufficient security for security level 4 or lower.
+                */
+               if (sec_level <= BT_SECURITY_FIPS)
+                       goto encrypt;
+               break;
+       case HCI_LK_AUTH_COMBINATION_P192:
+               /* An authenticated combination key has sufficient security for
+                * security level 3 or lower.
+                */
+               if (sec_level <= BT_SECURITY_HIGH)
+                       goto encrypt;
+               break;
+       case HCI_LK_UNAUTH_COMBINATION_P192:
+       case HCI_LK_UNAUTH_COMBINATION_P256:
+               /* An unauthenticated combination key has sufficient security
+                * for security level 2 or lower.
+                */
+               if (sec_level <= BT_SECURITY_MEDIUM)
+                       goto encrypt;
+               break;
+       case HCI_LK_COMBINATION:
+               /* A combination key has always sufficient security for the
+                * security levels 2 or lower. High security level requires the
+                * combination key is generated using maximum PIN code length
+                * (16). For pre 2.1 units.
+                */
+               if (sec_level <= BT_SECURITY_MEDIUM || conn->pin_length == 16)
+                       goto encrypt;
+               break;
+       default:
+               break;
+       }
 
 auth:
        if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags))
index a5992f1..195aea2 100644 (file)
@@ -2617,7 +2617,11 @@ int hci_register_dev(struct hci_dev *hdev)
        if (id < 0)
                return id;
 
-       snprintf(hdev->name, sizeof(hdev->name), "hci%d", id);
+       error = dev_set_name(&hdev->dev, "hci%u", id);
+       if (error)
+               return error;
+
+       hdev->name = dev_name(&hdev->dev);
        hdev->id = id;
 
        BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
@@ -2639,8 +2643,6 @@ int hci_register_dev(struct hci_dev *hdev)
        if (!IS_ERR_OR_NULL(bt_debugfs))
                hdev->debugfs = debugfs_create_dir(hdev->name, bt_debugfs);
 
-       dev_set_name(&hdev->dev, "%s", hdev->name);
-
        error = device_add(&hdev->dev);
        if (error < 0)
                goto err_wqueue;
@@ -2784,6 +2786,7 @@ void hci_release_dev(struct hci_dev *hdev)
        hci_conn_params_clear_all(hdev);
        hci_discovery_filter_clear(hdev);
        hci_blocked_keys_clear(hdev);
+       hci_codec_list_clear(&hdev->local_codecs);
        hci_dev_unlock(hdev);
 
        ida_simple_remove(&hci_index_ida, hdev->id);
@@ -3418,7 +3421,12 @@ static void hci_link_tx_to(struct hci_dev *hdev, __u8 type)
                if (c->type == type && c->sent) {
                        bt_dev_err(hdev, "killing stalled connection %pMR",
                                   &c->dst);
+                       /* hci_disconnect might sleep, so, we have to release
+                        * the RCU read lock before calling it.
+                        */
+                       rcu_read_unlock();
                        hci_disconnect(c, HCI_ERROR_REMOTE_USER_TERM);
+                       rcu_read_lock();
                }
        }
 
index 35f2510..31d02b5 100644 (file)
@@ -33,6 +33,7 @@
 
 #include "hci_request.h"
 #include "hci_debugfs.h"
+#include "hci_codec.h"
 #include "a2mp.h"
 #include "amp.h"
 #include "smp.h"
index b9c5a98..0be75cf 100644 (file)
@@ -71,7 +71,5 @@ struct sk_buff *hci_prepare_cmd(struct hci_dev *hdev, u16 opcode, u32 plen,
 void hci_req_add_le_scan_disable(struct hci_request *req, bool rpa_le_conn);
 void hci_req_add_le_passive_scan(struct hci_request *req);
 
-void hci_req_prepare_suspend(struct hci_dev *hdev, enum suspended_state next);
-
 void hci_request_setup(struct hci_dev *hdev);
 void hci_request_cancel_all(struct hci_dev *hdev);
index 9b93653..d06e07a 100644 (file)
@@ -413,11 +413,6 @@ static int hci_le_scan_restart_sync(struct hci_dev *hdev)
                                           LE_SCAN_FILTER_DUP_ENABLE);
 }
 
-static int le_scan_restart_sync(struct hci_dev *hdev, void *data)
-{
-       return hci_le_scan_restart_sync(hdev);
-}
-
 static void le_scan_restart(struct work_struct *work)
 {
        struct hci_dev *hdev = container_of(work, struct hci_dev,
@@ -427,15 +422,15 @@ static void le_scan_restart(struct work_struct *work)
 
        bt_dev_dbg(hdev, "");
 
-       hci_dev_lock(hdev);
-
-       status = hci_cmd_sync_queue(hdev, le_scan_restart_sync, NULL, NULL);
+       status = hci_le_scan_restart_sync(hdev);
        if (status) {
                bt_dev_err(hdev, "failed to restart LE scan: status %d",
                           status);
-               goto unlock;
+               return;
        }
 
+       hci_dev_lock(hdev);
+
        if (!test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks) ||
            !hdev->discovery.scan_start)
                goto unlock;
@@ -5079,6 +5074,7 @@ int hci_dev_close_sync(struct hci_dev *hdev)
        memset(hdev->eir, 0, sizeof(hdev->eir));
        memset(hdev->dev_class, 0, sizeof(hdev->dev_class));
        bacpy(&hdev->random_addr, BDADDR_ANY);
+       hci_codec_list_clear(&hdev->local_codecs);
 
        hci_dev_put(hdev);
        return err;
index 16da946..7124816 100644 (file)
@@ -502,7 +502,7 @@ drop:
 }
 
 /* -------- Socket interface ---------- */
-static struct sock *__iso_get_sock_listen_by_addr(bdaddr_t *ba)
+static struct sock *__iso_get_sock_listen_by_addr(bdaddr_t *src, bdaddr_t *dst)
 {
        struct sock *sk;
 
@@ -510,7 +510,10 @@ static struct sock *__iso_get_sock_listen_by_addr(bdaddr_t *ba)
                if (sk->sk_state != BT_LISTEN)
                        continue;
 
-               if (!bacmp(&iso_pi(sk)->src, ba))
+               if (bacmp(&iso_pi(sk)->dst, dst))
+                       continue;
+
+               if (!bacmp(&iso_pi(sk)->src, src))
                        return sk;
        }
 
@@ -952,7 +955,7 @@ static int iso_listen_cis(struct sock *sk)
 
        write_lock(&iso_sk_list.lock);
 
-       if (__iso_get_sock_listen_by_addr(&iso_pi(sk)->src))
+       if (__iso_get_sock_listen_by_addr(&iso_pi(sk)->src, &iso_pi(sk)->dst))
                err = -EADDRINUSE;
 
        write_unlock(&iso_sk_list.lock);
index 9d7bc8b..7431f89 100644 (file)
@@ -124,7 +124,7 @@ static int deliver_clone(const struct net_bridge_port *prev,
 
        skb = skb_clone(skb, GFP_ATOMIC);
        if (!skb) {
-               dev->stats.tx_dropped++;
+               DEV_STATS_INC(dev, tx_dropped);
                return -ENOMEM;
        }
 
@@ -268,7 +268,7 @@ static void maybe_deliver_addr(struct net_bridge_port *p, struct sk_buff *skb,
 
        skb = skb_copy(skb, GFP_ATOMIC);
        if (!skb) {
-               dev->stats.tx_dropped++;
+               DEV_STATS_INC(dev, tx_dropped);
                return;
        }
 
index c34a0b0..c729528 100644 (file)
@@ -181,12 +181,12 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
                        if ((mdst && mdst->host_joined) ||
                            br_multicast_is_router(brmctx, skb)) {
                                local_rcv = true;
-                               br->dev->stats.multicast++;
+                               DEV_STATS_INC(br->dev, multicast);
                        }
                        mcast_hit = true;
                } else {
                        local_rcv = true;
-                       br->dev->stats.multicast++;
+                       DEV_STATS_INC(br->dev, multicast);
                }
                break;
        case BR_PKT_UNICAST:
index 1518624..033034d 100644 (file)
@@ -294,7 +294,7 @@ int br_nf_pre_routing_finish_bridge(struct net *net, struct sock *sk, struct sk_
                        /* tell br_dev_xmit to continue with forwarding */
                        nf_bridge->bridged_dnat = 1;
                        /* FIXME Need to refragment */
-                       ret = neigh->output(neigh, skb);
+                       ret = READ_ONCE(neigh->output)(neigh, skb);
                }
                neigh_release(neigh);
                return ret;
index ccff2b6..85df22f 100644 (file)
@@ -69,7 +69,7 @@
  */
 
 #include <linux/uaccess.h>
-#include <linux/bitops.h>
+#include <linux/bitmap.h>
 #include <linux/capability.h>
 #include <linux/cpu.h>
 #include <linux/types.h>
@@ -1080,7 +1080,7 @@ static int __dev_alloc_name(struct net *net, const char *name, char *buf)
                        return -EINVAL;
 
                /* Use one page as a bit array of possible slots */
-               inuse = (unsigned long *) get_zeroed_page(GFP_ATOMIC);
+               inuse = bitmap_zalloc(max_netdevices, GFP_ATOMIC);
                if (!inuse)
                        return -ENOMEM;
 
@@ -1109,7 +1109,7 @@ static int __dev_alloc_name(struct net *net, const char *name, char *buf)
                }
 
                i = find_first_zero_bit(inuse, max_netdevices);
-               free_page((unsigned long) inuse);
+               bitmap_free(inuse);
        }
 
        snprintf(buf, IFNAMSIZ, name, i);
index b3b3af0..272f092 100644 (file)
@@ -1446,7 +1446,7 @@ proto_again:
                        break;
                }
 
-               nhoff += ntohs(hdr->message_length);
+               nhoff += sizeof(struct ptp_header);
                fdret = FLOW_DISSECT_RET_OUT_GOOD;
                break;
        }
index 6b76cd1..9c09f09 100644 (file)
@@ -410,7 +410,7 @@ static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev,
                                 */
                                __skb_queue_purge(&n->arp_queue);
                                n->arp_queue_len_bytes = 0;
-                               n->output = neigh_blackhole;
+                               WRITE_ONCE(n->output, neigh_blackhole);
                                if (n->nud_state & NUD_VALID)
                                        n->nud_state = NUD_NOARP;
                                else
@@ -920,7 +920,7 @@ static void neigh_suspect(struct neighbour *neigh)
 {
        neigh_dbg(2, "neigh %p is suspected\n", neigh);
 
-       neigh->output = neigh->ops->output;
+       WRITE_ONCE(neigh->output, neigh->ops->output);
 }
 
 /* Neighbour state is OK;
@@ -932,7 +932,7 @@ static void neigh_connect(struct neighbour *neigh)
 {
        neigh_dbg(2, "neigh %p is connected\n", neigh);
 
-       neigh->output = neigh->ops->connected_output;
+       WRITE_ONCE(neigh->output, neigh->ops->connected_output);
 }
 
 static void neigh_periodic_work(struct work_struct *work)
@@ -988,7 +988,9 @@ static void neigh_periodic_work(struct work_struct *work)
                            (state == NUD_FAILED ||
                             !time_in_range_open(jiffies, n->used,
                                                 n->used + NEIGH_VAR(n->parms, GC_STALETIME)))) {
-                               *np = n->next;
+                               rcu_assign_pointer(*np,
+                                       rcu_dereference_protected(n->next,
+                                               lockdep_is_held(&tbl->lock)));
                                neigh_mark_dead(n);
                                write_unlock(&n->lock);
                                neigh_cleanup_and_release(n);
@@ -1447,7 +1449,7 @@ static int __neigh_update(struct neighbour *neigh, const u8 *lladdr,
                                if (n2)
                                        n1 = n2;
                        }
-                       n1->output(n1, skb);
+                       READ_ONCE(n1->output)(n1, skb);
                        if (n2)
                                neigh_release(n2);
                        rcu_read_unlock();
@@ -3153,7 +3155,7 @@ int neigh_xmit(int index, struct net_device *dev,
                        rcu_read_unlock();
                        goto out_kfree_skb;
                }
-               err = neigh->output(neigh, skb);
+               err = READ_ONCE(neigh->output)(neigh, skb);
                rcu_read_unlock();
        }
        else if (index == NEIGH_LINK_TABLE) {
index cb11750..4292c2e 100644 (file)
@@ -668,6 +668,8 @@ BPF_CALL_4(bpf_msg_redirect_map, struct sk_msg *, msg,
        sk = __sock_map_lookup_elem(map, key);
        if (unlikely(!sk || !sock_map_redirect_allowed(sk)))
                return SK_DROP;
+       if (!(flags & BPF_F_INGRESS) && !sk_is_tcp(sk))
+               return SK_DROP;
 
        msg->flags = flags;
        msg->sk_redir = sk;
@@ -1267,6 +1269,8 @@ BPF_CALL_4(bpf_msg_redirect_hash, struct sk_msg *, msg,
        sk = __sock_hash_lookup_elem(map, key);
        if (unlikely(!sk || !sock_map_redirect_allowed(sk)))
                return SK_DROP;
+       if (!(flags & BPF_F_INGRESS) && !sk_is_tcp(sk))
+               return SK_DROP;
 
        msg->flags = flags;
        msg->sk_redir = sk;
index 8f56e87..69453b9 100644 (file)
@@ -254,13 +254,8 @@ static int dccp_v4_err(struct sk_buff *skb, u32 info)
        int err;
        struct net *net = dev_net(skb->dev);
 
-       /* For the first __dccp_basic_hdr_len() check, we only need dh->dccph_x,
-        * which is in byte 7 of the dccp header.
-        * Our caller (icmp_socket_deliver()) already pulled 8 bytes for us.
-        *
-        * Later on, we want to access the sequence number fields, which are
-        * beyond 8 bytes, so we have to pskb_may_pull() ourselves.
-        */
+       if (!pskb_may_pull(skb, offset + sizeof(*dh)))
+               return -EINVAL;
        dh = (struct dccp_hdr *)(skb->data + offset);
        if (!pskb_may_pull(skb, offset + __dccp_basic_hdr_len(dh)))
                return -EINVAL;
index 33f6ccf..c693a57 100644 (file)
@@ -83,13 +83,8 @@ static int dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
        __u64 seq;
        struct net *net = dev_net(skb->dev);
 
-       /* For the first __dccp_basic_hdr_len() check, we only need dh->dccph_x,
-        * which is in byte 7 of the dccp header.
-        * Our caller (icmpv6_notify()) already pulled 8 bytes for us.
-        *
-        * Later on, we want to access the sequence number fields, which are
-        * beyond 8 bytes, so we have to pskb_may_pull() ourselves.
-        */
+       if (!pskb_may_pull(skb, offset + sizeof(*dh)))
+               return -EINVAL;
        dh = (struct dccp_hdr *)(skb->data + offset);
        if (!pskb_may_pull(skb, offset + __dccp_basic_hdr_len(dh)))
                return -EINVAL;
index b238a1a..b1e2e3b 100644 (file)
@@ -21,16 +21,6 @@ struct plca_reply_data {
 #define PLCA_REPDATA(__reply_base) \
        container_of(__reply_base, struct plca_reply_data, base)
 
-static void plca_update_sint(int *dst, const struct nlattr *attr,
-                            bool *mod)
-{
-       if (!attr)
-               return;
-
-       *dst = nla_get_u32(attr);
-       *mod = true;
-}
-
 // PLCA get configuration message ------------------------------------------- //
 
 const struct nla_policy ethnl_plca_get_cfg_policy[] = {
@@ -38,6 +28,29 @@ const struct nla_policy ethnl_plca_get_cfg_policy[] = {
                NLA_POLICY_NESTED(ethnl_header_policy),
 };
 
+static void plca_update_sint(int *dst, struct nlattr **tb, u32 attrid,
+                            bool *mod)
+{
+       const struct nlattr *attr = tb[attrid];
+
+       if (!attr ||
+           WARN_ON_ONCE(attrid >= ARRAY_SIZE(ethnl_plca_set_cfg_policy)))
+               return;
+
+       switch (ethnl_plca_set_cfg_policy[attrid].type) {
+       case NLA_U8:
+               *dst = nla_get_u8(attr);
+               break;
+       case NLA_U32:
+               *dst = nla_get_u32(attr);
+               break;
+       default:
+               WARN_ON_ONCE(1);
+       }
+
+       *mod = true;
+}
+
 static int plca_get_cfg_prepare_data(const struct ethnl_req_info *req_base,
                                     struct ethnl_reply_data *reply_base,
                                     const struct genl_info *info)
@@ -144,13 +157,13 @@ ethnl_set_plca(struct ethnl_req_info *req_info, struct genl_info *info)
                return -EOPNOTSUPP;
 
        memset(&plca_cfg, 0xff, sizeof(plca_cfg));
-       plca_update_sint(&plca_cfg.enabled, tb[ETHTOOL_A_PLCA_ENABLED], &mod);
-       plca_update_sint(&plca_cfg.node_id, tb[ETHTOOL_A_PLCA_NODE_ID], &mod);
-       plca_update_sint(&plca_cfg.node_cnt, tb[ETHTOOL_A_PLCA_NODE_CNT], &mod);
-       plca_update_sint(&plca_cfg.to_tmr, tb[ETHTOOL_A_PLCA_TO_TMR], &mod);
-       plca_update_sint(&plca_cfg.burst_cnt, tb[ETHTOOL_A_PLCA_BURST_CNT],
+       plca_update_sint(&plca_cfg.enabled, tb, ETHTOOL_A_PLCA_ENABLED, &mod);
+       plca_update_sint(&plca_cfg.node_id, tb, ETHTOOL_A_PLCA_NODE_ID, &mod);
+       plca_update_sint(&plca_cfg.node_cnt, tb, ETHTOOL_A_PLCA_NODE_CNT, &mod);
+       plca_update_sint(&plca_cfg.to_tmr, tb, ETHTOOL_A_PLCA_TO_TMR, &mod);
+       plca_update_sint(&plca_cfg.burst_cnt, tb, ETHTOOL_A_PLCA_BURST_CNT,
                         &mod);
-       plca_update_sint(&plca_cfg.burst_tmr, tb[ETHTOOL_A_PLCA_BURST_TMR],
+       plca_update_sint(&plca_cfg.burst_tmr, tb, ETHTOOL_A_PLCA_BURST_TMR,
                         &mod);
        if (!mod)
                return 0;
index 6d37bab..16ed7bf 100644 (file)
@@ -235,7 +235,7 @@ static void handshake_req_submit_test4(struct kunit *test)
        KUNIT_EXPECT_PTR_EQ(test, req, result);
 
        handshake_req_cancel(sock->sk);
-       sock_release(sock);
+       fput(filp);
 }
 
 static void handshake_req_submit_test5(struct kunit *test)
@@ -272,7 +272,7 @@ static void handshake_req_submit_test5(struct kunit *test)
        /* Assert */
        KUNIT_EXPECT_EQ(test, err, -EAGAIN);
 
-       sock_release(sock);
+       fput(filp);
        hn->hn_pending = saved;
 }
 
@@ -306,7 +306,7 @@ static void handshake_req_submit_test6(struct kunit *test)
        KUNIT_EXPECT_EQ(test, err, -EBUSY);
 
        handshake_req_cancel(sock->sk);
-       sock_release(sock);
+       fput(filp);
 }
 
 static void handshake_req_cancel_test1(struct kunit *test)
@@ -340,7 +340,7 @@ static void handshake_req_cancel_test1(struct kunit *test)
        /* Assert */
        KUNIT_EXPECT_TRUE(test, result);
 
-       sock_release(sock);
+       fput(filp);
 }
 
 static void handshake_req_cancel_test2(struct kunit *test)
@@ -382,7 +382,7 @@ static void handshake_req_cancel_test2(struct kunit *test)
        /* Assert */
        KUNIT_EXPECT_TRUE(test, result);
 
-       sock_release(sock);
+       fput(filp);
 }
 
 static void handshake_req_cancel_test3(struct kunit *test)
@@ -427,7 +427,7 @@ static void handshake_req_cancel_test3(struct kunit *test)
        /* Assert */
        KUNIT_EXPECT_FALSE(test, result);
 
-       sock_release(sock);
+       fput(filp);
 }
 
 static struct handshake_req *handshake_req_destroy_test;
@@ -471,7 +471,7 @@ static void handshake_req_destroy_test1(struct kunit *test)
        handshake_req_cancel(sock->sk);
 
        /* Act */
-       sock_release(sock);
+       fput(filp);
 
        /* Assert */
        KUNIT_EXPECT_PTR_EQ(test, handshake_req_destroy_test, req);
index b77f118..6d14d93 100644 (file)
@@ -288,13 +288,13 @@ void hsr_handle_sup_frame(struct hsr_frame_info *frame)
 
        /* And leave the HSR tag. */
        if (ethhdr->h_proto == htons(ETH_P_HSR)) {
-               pull_size = sizeof(struct ethhdr);
+               pull_size = sizeof(struct hsr_tag);
                skb_pull(skb, pull_size);
                total_pull_size += pull_size;
        }
 
        /* And leave the HSR sup tag. */
-       pull_size = sizeof(struct hsr_tag);
+       pull_size = sizeof(struct hsr_sup_tag);
        skb_pull(skb, pull_size);
        total_pull_size += pull_size;
 
index 6851e33..18e0179 100644 (file)
@@ -83,7 +83,7 @@ struct hsr_vlan_ethhdr {
 struct hsr_sup_tlv {
        u8              HSR_TLV_type;
        u8              HSR_TLV_length;
-};
+} __packed;
 
 /* HSR/PRP Supervision Frame data types.
  * Field names as defined in the IEC:2010 standard for HSR.
index eafa4a0..1ea82bc 100644 (file)
@@ -1887,6 +1887,7 @@ int fib_sync_down_addr(struct net_device *dev, __be32 local)
                        continue;
                if (fi->fib_prefsrc == local) {
                        fi->fib_flags |= RTNH_F_DEAD;
+                       fi->pfsrc_removed = true;
                        ret++;
                }
        }
index d13fb9e..9bdfdab 100644 (file)
@@ -2027,6 +2027,7 @@ void fib_table_flush_external(struct fib_table *tb)
 int fib_table_flush(struct net *net, struct fib_table *tb, bool flush_all)
 {
        struct trie *t = (struct trie *)tb->tb_data;
+       struct nl_info info = { .nl_net = net };
        struct key_vector *pn = t->kv;
        unsigned long cindex = 1;
        struct hlist_node *tmp;
@@ -2089,6 +2090,9 @@ int fib_table_flush(struct net *net, struct fib_table *tb, bool flush_all)
 
                        fib_notify_alias_delete(net, n->key, &n->leaf, fa,
                                                NULL);
+                       if (fi->pfsrc_removed)
+                               rtmsg_fib(RTM_DELROUTE, htonl(n->key), fa,
+                                         KEYLENGTH - fa->fa_slen, tb->tb_id, &info, 0);
                        hlist_del_rcu(&fa->fa_list);
                        fib_release_info(fa->fa_info);
                        alias_free_mem_rcu(fa);
index 66f419e..b214b5a 100644 (file)
@@ -1213,6 +1213,7 @@ EXPORT_INDIRECT_CALLABLE(ipv4_dst_check);
 
 static void ipv4_send_dest_unreach(struct sk_buff *skb)
 {
+       struct net_device *dev;
        struct ip_options opt;
        int res;
 
@@ -1230,7 +1231,8 @@ static void ipv4_send_dest_unreach(struct sk_buff *skb)
                opt.optlen = ip_hdr(skb)->ihl * 4 - sizeof(struct iphdr);
 
                rcu_read_lock();
-               res = __ip_options_compile(dev_net(skb->dev), &opt, skb, NULL);
+               dev = skb->dev ? skb->dev : skb_rtable(skb)->dst.dev;
+               res = __ip_options_compile(dev_net(dev), &opt, skb, NULL);
                rcu_read_unlock();
 
                if (res)
@@ -3415,6 +3417,8 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
                                    fa->fa_type == fri.type) {
                                        fri.offload = READ_ONCE(fa->offload);
                                        fri.trap = READ_ONCE(fa->trap);
+                                       fri.offload_failed =
+                                               READ_ONCE(fa->offload_failed);
                                        break;
                                }
                        }
index 0c3040a..3f66cde 100644 (file)
@@ -1621,16 +1621,13 @@ EXPORT_SYMBOL(tcp_read_sock);
 
 int tcp_read_skb(struct sock *sk, skb_read_actor_t recv_actor)
 {
-       struct tcp_sock *tp = tcp_sk(sk);
-       u32 seq = tp->copied_seq;
        struct sk_buff *skb;
        int copied = 0;
-       u32 offset;
 
        if (sk->sk_state == TCP_LISTEN)
                return -ENOTCONN;
 
-       while ((skb = tcp_recv_skb(sk, seq, &offset)) != NULL) {
+       while ((skb = skb_peek(&sk->sk_receive_queue)) != NULL) {
                u8 tcp_flags;
                int used;
 
@@ -1643,13 +1640,10 @@ int tcp_read_skb(struct sock *sk, skb_read_actor_t recv_actor)
                                copied = used;
                        break;
                }
-               seq += used;
                copied += used;
 
-               if (tcp_flags & TCPHDR_FIN) {
-                       ++seq;
+               if (tcp_flags & TCPHDR_FIN)
                        break;
-               }
        }
        return copied;
 }
index 81f0dff..3272682 100644 (file)
@@ -222,6 +222,7 @@ static int tcp_bpf_recvmsg_parser(struct sock *sk,
                                  int *addr_len)
 {
        struct tcp_sock *tcp = tcp_sk(sk);
+       int peek = flags & MSG_PEEK;
        u32 seq = tcp->copied_seq;
        struct sk_psock *psock;
        int copied = 0;
@@ -311,7 +312,8 @@ msg_bytes_ready:
                copied = -EAGAIN;
        }
 out:
-       WRITE_ONCE(tcp->copied_seq, seq);
+       if (!peek)
+               WRITE_ONCE(tcp->copied_seq, seq);
        tcp_rcv_space_adjust(sk);
        if (copied > 0)
                __tcp_cleanup_rbuf(sk, copied);
index 06fe1cf..8afb095 100644 (file)
@@ -253,6 +253,19 @@ static void tcp_measure_rcv_mss(struct sock *sk, const struct sk_buff *skb)
                if (unlikely(len > icsk->icsk_ack.rcv_mss +
                                   MAX_TCP_OPTION_SPACE))
                        tcp_gro_dev_warn(sk, skb, len);
+               /* If the skb has a len of exactly 1*MSS and has the PSH bit
+                * set then it is likely the end of an application write. So
+                * more data may not be arriving soon, and yet the data sender
+                * may be waiting for an ACK if cwnd-bound or using TX zero
+                * copy. So we set ICSK_ACK_PUSHED here so that
+                * tcp_cleanup_rbuf() will send an ACK immediately if the app
+                * reads all of the data and is not ping-pong. If len > MSS
+                * then this logic does not matter (and does not hurt) because
+                * tcp_cleanup_rbuf() will always ACK immediately if the app
+                * reads data and there is more than an MSS of unACKed data.
+                */
+               if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_PSH)
+                       icsk->icsk_ack.pending |= ICSK_ACK_PUSHED;
        } else {
                /* Otherwise, we make more careful check taking into account,
                 * that SACKs block is variable.
index ccfc8bb..aa0fc8c 100644 (file)
@@ -177,8 +177,7 @@ static void tcp_event_data_sent(struct tcp_sock *tp,
 }
 
 /* Account for an ACK we sent. */
-static inline void tcp_event_ack_sent(struct sock *sk, unsigned int pkts,
-                                     u32 rcv_nxt)
+static inline void tcp_event_ack_sent(struct sock *sk, u32 rcv_nxt)
 {
        struct tcp_sock *tp = tcp_sk(sk);
 
@@ -192,7 +191,7 @@ static inline void tcp_event_ack_sent(struct sock *sk, unsigned int pkts,
 
        if (unlikely(rcv_nxt != tp->rcv_nxt))
                return;  /* Special ACK sent by DCTCP to reflect ECN */
-       tcp_dec_quickack_mode(sk, pkts);
+       tcp_dec_quickack_mode(sk);
        inet_csk_clear_xmit_timer(sk, ICSK_TIME_DACK);
 }
 
@@ -1387,7 +1386,7 @@ static int __tcp_transmit_skb(struct sock *sk, struct sk_buff *skb,
                           sk, skb);
 
        if (likely(tcb->tcp_flags & TCPHDR_ACK))
-               tcp_event_ack_sent(sk, tcp_skb_pcount(skb), rcv_nxt);
+               tcp_event_ack_sent(sk, rcv_nxt);
 
        if (skb->len != tcp_header_size) {
                tcp_event_data_sent(tp, sk);
index 3a88545..44b6949 100644 (file)
@@ -1640,9 +1640,12 @@ process:
                struct sock *nsk;
 
                sk = req->rsk_listener;
-               drop_reason = tcp_inbound_md5_hash(sk, skb,
-                                                  &hdr->saddr, &hdr->daddr,
-                                                  AF_INET6, dif, sdif);
+               if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
+                       drop_reason = SKB_DROP_REASON_XFRM_POLICY;
+               else
+                       drop_reason = tcp_inbound_md5_hash(sk, skb,
+                                                          &hdr->saddr, &hdr->daddr,
+                                                          AF_INET6, dif, sdif);
                if (drop_reason) {
                        sk_drops_add(sk, skb);
                        reqsk_put(req);
@@ -1689,6 +1692,7 @@ process:
                        }
                        goto discard_and_relse;
                }
+               nf_reset_ct(skb);
                if (nsk == sk) {
                        reqsk_put(req);
                        tcp_v6_restore_cb(skb);
index ed8ebb6..11f3d37 100644 (file)
@@ -507,7 +507,6 @@ static int l2tp_ip6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
         */
        if (len > INT_MAX - transhdrlen)
                return -EMSGSIZE;
-       ulen = len + transhdrlen;
 
        /* Mirror BSD error message compatibility */
        if (msg->msg_flags & MSG_OOB)
@@ -628,6 +627,7 @@ static int l2tp_ip6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
 
 back_from_confirm:
        lock_sock(sk);
+       ulen = len + skb_queue_empty(&sk->sk_write_queue) ? transhdrlen : 0;
        err = ip6_append_data(sk, ip_generic_getfrag, msg,
                              ulen, transhdrlen, &ipc6,
                              &fl6, (struct rt6_info *)dst,
index 45e7a5d..0e3a175 100644 (file)
@@ -566,6 +566,9 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
        }
 
        err = ieee80211_key_link(key, link, sta);
+       /* KRACK protection, shouldn't happen but just silently accept key */
+       if (err == -EALREADY)
+               err = 0;
 
  out_unlock:
        mutex_unlock(&local->sta_mtx);
@@ -1857,7 +1860,8 @@ static int sta_link_apply_parameters(struct ieee80211_local *local,
        /* VHT can override some HT caps such as the A-MSDU max length */
        if (params->vht_capa)
                ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
-                                                   params->vht_capa, link_sta);
+                                                   params->vht_capa, NULL,
+                                                   link_sta);
 
        if (params->he_capa)
                ieee80211_he_cap_ie_to_sta_he_cap(sdata, sband,
index e190007..5542c93 100644 (file)
@@ -1072,7 +1072,7 @@ static void ieee80211_update_sta_info(struct ieee80211_sub_if_data *sdata,
                                                   &chandef);
                        memcpy(&cap_ie, elems->vht_cap_elem, sizeof(cap_ie));
                        ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
-                                                           &cap_ie,
+                                                           &cap_ie, NULL,
                                                            &sta->deflink);
                        if (memcmp(&cap, &sta->sta.deflink.vht_cap, sizeof(cap)))
                                rates_updated |= true;
index 06bd406..98ef1fe 100644 (file)
@@ -676,7 +676,7 @@ struct ieee80211_if_mesh {
        struct timer_list mesh_path_root_timer;
 
        unsigned long wrkq_flags;
-       unsigned long mbss_changed;
+       unsigned long mbss_changed[64 / BITS_PER_LONG];
 
        bool userspace_handles_dfs;
 
@@ -2141,6 +2141,7 @@ void
 ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
                                    struct ieee80211_supported_band *sband,
                                    const struct ieee80211_vht_cap *vht_cap_ie,
+                                   const struct ieee80211_vht_cap *vht_cap_ie2,
                                    struct link_sta_info *link_sta);
 enum ieee80211_sta_rx_bandwidth
 ieee80211_sta_cap_rx_bw(struct link_sta_info *link_sta);
index 13050dc..0665ff5 100644 (file)
@@ -802,6 +802,9 @@ static void ieee80211_key_destroy(struct ieee80211_key *key,
 
 void ieee80211_key_free_unused(struct ieee80211_key *key)
 {
+       if (!key)
+               return;
+
        WARN_ON(key->sdata || key->local);
        ieee80211_key_free_common(key);
 }
@@ -854,7 +857,7 @@ int ieee80211_key_link(struct ieee80211_key *key,
         * can cause warnings to appear.
         */
        bool delay_tailroom = sdata->vif.type == NL80211_IFTYPE_STATION;
-       int ret = -EOPNOTSUPP;
+       int ret;
 
        mutex_lock(&sdata->local->key_mtx);
 
@@ -868,8 +871,10 @@ int ieee80211_key_link(struct ieee80211_key *key,
                 * the same cipher. Enforce the assumption for pairwise keys.
                 */
                if ((alt_key && alt_key->conf.cipher != key->conf.cipher) ||
-                   (old_key && old_key->conf.cipher != key->conf.cipher))
+                   (old_key && old_key->conf.cipher != key->conf.cipher)) {
+                       ret = -EOPNOTSUPP;
                        goto out;
+               }
        } else if (sta) {
                struct link_sta_info *link_sta = &sta->deflink;
                int link_id = key->conf.link_id;
@@ -895,8 +900,10 @@ int ieee80211_key_link(struct ieee80211_key *key,
 
        /* Non-pairwise keys must also not switch the cipher on rekey */
        if (!pairwise) {
-               if (old_key && old_key->conf.cipher != key->conf.cipher)
+               if (old_key && old_key->conf.cipher != key->conf.cipher) {
+                       ret = -EOPNOTSUPP;
                        goto out;
+               }
        }
 
        /*
@@ -904,9 +911,8 @@ int ieee80211_key_link(struct ieee80211_key *key,
         * new version of the key to avoid nonce reuse or replay issues.
         */
        if (ieee80211_key_identical(sdata, old_key, key)) {
-               ieee80211_key_free_unused(key);
-               ret = 0;
-               goto out;
+               ret = -EALREADY;
+               goto unlock;
        }
 
        key->local = sdata->local;
@@ -930,7 +936,11 @@ int ieee80211_key_link(struct ieee80211_key *key,
                ieee80211_key_free(key, delay_tailroom);
        }
 
+       key = NULL;
+
  out:
+       ieee80211_key_free_unused(key);
+ unlock:
        mutex_unlock(&sdata->local->key_mtx);
 
        return ret;
index af8c5fc..e31c312 100644 (file)
@@ -1175,7 +1175,7 @@ void ieee80211_mbss_info_change_notify(struct ieee80211_sub_if_data *sdata,
 
        /* if we race with running work, worst case this work becomes a noop */
        for_each_set_bit(bit, &bits, sizeof(changed) * BITS_PER_BYTE)
-               set_bit(bit, &ifmsh->mbss_changed);
+               set_bit(bit, ifmsh->mbss_changed);
        set_bit(MESH_WORK_MBSS_CHANGED, &ifmsh->wrkq_flags);
        wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work);
 }
@@ -1257,7 +1257,7 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
 
        /* clear any mesh work (for next join) we may have accrued */
        ifmsh->wrkq_flags = 0;
-       ifmsh->mbss_changed = 0;
+       memset(ifmsh->mbss_changed, 0, sizeof(ifmsh->mbss_changed));
 
        local->fif_other_bss--;
        atomic_dec(&local->iff_allmultis);
@@ -1724,9 +1724,9 @@ static void mesh_bss_info_changed(struct ieee80211_sub_if_data *sdata)
        u32 bit;
        u64 changed = 0;
 
-       for_each_set_bit(bit, &ifmsh->mbss_changed,
+       for_each_set_bit(bit, ifmsh->mbss_changed,
                         sizeof(changed) * BITS_PER_BYTE) {
-               clear_bit(bit, &ifmsh->mbss_changed);
+               clear_bit(bit, ifmsh->mbss_changed);
                changed |= BIT(bit);
        }
 
index f3d5bb0..a1e5264 100644 (file)
@@ -451,7 +451,7 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata,
                changed |= IEEE80211_RC_BW_CHANGED;
 
        ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
-                                           elems->vht_cap_elem,
+                                           elems->vht_cap_elem, NULL,
                                            &sta->deflink);
 
        ieee80211_he_cap_ie_to_sta_he_cap(sdata, sband, elems->he_cap,
index f93eb38..0c91989 100644 (file)
@@ -4202,10 +4202,33 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link,
                                                  elems->ht_cap_elem,
                                                  link_sta);
 
-       if (elems->vht_cap_elem && !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT))
+       if (elems->vht_cap_elem &&
+           !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT)) {
+               const struct ieee80211_vht_cap *bss_vht_cap = NULL;
+               const struct cfg80211_bss_ies *ies;
+
+               /*
+                * Cisco AP module 9115 with FW 17.3 has a bug and sends a
+                * too large maximum MPDU length in the association response
+                * (indicating 12k) that it cannot actually process ...
+                * Work around that.
+                */
+               rcu_read_lock();
+               ies = rcu_dereference(cbss->ies);
+               if (ies) {
+                       const struct element *elem;
+
+                       elem = cfg80211_find_elem(WLAN_EID_VHT_CAPABILITY,
+                                                 ies->data, ies->len);
+                       if (elem && elem->datalen >= sizeof(*bss_vht_cap))
+                               bss_vht_cap = (const void *)elem->data;
+               }
+
                ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
                                                    elems->vht_cap_elem,
-                                                   link_sta);
+                                                   bss_vht_cap, link_sta);
+               rcu_read_unlock();
+       }
 
        if (elems->he_operation && !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE) &&
            elems->he_cap) {
@@ -5107,9 +5130,10 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
                                continue;
 
                        valid_links |= BIT(link_id);
-                       if (assoc_data->link[link_id].disabled) {
+                       if (assoc_data->link[link_id].disabled)
                                dormant_links |= BIT(link_id);
-                       } else if (link_id != assoc_data->assoc_link_id) {
+
+                       if (link_id != assoc_data->assoc_link_id) {
                                err = ieee80211_sta_allocate_link(sta, link_id);
                                if (err)
                                        goto out_err;
@@ -5124,7 +5148,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
                struct ieee80211_link_data *link;
                struct link_sta_info *link_sta;
 
-               if (!cbss || assoc_data->link[link_id].disabled)
+               if (!cbss)
                        continue;
 
                link = sdata_dereference(sdata->link[link_id], sdata);
@@ -5429,17 +5453,18 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
        for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) {
                struct ieee80211_link_data *link;
 
-               link = sdata_dereference(sdata->link[link_id], sdata);
-               if (!link)
-                       continue;
-
                if (!assoc_data->link[link_id].bss)
                        continue;
 
                resp.links[link_id].bss = assoc_data->link[link_id].bss;
-               resp.links[link_id].addr = link->conf->addr;
+               ether_addr_copy(resp.links[link_id].addr,
+                               assoc_data->link[link_id].addr);
                resp.links[link_id].status = assoc_data->link[link_id].status;
 
+               link = sdata_dereference(sdata->link[link_id], sdata);
+               if (!link)
+                       continue;
+
                /* get uapsd queues configuration - same for all links */
                resp.uapsd_queues = 0;
                for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
index 7fe7280..d45d4be 100644 (file)
@@ -665,7 +665,8 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
                }
 
                if (unlikely(tx->key && tx->key->flags & KEY_FLAG_TAINTED &&
-                            !ieee80211_is_deauth(hdr->frame_control)))
+                            !ieee80211_is_deauth(hdr->frame_control)) &&
+                            tx->skb->protocol != tx->sdata->control_port_protocol)
                        return TX_DROP;
 
                if (!skip_hw && tx->key &&
index c1250aa..b3a5c3e 100644 (file)
@@ -4,7 +4,7 @@
  *
  * Portions of this file
  * Copyright(c) 2015 - 2016 Intel Deutschland GmbH
- * Copyright (C) 2018 - 2022 Intel Corporation
+ * Copyright (C) 2018 - 2023 Intel Corporation
  */
 
 #include <linux/ieee80211.h>
@@ -116,12 +116,14 @@ void
 ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
                                    struct ieee80211_supported_band *sband,
                                    const struct ieee80211_vht_cap *vht_cap_ie,
+                                   const struct ieee80211_vht_cap *vht_cap_ie2,
                                    struct link_sta_info *link_sta)
 {
        struct ieee80211_sta_vht_cap *vht_cap = &link_sta->pub->vht_cap;
        struct ieee80211_sta_vht_cap own_cap;
        u32 cap_info, i;
        bool have_80mhz;
+       u32 mpdu_len;
 
        memset(vht_cap, 0, sizeof(*vht_cap));
 
@@ -318,10 +320,20 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
        link_sta->pub->bandwidth = ieee80211_sta_cur_vht_bw(link_sta);
 
        /*
+        * Work around the Cisco 9115 FW 17.3 bug by taking the min of
+        * both reported MPDU lengths.
+        */
+       mpdu_len = vht_cap->cap & IEEE80211_VHT_CAP_MAX_MPDU_MASK;
+       if (vht_cap_ie2)
+               mpdu_len = min_t(u32, mpdu_len,
+                                le32_get_bits(vht_cap_ie2->vht_cap_info,
+                                              IEEE80211_VHT_CAP_MAX_MPDU_MASK));
+
+       /*
         * FIXME - should the amsdu len be per link? store per link
         * and maintain a minimum?
         */
-       switch (vht_cap->cap & IEEE80211_VHT_CAP_MAX_MPDU_MASK) {
+       switch (mpdu_len) {
        case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454:
                link_sta->pub->agg.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_11454;
                break;
index c254acc..cd15ec7 100644 (file)
@@ -1269,12 +1269,13 @@ static void mptcp_set_rwin(struct tcp_sock *tp, struct tcphdr *th)
 
                        if (rcv_wnd == rcv_wnd_old)
                                break;
-                       if (before64(rcv_wnd_new, rcv_wnd)) {
+
+                       rcv_wnd_old = rcv_wnd;
+                       if (before64(rcv_wnd_new, rcv_wnd_old)) {
                                MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_RCVWNDCONFLICTUPDATE);
                                goto raise_win;
                        }
                        MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_RCVWNDCONFLICT);
-                       rcv_wnd_old = rcv_wnd;
                }
                return;
        }
index b5a8aa4..d042d32 100644 (file)
@@ -307,12 +307,6 @@ int mptcp_nl_cmd_sf_create(struct sk_buff *skb, struct genl_info *info)
                goto create_err;
        }
 
-       if (addr_l.id == 0) {
-               NL_SET_ERR_MSG_ATTR(info->extack, laddr, "missing local addr id");
-               err = -EINVAL;
-               goto create_err;
-       }
-
        err = mptcp_pm_parse_addr(raddr, info, &addr_r);
        if (err < 0) {
                NL_SET_ERR_MSG_ATTR(info->extack, raddr, "error parsing remote addr");
index a7fc16f..c3b83cb 100644 (file)
@@ -405,7 +405,7 @@ drop:
        return false;
 }
 
-static void mptcp_stop_timer(struct sock *sk)
+static void mptcp_stop_rtx_timer(struct sock *sk)
 {
        struct inet_connection_sock *icsk = inet_csk(sk);
 
@@ -770,6 +770,46 @@ static bool __mptcp_ofo_queue(struct mptcp_sock *msk)
        return moved;
 }
 
+static bool __mptcp_subflow_error_report(struct sock *sk, struct sock *ssk)
+{
+       int err = sock_error(ssk);
+       int ssk_state;
+
+       if (!err)
+               return false;
+
+       /* only propagate errors on fallen-back sockets or
+        * on MPC connect
+        */
+       if (sk->sk_state != TCP_SYN_SENT && !__mptcp_check_fallback(mptcp_sk(sk)))
+               return false;
+
+       /* We need to propagate only transition to CLOSE state.
+        * Orphaned socket will see such state change via
+        * subflow_sched_work_if_closed() and that path will properly
+        * destroy the msk as needed.
+        */
+       ssk_state = inet_sk_state_load(ssk);
+       if (ssk_state == TCP_CLOSE && !sock_flag(sk, SOCK_DEAD))
+               inet_sk_state_store(sk, ssk_state);
+       WRITE_ONCE(sk->sk_err, -err);
+
+       /* This barrier is coupled with smp_rmb() in mptcp_poll() */
+       smp_wmb();
+       sk_error_report(sk);
+       return true;
+}
+
+void __mptcp_error_report(struct sock *sk)
+{
+       struct mptcp_subflow_context *subflow;
+       struct mptcp_sock *msk = mptcp_sk(sk);
+
+       mptcp_for_each_subflow(msk, subflow)
+               if (__mptcp_subflow_error_report(sk, mptcp_subflow_tcp_sock(subflow)))
+                       break;
+}
+
 /* In most cases we will be able to lock the mptcp socket.  If its already
  * owned, we need to defer to the work queue to avoid ABBA deadlock.
  */
@@ -852,6 +892,7 @@ static bool __mptcp_finish_join(struct mptcp_sock *msk, struct sock *ssk)
        mptcp_subflow_ctx(ssk)->subflow_id = msk->subflow_id++;
        mptcp_sockopt_sync_locked(msk, ssk);
        mptcp_subflow_joined(msk, ssk);
+       mptcp_stop_tout_timer(sk);
        return true;
 }
 
@@ -871,12 +912,12 @@ static void __mptcp_flush_join_list(struct sock *sk, struct list_head *join_list
        }
 }
 
-static bool mptcp_timer_pending(struct sock *sk)
+static bool mptcp_rtx_timer_pending(struct sock *sk)
 {
        return timer_pending(&inet_csk(sk)->icsk_retransmit_timer);
 }
 
-static void mptcp_reset_timer(struct sock *sk)
+static void mptcp_reset_rtx_timer(struct sock *sk)
 {
        struct inet_connection_sock *icsk = inet_csk(sk);
        unsigned long tout;
@@ -1010,10 +1051,10 @@ static void __mptcp_clean_una(struct sock *sk)
 out:
        if (snd_una == READ_ONCE(msk->snd_nxt) &&
            snd_una == READ_ONCE(msk->write_seq)) {
-               if (mptcp_timer_pending(sk) && !mptcp_data_fin_enabled(msk))
-                       mptcp_stop_timer(sk);
+               if (mptcp_rtx_timer_pending(sk) && !mptcp_data_fin_enabled(msk))
+                       mptcp_stop_rtx_timer(sk);
        } else {
-               mptcp_reset_timer(sk);
+               mptcp_reset_rtx_timer(sk);
        }
 }
 
@@ -1586,8 +1627,8 @@ void __mptcp_push_pending(struct sock *sk, unsigned int flags)
                mptcp_push_release(ssk, &info);
 
        /* ensure the rtx timer is running */
-       if (!mptcp_timer_pending(sk))
-               mptcp_reset_timer(sk);
+       if (!mptcp_rtx_timer_pending(sk))
+               mptcp_reset_rtx_timer(sk);
        if (do_check_data_fin)
                mptcp_check_send_data_fin(sk);
 }
@@ -1650,8 +1691,8 @@ out:
        if (copied) {
                tcp_push(ssk, 0, info.mss_now, tcp_sk(ssk)->nonagle,
                         info.size_goal);
-               if (!mptcp_timer_pending(sk))
-                       mptcp_reset_timer(sk);
+               if (!mptcp_rtx_timer_pending(sk))
+                       mptcp_reset_rtx_timer(sk);
 
                if (msk->snd_data_fin_enable &&
                    msk->snd_nxt + 1 == msk->write_seq)
@@ -2220,7 +2261,7 @@ static void mptcp_retransmit_timer(struct timer_list *t)
        sock_put(sk);
 }
 
-static void mptcp_timeout_timer(struct timer_list *t)
+static void mptcp_tout_timer(struct timer_list *t)
 {
        struct sock *sk = from_timer(sk, t, sk_timer);
 
@@ -2329,18 +2370,14 @@ static void __mptcp_close_ssk(struct sock *sk, struct sock *ssk,
        bool dispose_it, need_push = false;
 
        /* If the first subflow moved to a close state before accept, e.g. due
-        * to an incoming reset, mptcp either:
-        * - if either the subflow or the msk are dead, destroy the context
-        *   (the subflow socket is deleted by inet_child_forget) and the msk
-        * - otherwise do nothing at the moment and take action at accept and/or
-        *   listener shutdown - user-space must be able to accept() the closed
-        *   socket.
+        * to an incoming reset or listener shutdown, the subflow socket is
+        * already deleted by inet_child_forget() and the mptcp socket can't
+        * survive too.
         */
-       if (msk->in_accept_queue && msk->first == ssk) {
-               if (!sock_flag(sk, SOCK_DEAD) && !sock_flag(ssk, SOCK_DEAD))
-                       return;
-
+       if (msk->in_accept_queue && msk->first == ssk &&
+           (sock_flag(sk, SOCK_DEAD) || sock_flag(ssk, SOCK_DEAD))) {
                /* ensure later check in mptcp_worker() will dispose the msk */
+               mptcp_set_close_tout(sk, tcp_jiffies32 - (TCP_TIMEWAIT_LEN + 1));
                sock_set_flag(sk, SOCK_DEAD);
                lock_sock_nested(ssk, SINGLE_DEPTH_NESTING);
                mptcp_subflow_drop_ctx(ssk);
@@ -2392,6 +2429,7 @@ static void __mptcp_close_ssk(struct sock *sk, struct sock *ssk,
        }
 
 out_release:
+       __mptcp_subflow_error_report(sk, ssk);
        release_sock(ssk);
 
        sock_put(ssk);
@@ -2402,6 +2440,22 @@ out_release:
 out:
        if (need_push)
                __mptcp_push_pending(sk, 0);
+
+       /* Catch every 'all subflows closed' scenario, including peers silently
+        * closing them, e.g. due to timeout.
+        * For established sockets, allow an additional timeout before closing,
+        * as the protocol can still create more subflows.
+        */
+       if (list_is_singular(&msk->conn_list) && msk->first &&
+           inet_sk_state_load(msk->first) == TCP_CLOSE) {
+               if (sk->sk_state != TCP_ESTABLISHED ||
+                   msk->in_accept_queue || sock_flag(sk, SOCK_DEAD)) {
+                       inet_sk_state_store(sk, TCP_CLOSE);
+                       mptcp_close_wake_up(sk);
+               } else {
+                       mptcp_start_tout_timer(sk);
+               }
+       }
 }
 
 void mptcp_close_ssk(struct sock *sk, struct sock *ssk,
@@ -2445,23 +2499,14 @@ static void __mptcp_close_subflow(struct sock *sk)
 
 }
 
-static bool mptcp_should_close(const struct sock *sk)
+static bool mptcp_close_tout_expired(const struct sock *sk)
 {
-       s32 delta = tcp_jiffies32 - inet_csk(sk)->icsk_mtup.probe_timestamp;
-       struct mptcp_subflow_context *subflow;
-
-       if (delta >= TCP_TIMEWAIT_LEN || mptcp_sk(sk)->in_accept_queue)
-               return true;
+       if (!inet_csk(sk)->icsk_mtup.probe_timestamp ||
+           sk->sk_state == TCP_CLOSE)
+               return false;
 
-       /* if all subflows are in closed status don't bother with additional
-        * timeout
-        */
-       mptcp_for_each_subflow(mptcp_sk(sk), subflow) {
-               if (inet_sk_state_load(mptcp_subflow_tcp_sock(subflow)) !=
-                   TCP_CLOSE)
-                       return false;
-       }
-       return true;
+       return time_after32(tcp_jiffies32,
+                 inet_csk(sk)->icsk_mtup.probe_timestamp + TCP_TIMEWAIT_LEN);
 }
 
 static void mptcp_check_fastclose(struct mptcp_sock *msk)
@@ -2588,27 +2633,28 @@ static void __mptcp_retrans(struct sock *sk)
 reset_timer:
        mptcp_check_and_set_pending(sk);
 
-       if (!mptcp_timer_pending(sk))
-               mptcp_reset_timer(sk);
+       if (!mptcp_rtx_timer_pending(sk))
+               mptcp_reset_rtx_timer(sk);
 }
 
 /* schedule the timeout timer for the relevant event: either close timeout
  * or mp_fail timeout. The close timeout takes precedence on the mp_fail one
  */
-void mptcp_reset_timeout(struct mptcp_sock *msk, unsigned long fail_tout)
+void mptcp_reset_tout_timer(struct mptcp_sock *msk, unsigned long fail_tout)
 {
        struct sock *sk = (struct sock *)msk;
        unsigned long timeout, close_timeout;
 
-       if (!fail_tout && !sock_flag(sk, SOCK_DEAD))
+       if (!fail_tout && !inet_csk(sk)->icsk_mtup.probe_timestamp)
                return;
 
-       close_timeout = inet_csk(sk)->icsk_mtup.probe_timestamp - tcp_jiffies32 + jiffies + TCP_TIMEWAIT_LEN;
+       close_timeout = inet_csk(sk)->icsk_mtup.probe_timestamp - tcp_jiffies32 + jiffies +
+                       TCP_TIMEWAIT_LEN;
 
        /* the close timeout takes precedence on the fail one, and here at least one of
         * them is active
         */
-       timeout = sock_flag(sk, SOCK_DEAD) ? close_timeout : fail_tout;
+       timeout = inet_csk(sk)->icsk_mtup.probe_timestamp ? close_timeout : fail_tout;
 
        sk_reset_timer(sk, &sk->sk_timer, timeout);
 }
@@ -2627,8 +2673,6 @@ static void mptcp_mp_fail_no_response(struct mptcp_sock *msk)
        mptcp_subflow_reset(ssk);
        WRITE_ONCE(mptcp_subflow_ctx(ssk)->fail_tout, 0);
        unlock_sock_fast(ssk, slow);
-
-       mptcp_reset_timeout(msk, 0);
 }
 
 static void mptcp_do_fastclose(struct sock *sk)
@@ -2665,18 +2709,14 @@ static void mptcp_worker(struct work_struct *work)
        if (test_and_clear_bit(MPTCP_WORK_CLOSE_SUBFLOW, &msk->flags))
                __mptcp_close_subflow(sk);
 
-       /* There is no point in keeping around an orphaned sk timedout or
-        * closed, but we need the msk around to reply to incoming DATA_FIN,
-        * even if it is orphaned and in FIN_WAIT2 state
-        */
-       if (sock_flag(sk, SOCK_DEAD)) {
-               if (mptcp_should_close(sk))
-                       mptcp_do_fastclose(sk);
+       if (mptcp_close_tout_expired(sk)) {
+               mptcp_do_fastclose(sk);
+               mptcp_close_wake_up(sk);
+       }
 
-               if (sk->sk_state == TCP_CLOSE) {
-                       __mptcp_destroy_sock(sk);
-                       goto unlock;
-               }
+       if (sock_flag(sk, SOCK_DEAD) && sk->sk_state == TCP_CLOSE) {
+               __mptcp_destroy_sock(sk);
+               goto unlock;
        }
 
        if (test_and_clear_bit(MPTCP_WORK_RTX, &msk->flags))
@@ -2717,7 +2757,7 @@ static void __mptcp_init_sock(struct sock *sk)
 
        /* re-use the csk retrans timer for MPTCP-level retrans */
        timer_setup(&msk->sk.icsk_retransmit_timer, mptcp_retransmit_timer, 0);
-       timer_setup(&sk->sk_timer, mptcp_timeout_timer, 0);
+       timer_setup(&sk->sk_timer, mptcp_tout_timer, 0);
 }
 
 static void mptcp_ca_reset(struct sock *sk)
@@ -2808,8 +2848,8 @@ void mptcp_subflow_shutdown(struct sock *sk, struct sock *ssk, int how)
                } else {
                        pr_debug("Sending DATA_FIN on subflow %p", ssk);
                        tcp_send_ack(ssk);
-                       if (!mptcp_timer_pending(sk))
-                               mptcp_reset_timer(sk);
+                       if (!mptcp_rtx_timer_pending(sk))
+                               mptcp_reset_rtx_timer(sk);
                }
                break;
        }
@@ -2892,7 +2932,7 @@ static void __mptcp_destroy_sock(struct sock *sk)
 
        might_sleep();
 
-       mptcp_stop_timer(sk);
+       mptcp_stop_rtx_timer(sk);
        sk_stop_timer(sk, &sk->sk_timer);
        msk->pm.status = 0;
        mptcp_release_sched(msk);
@@ -2975,7 +3015,6 @@ bool __mptcp_close(struct sock *sk, long timeout)
 
 cleanup:
        /* orphan all the subflows */
-       inet_csk(sk)->icsk_mtup.probe_timestamp = tcp_jiffies32;
        mptcp_for_each_subflow(msk, subflow) {
                struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
                bool slow = lock_sock_fast_nested(ssk);
@@ -3012,7 +3051,7 @@ cleanup:
                __mptcp_destroy_sock(sk);
                do_cancel_work = true;
        } else {
-               mptcp_reset_timeout(msk, 0);
+               mptcp_start_tout_timer(sk);
        }
 
        return do_cancel_work;
@@ -3075,8 +3114,8 @@ static int mptcp_disconnect(struct sock *sk, int flags)
        mptcp_check_listen_stop(sk);
        inet_sk_state_store(sk, TCP_CLOSE);
 
-       mptcp_stop_timer(sk);
-       sk_stop_timer(sk, &sk->sk_timer);
+       mptcp_stop_rtx_timer(sk);
+       mptcp_stop_tout_timer(sk);
 
        if (msk->token)
                mptcp_event(MPTCP_EVENT_CLOSED, msk, NULL, GFP_KERNEL);
@@ -3386,24 +3425,21 @@ static void schedule_3rdack_retransmission(struct sock *ssk)
        sk_reset_timer(ssk, &icsk->icsk_delack_timer, timeout);
 }
 
-void mptcp_subflow_process_delegated(struct sock *ssk)
+void mptcp_subflow_process_delegated(struct sock *ssk, long status)
 {
        struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk);
        struct sock *sk = subflow->conn;
 
-       if (test_bit(MPTCP_DELEGATE_SEND, &subflow->delegated_status)) {
+       if (status & BIT(MPTCP_DELEGATE_SEND)) {
                mptcp_data_lock(sk);
                if (!sock_owned_by_user(sk))
                        __mptcp_subflow_push_pending(sk, ssk, true);
                else
                        __set_bit(MPTCP_PUSH_PENDING, &mptcp_sk(sk)->cb_flags);
                mptcp_data_unlock(sk);
-               mptcp_subflow_delegated_done(subflow, MPTCP_DELEGATE_SEND);
        }
-       if (test_bit(MPTCP_DELEGATE_ACK, &subflow->delegated_status)) {
+       if (status & BIT(MPTCP_DELEGATE_ACK))
                schedule_3rdack_retransmission(ssk);
-               mptcp_subflow_delegated_done(subflow, MPTCP_DELEGATE_ACK);
-       }
 }
 
 static int mptcp_hash(struct sock *sk)
@@ -3929,14 +3965,17 @@ static int mptcp_napi_poll(struct napi_struct *napi, int budget)
                struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
 
                bh_lock_sock_nested(ssk);
-               if (!sock_owned_by_user(ssk) &&
-                   mptcp_subflow_has_delegated_action(subflow))
-                       mptcp_subflow_process_delegated(ssk);
-               /* ... elsewhere tcp_release_cb_override already processed
-                * the action or will do at next release_sock().
-                * In both case must dequeue the subflow here - on the same
-                * CPU that scheduled it.
-                */
+               if (!sock_owned_by_user(ssk)) {
+                       mptcp_subflow_process_delegated(ssk, xchg(&subflow->delegated_status, 0));
+               } else {
+                       /* tcp_release_cb_override already processed
+                        * the action or will do at next release_sock().
+                        * In both case must dequeue the subflow here - on the same
+                        * CPU that scheduled it.
+                        */
+                       smp_wmb();
+                       clear_bit(MPTCP_DELEGATE_SCHEDULED, &subflow->delegated_status);
+               }
                bh_unlock_sock(ssk);
                sock_put(ssk);
 
index 7254b35..3612545 100644 (file)
@@ -444,9 +444,11 @@ struct mptcp_delegated_action {
 
 DECLARE_PER_CPU(struct mptcp_delegated_action, mptcp_delegated_actions);
 
-#define MPTCP_DELEGATE_SEND            0
-#define MPTCP_DELEGATE_ACK             1
+#define MPTCP_DELEGATE_SCHEDULED       0
+#define MPTCP_DELEGATE_SEND            1
+#define MPTCP_DELEGATE_ACK             2
 
+#define MPTCP_DELEGATE_ACTIONS_MASK    (~BIT(MPTCP_DELEGATE_SCHEDULED))
 /* MPTCP subflow context */
 struct mptcp_subflow_context {
        struct  list_head node;/* conn_list of subflows */
@@ -564,23 +566,24 @@ mptcp_subflow_get_mapped_dsn(const struct mptcp_subflow_context *subflow)
        return subflow->map_seq + mptcp_subflow_get_map_offset(subflow);
 }
 
-void mptcp_subflow_process_delegated(struct sock *ssk);
+void mptcp_subflow_process_delegated(struct sock *ssk, long actions);
 
 static inline void mptcp_subflow_delegate(struct mptcp_subflow_context *subflow, int action)
 {
+       long old, set_bits = BIT(MPTCP_DELEGATE_SCHEDULED) | BIT(action);
        struct mptcp_delegated_action *delegated;
        bool schedule;
 
        /* the caller held the subflow bh socket lock */
        lockdep_assert_in_softirq();
 
-       /* The implied barrier pairs with mptcp_subflow_delegated_done(), and
-        * ensures the below list check sees list updates done prior to status
-        * bit changes
+       /* The implied barrier pairs with tcp_release_cb_override()
+        * mptcp_napi_poll(), and ensures the below list check sees list
+        * updates done prior to delegated status bits changes
         */
-       if (!test_and_set_bit(action, &subflow->delegated_status)) {
-               /* still on delegated list from previous scheduling */
-               if (!list_empty(&subflow->delegated_node))
+       old = set_mask_bits(&subflow->delegated_status, 0, set_bits);
+       if (!(old & BIT(MPTCP_DELEGATE_SCHEDULED))) {
+               if (WARN_ON_ONCE(!list_empty(&subflow->delegated_node)))
                        return;
 
                delegated = this_cpu_ptr(&mptcp_delegated_actions);
@@ -605,20 +608,6 @@ mptcp_subflow_delegated_next(struct mptcp_delegated_action *delegated)
        return ret;
 }
 
-static inline bool mptcp_subflow_has_delegated_action(const struct mptcp_subflow_context *subflow)
-{
-       return !!READ_ONCE(subflow->delegated_status);
-}
-
-static inline void mptcp_subflow_delegated_done(struct mptcp_subflow_context *subflow, int action)
-{
-       /* pairs with mptcp_subflow_delegate, ensures delegate_node is updated before
-        * touching the status bit
-        */
-       smp_wmb();
-       clear_bit(action, &subflow->delegated_status);
-}
-
 int mptcp_is_enabled(const struct net *net);
 unsigned int mptcp_get_add_addr_timeout(const struct net *net);
 int mptcp_is_checksum_enabled(const struct net *net);
@@ -718,7 +707,29 @@ void mptcp_get_options(const struct sk_buff *skb,
 
 void mptcp_finish_connect(struct sock *sk);
 void __mptcp_set_connected(struct sock *sk);
-void mptcp_reset_timeout(struct mptcp_sock *msk, unsigned long fail_tout);
+void mptcp_reset_tout_timer(struct mptcp_sock *msk, unsigned long fail_tout);
+
+static inline void mptcp_stop_tout_timer(struct sock *sk)
+{
+       if (!inet_csk(sk)->icsk_mtup.probe_timestamp)
+               return;
+
+       sk_stop_timer(sk, &sk->sk_timer);
+       inet_csk(sk)->icsk_mtup.probe_timestamp = 0;
+}
+
+static inline void mptcp_set_close_tout(struct sock *sk, unsigned long tout)
+{
+       /* avoid 0 timestamp, as that means no close timeout */
+       inet_csk(sk)->icsk_mtup.probe_timestamp = tout ? : 1;
+}
+
+static inline void mptcp_start_tout_timer(struct sock *sk)
+{
+       mptcp_set_close_tout(sk, tcp_jiffies32);
+       mptcp_reset_tout_timer(mptcp_sk(sk), 0);
+}
+
 static inline bool mptcp_is_fully_established(struct sock *sk)
 {
        return inet_sk_state_load(sk) == TCP_ESTABLISHED &&
index 9bf3c7b..9c1f8d1 100644 (file)
@@ -1226,7 +1226,7 @@ static void mptcp_subflow_fail(struct mptcp_sock *msk, struct sock *ssk)
        WRITE_ONCE(subflow->fail_tout, fail_tout);
        tcp_send_ack(ssk);
 
-       mptcp_reset_timeout(msk, subflow->fail_tout);
+       mptcp_reset_tout_timer(msk, subflow->fail_tout);
 }
 
 static bool subflow_check_data_avail(struct sock *ssk)
@@ -1362,42 +1362,6 @@ void mptcp_space(const struct sock *ssk, int *space, int *full_space)
        *full_space = mptcp_win_from_space(sk, READ_ONCE(sk->sk_rcvbuf));
 }
 
-void __mptcp_error_report(struct sock *sk)
-{
-       struct mptcp_subflow_context *subflow;
-       struct mptcp_sock *msk = mptcp_sk(sk);
-
-       mptcp_for_each_subflow(msk, subflow) {
-               struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
-               int err = sock_error(ssk);
-               int ssk_state;
-
-               if (!err)
-                       continue;
-
-               /* only propagate errors on fallen-back sockets or
-                * on MPC connect
-                */
-               if (sk->sk_state != TCP_SYN_SENT && !__mptcp_check_fallback(msk))
-                       continue;
-
-               /* We need to propagate only transition to CLOSE state.
-                * Orphaned socket will see such state change via
-                * subflow_sched_work_if_closed() and that path will properly
-                * destroy the msk as needed.
-                */
-               ssk_state = inet_sk_state_load(ssk);
-               if (ssk_state == TCP_CLOSE && !sock_flag(sk, SOCK_DEAD))
-                       inet_sk_state_store(sk, ssk_state);
-               WRITE_ONCE(sk->sk_err, -err);
-
-               /* This barrier is coupled with smp_rmb() in mptcp_poll() */
-               smp_wmb();
-               sk_error_report(sk);
-               break;
-       }
-}
-
 static void subflow_error_report(struct sock *ssk)
 {
        struct sock *sk = mptcp_subflow_ctx(ssk)->conn;
@@ -1588,6 +1552,7 @@ int __mptcp_subflow_connect(struct sock *sk, const struct mptcp_addr_info *loc,
        mptcp_sock_graft(ssk, sk->sk_socket);
        iput(SOCK_INODE(sf));
        WRITE_ONCE(msk->allow_infinite_fallback, false);
+       mptcp_stop_tout_timer(sk);
        return 0;
 
 failed_unlink:
@@ -1991,9 +1956,15 @@ static void subflow_ulp_clone(const struct request_sock *req,
 static void tcp_release_cb_override(struct sock *ssk)
 {
        struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk);
+       long status;
 
-       if (mptcp_subflow_has_delegated_action(subflow))
-               mptcp_subflow_process_delegated(ssk);
+       /* process and clear all the pending actions, but leave the subflow into
+        * the napi queue. To respect locking, only the same CPU that originated
+        * the action can touch the list. mptcp_napi_poll will take care of it.
+        */
+       status = set_mask_bits(&subflow->delegated_status, MPTCP_DELEGATE_ACTIONS_MASK, 0);
+       if (status)
+               mptcp_subflow_process_delegated(ssk, status);
 
        tcp_release_cb(ssk);
 }
index 62fb103..f8854bf 100644 (file)
@@ -89,6 +89,11 @@ static int ncsi_aen_handler_lsc(struct ncsi_dev_priv *ndp,
        if ((had_link == has_link) || chained)
                return 0;
 
+       if (had_link)
+               netif_carrier_off(ndp->ndev.dev);
+       else
+               netif_carrier_on(ndp->ndev.dev);
+
        if (!ndp->multi_package && !nc->package->multi_channel) {
                if (had_link) {
                        ndp->flags |= NCSI_DEV_RESHUFFLE;
index e564b51..35d2f9c 100644 (file)
@@ -683,6 +683,14 @@ __ip_set_put(struct ip_set *set)
  * a separate reference counter
  */
 static void
+__ip_set_get_netlink(struct ip_set *set)
+{
+       write_lock_bh(&ip_set_ref_lock);
+       set->ref_netlink++;
+       write_unlock_bh(&ip_set_ref_lock);
+}
+
+static void
 __ip_set_put_netlink(struct ip_set *set)
 {
        write_lock_bh(&ip_set_ref_lock);
@@ -1693,11 +1701,11 @@ call_ad(struct net *net, struct sock *ctnl, struct sk_buff *skb,
 
        do {
                if (retried) {
-                       __ip_set_get(set);
+                       __ip_set_get_netlink(set);
                        nfnl_unlock(NFNL_SUBSYS_IPSET);
                        cond_resched();
                        nfnl_lock(NFNL_SUBSYS_IPSET);
-                       __ip_set_put(set);
+                       __ip_set_put_netlink(set);
                }
 
                ip_set_lock(set);
index da5af28..4174076 100644 (file)
@@ -1439,7 +1439,7 @@ static int bind_mcastif_addr(struct socket *sock, struct net_device *dev)
        sin.sin_addr.s_addr  = addr;
        sin.sin_port         = 0;
 
-       return sock->ops->bind(sock, (struct sockaddr*)&sin, sizeof(sin));
+       return kernel_bind(sock, (struct sockaddr *)&sin, sizeof(sin));
 }
 
 static void get_mcast_sockaddr(union ipvs_sockaddr *sa, int *salen,
@@ -1505,8 +1505,8 @@ static int make_send_sock(struct netns_ipvs *ipvs, int id,
        }
 
        get_mcast_sockaddr(&mcast_addr, &salen, &ipvs->mcfg, id);
-       result = sock->ops->connect(sock, (struct sockaddr *) &mcast_addr,
-                                   salen, 0);
+       result = kernel_connect(sock, (struct sockaddr *)&mcast_addr,
+                               salen, 0);
        if (result < 0) {
                pr_err("Error connecting to the multicast addr\n");
                goto error;
@@ -1546,7 +1546,7 @@ static int make_receive_sock(struct netns_ipvs *ipvs, int id,
 
        get_mcast_sockaddr(&mcast_addr, &salen, &ipvs->bcfg, id);
        sock->sk->sk_bound_dev_if = dev->ifindex;
-       result = sock->ops->bind(sock, (struct sockaddr *)&mcast_addr, salen);
+       result = kernel_bind(sock, (struct sockaddr *)&mcast_addr, salen);
        if (result < 0) {
                pr_err("Error binding to the multicast addr\n");
                goto error;
index c7a6114..b21799d 100644 (file)
@@ -381,6 +381,8 @@ __bpf_kfunc struct nf_conn *bpf_ct_insert_entry(struct nf_conn___init *nfct_i)
        struct nf_conn *nfct = (struct nf_conn *)nfct_i;
        int err;
 
+       if (!nf_ct_is_confirmed(nfct))
+               nfct->timeout += nfct_time_stamp;
        nfct->status |= IPS_CONFIRMED;
        err = nf_conntrack_hash_check_insert(nfct);
        if (err < 0) {
index 0b513f7..dd62cc1 100644 (file)
@@ -40,10 +40,10 @@ static const u8 nf_ct_ext_type_len[NF_CT_EXT_NUM] = {
        [NF_CT_EXT_ECACHE] = sizeof(struct nf_conntrack_ecache),
 #endif
 #ifdef CONFIG_NF_CONNTRACK_TIMESTAMP
-       [NF_CT_EXT_TSTAMP] = sizeof(struct nf_conn_acct),
+       [NF_CT_EXT_TSTAMP] = sizeof(struct nf_conn_tstamp),
 #endif
 #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
-       [NF_CT_EXT_TIMEOUT] = sizeof(struct nf_conn_tstamp),
+       [NF_CT_EXT_TIMEOUT] = sizeof(struct nf_conn_timeout),
 #endif
 #ifdef CONFIG_NF_CONNTRACK_LABELS
        [NF_CT_EXT_LABELS] = sizeof(struct nf_conn_labels),
index b6bcc8f..c6bd533 100644 (file)
@@ -112,7 +112,7 @@ static const u8 sctp_conntracks[2][11][SCTP_CONNTRACK_MAX] = {
 /* shutdown_ack */ {sSA, sCL, sCW, sCE, sES, sSA, sSA, sSA, sSA},
 /* error        */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sCL},/* Can't have Stale cookie*/
 /* cookie_echo  */ {sCL, sCL, sCE, sCE, sES, sSS, sSR, sSA, sCL},/* 5.2.4 - Big TODO */
-/* cookie_ack   */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sCL},/* Can't come in orig dir */
+/* cookie_ack   */ {sCL, sCL, sCW, sES, sES, sSS, sSR, sSA, sCL},/* Can't come in orig dir */
 /* shutdown_comp*/ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sCL, sCL},
 /* heartbeat    */ {sHS, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS},
 /* heartbeat_ack*/ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS},
@@ -126,7 +126,7 @@ static const u8 sctp_conntracks[2][11][SCTP_CONNTRACK_MAX] = {
 /* shutdown     */ {sIV, sCL, sCW, sCE, sSR, sSS, sSR, sSA, sIV},
 /* shutdown_ack */ {sIV, sCL, sCW, sCE, sES, sSA, sSA, sSA, sIV},
 /* error        */ {sIV, sCL, sCW, sCL, sES, sSS, sSR, sSA, sIV},
-/* cookie_echo  */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA, sIV},/* Can't come in reply dir */
+/* cookie_echo  */ {sIV, sCL, sCE, sCE, sES, sSS, sSR, sSA, sIV},/* Can't come in reply dir */
 /* cookie_ack   */ {sIV, sCL, sCW, sES, sES, sSS, sSR, sSA, sIV},
 /* shutdown_comp*/ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sCL, sIV},
 /* heartbeat    */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS},
@@ -412,6 +412,9 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct,
                        /* (D) vtag must be same as init_vtag as found in INIT_ACK */
                        if (sh->vtag != ct->proto.sctp.vtag[dir])
                                goto out_unlock;
+               } else if (sch->type == SCTP_CID_COOKIE_ACK) {
+                       ct->proto.sctp.init[dir] = 0;
+                       ct->proto.sctp.init[!dir] = 0;
                } else if (sch->type == SCTP_CID_HEARTBEAT) {
                        if (ct->proto.sctp.vtag[dir] == 0) {
                                pr_debug("Setting %d vtag %x for dir %d\n", sch->type, sh->vtag, dir);
@@ -461,16 +464,18 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct,
                }
 
                /* If it is an INIT or an INIT ACK note down the vtag */
-               if (sch->type == SCTP_CID_INIT ||
-                   sch->type == SCTP_CID_INIT_ACK) {
-                       struct sctp_inithdr _inithdr, *ih;
+               if (sch->type == SCTP_CID_INIT) {
+                       struct sctp_inithdr _ih, *ih;
 
-                       ih = skb_header_pointer(skb, offset + sizeof(_sch),
-                                               sizeof(_inithdr), &_inithdr);
-                       if (ih == NULL)
+                       ih = skb_header_pointer(skb, offset + sizeof(_sch), sizeof(*ih), &_ih);
+                       if (!ih)
                                goto out_unlock;
-                       pr_debug("Setting vtag %x for dir %d\n",
-                                ih->init_tag, !dir);
+
+                       if (ct->proto.sctp.init[dir] && ct->proto.sctp.init[!dir])
+                               ct->proto.sctp.init[!dir] = 0;
+                       ct->proto.sctp.init[dir] = 1;
+
+                       pr_debug("Setting vtag %x for dir %d\n", ih->init_tag, !dir);
                        ct->proto.sctp.vtag[!dir] = ih->init_tag;
 
                        /* don't renew timeout on init retransmit so
@@ -481,6 +486,24 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct,
                            old_state == SCTP_CONNTRACK_CLOSED &&
                            nf_ct_is_confirmed(ct))
                                ignore = true;
+               } else if (sch->type == SCTP_CID_INIT_ACK) {
+                       struct sctp_inithdr _ih, *ih;
+                       __be32 vtag;
+
+                       ih = skb_header_pointer(skb, offset + sizeof(_sch), sizeof(*ih), &_ih);
+                       if (!ih)
+                               goto out_unlock;
+
+                       vtag = ct->proto.sctp.vtag[!dir];
+                       if (!ct->proto.sctp.init[!dir] && vtag && vtag != ih->init_tag)
+                               goto out_unlock;
+                       /* collision */
+                       if (ct->proto.sctp.init[dir] && ct->proto.sctp.init[!dir] &&
+                           vtag != ih->init_tag)
+                               goto out_unlock;
+
+                       pr_debug("Setting vtag %x for dir %d\n", ih->init_tag, !dir);
+                       ct->proto.sctp.vtag[!dir] = ih->init_tag;
                }
 
                ct->proto.sctp.state = new_state;
index e429ebb..a72b6ae 100644 (file)
@@ -1219,6 +1219,10 @@ static int nf_tables_updtable(struct nft_ctx *ctx)
             flags & NFT_TABLE_F_OWNER))
                return -EOPNOTSUPP;
 
+       /* No dormant off/on/off/on games in single transaction */
+       if (ctx->table->flags & __NFT_TABLE_F_UPDATE)
+               return -EINVAL;
+
        trans = nft_trans_alloc(ctx, NFT_MSG_NEWTABLE,
                                sizeof(struct nft_trans_table));
        if (trans == NULL)
@@ -1432,7 +1436,7 @@ static int nft_flush_table(struct nft_ctx *ctx)
                if (!nft_is_active_next(ctx->net, chain))
                        continue;
 
-               if (nft_chain_is_bound(chain))
+               if (nft_chain_binding(chain))
                        continue;
 
                ctx->chain = chain;
@@ -1446,8 +1450,7 @@ static int nft_flush_table(struct nft_ctx *ctx)
                if (!nft_is_active_next(ctx->net, set))
                        continue;
 
-               if (nft_set_is_anonymous(set) &&
-                   !list_empty(&set->bindings))
+               if (nft_set_is_anonymous(set))
                        continue;
 
                err = nft_delset(ctx, set);
@@ -1477,7 +1480,7 @@ static int nft_flush_table(struct nft_ctx *ctx)
                if (!nft_is_active_next(ctx->net, chain))
                        continue;
 
-               if (nft_chain_is_bound(chain))
+               if (nft_chain_binding(chain))
                        continue;
 
                ctx->chain = chain;
@@ -2910,6 +2913,9 @@ static int nf_tables_delchain(struct sk_buff *skb, const struct nfnl_info *info,
                return PTR_ERR(chain);
        }
 
+       if (nft_chain_binding(chain))
+               return -EOPNOTSUPP;
+
        nft_ctx_init(&ctx, net, skb, info->nlh, family, table, chain, nla);
 
        if (nla[NFTA_CHAIN_HOOK]) {
@@ -3449,6 +3455,8 @@ static int __nf_tables_dump_rules(struct sk_buff *skb,
        struct net *net = sock_net(skb->sk);
        const struct nft_rule *rule, *prule;
        unsigned int s_idx = cb->args[0];
+       unsigned int entries = 0;
+       int ret = 0;
        u64 handle;
 
        prule = NULL;
@@ -3471,9 +3479,11 @@ static int __nf_tables_dump_rules(struct sk_buff *skb,
                                        NFT_MSG_NEWRULE,
                                        NLM_F_MULTI | NLM_F_APPEND,
                                        table->family,
-                                       table, chain, rule, handle, reset) < 0)
-                       return 1;
-
+                                       table, chain, rule, handle, reset) < 0) {
+                       ret = 1;
+                       break;
+               }
+               entries++;
                nl_dump_check_consistent(cb, nlmsg_hdr(skb));
 cont:
                prule = rule;
@@ -3481,10 +3491,10 @@ cont_skip:
                (*idx)++;
        }
 
-       if (reset && *idx)
-               audit_log_rule_reset(table, cb->seq, *idx);
+       if (reset && entries)
+               audit_log_rule_reset(table, cb->seq, entries);
 
-       return 0;
+       return ret;
 }
 
 static int nf_tables_dump_rules(struct sk_buff *skb,
@@ -3971,6 +3981,11 @@ static int nf_tables_newrule(struct sk_buff *skb, const struct nfnl_info *info,
        }
 
        if (info->nlh->nlmsg_flags & NLM_F_REPLACE) {
+               if (nft_chain_binding(chain)) {
+                       err = -EOPNOTSUPP;
+                       goto err_destroy_flow_rule;
+               }
+
                err = nft_delrule(&ctx, old_rule);
                if (err < 0)
                        goto err_destroy_flow_rule;
@@ -4078,7 +4093,7 @@ static int nf_tables_delrule(struct sk_buff *skb, const struct nfnl_info *info,
                        NL_SET_BAD_ATTR(extack, nla[NFTA_RULE_CHAIN]);
                        return PTR_ERR(chain);
                }
-               if (nft_chain_is_bound(chain))
+               if (nft_chain_binding(chain))
                        return -EOPNOTSUPP;
        }
 
@@ -4112,7 +4127,7 @@ static int nf_tables_delrule(struct sk_buff *skb, const struct nfnl_info *info,
                list_for_each_entry(chain, &table->chains, list) {
                        if (!nft_is_active_next(net, chain))
                                continue;
-                       if (nft_chain_is_bound(chain))
+                       if (nft_chain_binding(chain))
                                continue;
 
                        ctx.chain = chain;
@@ -7183,8 +7198,10 @@ static int nf_tables_delsetelem(struct sk_buff *skb,
        if (IS_ERR(set))
                return PTR_ERR(set);
 
-       if (!list_empty(&set->bindings) &&
-           (set->flags & (NFT_SET_CONSTANT | NFT_SET_ANONYMOUS)))
+       if (nft_set_is_anonymous(set))
+               return -EOPNOTSUPP;
+
+       if (!list_empty(&set->bindings) && (set->flags & NFT_SET_CONSTANT))
                return -EBUSY;
 
        nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla);
@@ -7854,24 +7871,14 @@ static int nf_tables_delobj(struct sk_buff *skb, const struct nfnl_info *info,
        return nft_delobj(&ctx, obj);
 }
 
-void nft_obj_notify(struct net *net, const struct nft_table *table,
-                   struct nft_object *obj, u32 portid, u32 seq, int event,
-                   u16 flags, int family, int report, gfp_t gfp)
+static void
+__nft_obj_notify(struct net *net, const struct nft_table *table,
+                struct nft_object *obj, u32 portid, u32 seq, int event,
+                u16 flags, int family, int report, gfp_t gfp)
 {
        struct nftables_pernet *nft_net = nft_pernet(net);
        struct sk_buff *skb;
        int err;
-       char *buf = kasprintf(gfp, "%s:%u",
-                             table->name, nft_net->base_seq);
-
-       audit_log_nfcfg(buf,
-                       family,
-                       obj->handle,
-                       event == NFT_MSG_NEWOBJ ?
-                                AUDIT_NFT_OP_OBJ_REGISTER :
-                                AUDIT_NFT_OP_OBJ_UNREGISTER,
-                       gfp);
-       kfree(buf);
 
        if (!report &&
            !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES))
@@ -7894,13 +7901,35 @@ void nft_obj_notify(struct net *net, const struct nft_table *table,
 err:
        nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, -ENOBUFS);
 }
+
+void nft_obj_notify(struct net *net, const struct nft_table *table,
+                   struct nft_object *obj, u32 portid, u32 seq, int event,
+                   u16 flags, int family, int report, gfp_t gfp)
+{
+       struct nftables_pernet *nft_net = nft_pernet(net);
+       char *buf = kasprintf(gfp, "%s:%u",
+                             table->name, nft_net->base_seq);
+
+       audit_log_nfcfg(buf,
+                       family,
+                       obj->handle,
+                       event == NFT_MSG_NEWOBJ ?
+                                AUDIT_NFT_OP_OBJ_REGISTER :
+                                AUDIT_NFT_OP_OBJ_UNREGISTER,
+                       gfp);
+       kfree(buf);
+
+       __nft_obj_notify(net, table, obj, portid, seq, event,
+                        flags, family, report, gfp);
+}
 EXPORT_SYMBOL_GPL(nft_obj_notify);
 
 static void nf_tables_obj_notify(const struct nft_ctx *ctx,
                                 struct nft_object *obj, int event)
 {
-       nft_obj_notify(ctx->net, ctx->table, obj, ctx->portid, ctx->seq, event,
-                      ctx->flags, ctx->family, ctx->report, GFP_KERNEL);
+       __nft_obj_notify(ctx->net, ctx->table, obj, ctx->portid,
+                        ctx->seq, event, ctx->flags, ctx->family,
+                        ctx->report, GFP_KERNEL);
 }
 
 /*
@@ -9562,12 +9591,15 @@ static int nft_trans_gc_space(struct nft_trans_gc *trans)
 struct nft_trans_gc *nft_trans_gc_queue_async(struct nft_trans_gc *gc,
                                              unsigned int gc_seq, gfp_t gfp)
 {
+       struct nft_set *set;
+
        if (nft_trans_gc_space(gc))
                return gc;
 
+       set = gc->set;
        nft_trans_gc_queue_work(gc);
 
-       return nft_trans_gc_alloc(gc->set, gc_seq, gfp);
+       return nft_trans_gc_alloc(set, gc_seq, gfp);
 }
 
 void nft_trans_gc_queue_async_done(struct nft_trans_gc *trans)
@@ -9582,15 +9614,18 @@ void nft_trans_gc_queue_async_done(struct nft_trans_gc *trans)
 
 struct nft_trans_gc *nft_trans_gc_queue_sync(struct nft_trans_gc *gc, gfp_t gfp)
 {
+       struct nft_set *set;
+
        if (WARN_ON_ONCE(!lockdep_commit_lock_is_held(gc->net)))
                return NULL;
 
        if (nft_trans_gc_space(gc))
                return gc;
 
+       set = gc->set;
        call_rcu(&gc->rcu, nft_trans_gc_trans_free);
 
-       return nft_trans_gc_alloc(gc->set, 0, gfp);
+       return nft_trans_gc_alloc(set, 0, gfp);
 }
 
 void nft_trans_gc_queue_sync_done(struct nft_trans_gc *trans)
@@ -9605,8 +9640,9 @@ void nft_trans_gc_queue_sync_done(struct nft_trans_gc *trans)
        call_rcu(&trans->rcu, nft_trans_gc_trans_free);
 }
 
-struct nft_trans_gc *nft_trans_gc_catchall(struct nft_trans_gc *gc,
-                                          unsigned int gc_seq)
+static struct nft_trans_gc *nft_trans_gc_catchall(struct nft_trans_gc *gc,
+                                                 unsigned int gc_seq,
+                                                 bool sync)
 {
        struct nft_set_elem_catchall *catchall;
        const struct nft_set *set = gc->set;
@@ -9622,7 +9658,11 @@ struct nft_trans_gc *nft_trans_gc_catchall(struct nft_trans_gc *gc,
 
                nft_set_elem_dead(ext);
 dead_elem:
-               gc = nft_trans_gc_queue_async(gc, gc_seq, GFP_ATOMIC);
+               if (sync)
+                       gc = nft_trans_gc_queue_sync(gc, GFP_ATOMIC);
+               else
+                       gc = nft_trans_gc_queue_async(gc, gc_seq, GFP_ATOMIC);
+
                if (!gc)
                        return NULL;
 
@@ -9632,6 +9672,17 @@ dead_elem:
        return gc;
 }
 
+struct nft_trans_gc *nft_trans_gc_catchall_async(struct nft_trans_gc *gc,
+                                                unsigned int gc_seq)
+{
+       return nft_trans_gc_catchall(gc, gc_seq, false);
+}
+
+struct nft_trans_gc *nft_trans_gc_catchall_sync(struct nft_trans_gc *gc)
+{
+       return nft_trans_gc_catchall(gc, 0, true);
+}
+
 static void nf_tables_module_autoload_cleanup(struct net *net)
 {
        struct nftables_pernet *nft_net = nft_pernet(net);
@@ -11054,7 +11105,7 @@ static void __nft_release_table(struct net *net, struct nft_table *table)
        ctx.family = table->family;
        ctx.table = table;
        list_for_each_entry(chain, &table->chains, list) {
-               if (nft_chain_is_bound(chain))
+               if (nft_chain_binding(chain))
                        continue;
 
                ctx.chain = chain;
index 8cb8009..120f6d3 100644 (file)
@@ -154,6 +154,17 @@ int nft_payload_inner_offset(const struct nft_pktinfo *pkt)
        return pkt->inneroff;
 }
 
+static bool nft_payload_need_vlan_copy(const struct nft_payload *priv)
+{
+       unsigned int len = priv->offset + priv->len;
+
+       /* data past ether src/dst requested, copy needed */
+       if (len > offsetof(struct ethhdr, h_proto))
+               return true;
+
+       return false;
+}
+
 void nft_payload_eval(const struct nft_expr *expr,
                      struct nft_regs *regs,
                      const struct nft_pktinfo *pkt)
@@ -172,7 +183,7 @@ void nft_payload_eval(const struct nft_expr *expr,
                        goto err;
 
                if (skb_vlan_tag_present(skb) &&
-                   priv->offset >= offsetof(struct ethhdr, h_proto)) {
+                   nft_payload_need_vlan_copy(priv)) {
                        if (!nft_payload_copy_vlan(dest, skb,
                                                   priv->offset, priv->len))
                                goto err;
index 5247636..2013de9 100644 (file)
@@ -338,12 +338,9 @@ static void nft_rhash_gc(struct work_struct *work)
 
        while ((he = rhashtable_walk_next(&hti))) {
                if (IS_ERR(he)) {
-                       if (PTR_ERR(he) != -EAGAIN) {
-                               nft_trans_gc_destroy(gc);
-                               gc = NULL;
-                               goto try_later;
-                       }
-                       continue;
+                       nft_trans_gc_destroy(gc);
+                       gc = NULL;
+                       goto try_later;
                }
 
                /* Ruleset has been updated, try later. */
@@ -372,7 +369,7 @@ dead_elem:
                nft_trans_gc_elem_add(gc, he);
        }
 
-       gc = nft_trans_gc_catchall(gc, gc_seq);
+       gc = nft_trans_gc_catchall_async(gc, gc_seq);
 
 try_later:
        /* catchall list iteration requires rcu read side lock. */
index 6af9c9e..c0dcc40 100644 (file)
@@ -1596,7 +1596,7 @@ static void pipapo_gc(const struct nft_set *_set, struct nft_pipapo_match *m)
 
                        gc = nft_trans_gc_queue_sync(gc, GFP_ATOMIC);
                        if (!gc)
-                               break;
+                               return;
 
                        nft_pipapo_gc_deactivate(net, set, e);
                        pipapo_drop(m, rulemap);
@@ -1610,7 +1610,7 @@ static void pipapo_gc(const struct nft_set *_set, struct nft_pipapo_match *m)
                }
        }
 
-       gc = nft_trans_gc_catchall(gc, 0);
+       gc = nft_trans_gc_catchall_sync(gc);
        if (gc) {
                nft_trans_gc_queue_sync_done(gc);
                priv->last_gc = jiffies;
index f250b53..2660cea 100644 (file)
@@ -233,10 +233,9 @@ static void nft_rbtree_gc_remove(struct net *net, struct nft_set *set,
        rb_erase(&rbe->node, &priv->root);
 }
 
-static int nft_rbtree_gc_elem(const struct nft_set *__set,
-                             struct nft_rbtree *priv,
-                             struct nft_rbtree_elem *rbe,
-                             u8 genmask)
+static const struct nft_rbtree_elem *
+nft_rbtree_gc_elem(const struct nft_set *__set, struct nft_rbtree *priv,
+                  struct nft_rbtree_elem *rbe, u8 genmask)
 {
        struct nft_set *set = (struct nft_set *)__set;
        struct rb_node *prev = rb_prev(&rbe->node);
@@ -246,7 +245,7 @@ static int nft_rbtree_gc_elem(const struct nft_set *__set,
 
        gc = nft_trans_gc_alloc(set, 0, GFP_ATOMIC);
        if (!gc)
-               return -ENOMEM;
+               return ERR_PTR(-ENOMEM);
 
        /* search for end interval coming before this element.
         * end intervals don't carry a timeout extension, they
@@ -261,6 +260,7 @@ static int nft_rbtree_gc_elem(const struct nft_set *__set,
                prev = rb_prev(prev);
        }
 
+       rbe_prev = NULL;
        if (prev) {
                rbe_prev = rb_entry(prev, struct nft_rbtree_elem, node);
                nft_rbtree_gc_remove(net, set, priv, rbe_prev);
@@ -272,7 +272,7 @@ static int nft_rbtree_gc_elem(const struct nft_set *__set,
                 */
                gc = nft_trans_gc_queue_sync(gc, GFP_ATOMIC);
                if (WARN_ON_ONCE(!gc))
-                       return -ENOMEM;
+                       return ERR_PTR(-ENOMEM);
 
                nft_trans_gc_elem_add(gc, rbe_prev);
        }
@@ -280,13 +280,13 @@ static int nft_rbtree_gc_elem(const struct nft_set *__set,
        nft_rbtree_gc_remove(net, set, priv, rbe);
        gc = nft_trans_gc_queue_sync(gc, GFP_ATOMIC);
        if (WARN_ON_ONCE(!gc))
-               return -ENOMEM;
+               return ERR_PTR(-ENOMEM);
 
        nft_trans_gc_elem_add(gc, rbe);
 
        nft_trans_gc_queue_sync_done(gc);
 
-       return 0;
+       return rbe_prev;
 }
 
 static bool nft_rbtree_update_first(const struct nft_set *set,
@@ -314,7 +314,7 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
        struct nft_rbtree *priv = nft_set_priv(set);
        u8 cur_genmask = nft_genmask_cur(net);
        u8 genmask = nft_genmask_next(net);
-       int d, err;
+       int d;
 
        /* Descend the tree to search for an existing element greater than the
         * key value to insert that is greater than the new element. This is the
@@ -363,9 +363,14 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
                 */
                if (nft_set_elem_expired(&rbe->ext) &&
                    nft_set_elem_active(&rbe->ext, cur_genmask)) {
-                       err = nft_rbtree_gc_elem(set, priv, rbe, genmask);
-                       if (err < 0)
-                               return err;
+                       const struct nft_rbtree_elem *removed_end;
+
+                       removed_end = nft_rbtree_gc_elem(set, priv, rbe, genmask);
+                       if (IS_ERR(removed_end))
+                               return PTR_ERR(removed_end);
+
+                       if (removed_end == rbe_le || removed_end == rbe_ge)
+                               return -EAGAIN;
 
                        continue;
                }
@@ -486,11 +491,18 @@ static int nft_rbtree_insert(const struct net *net, const struct nft_set *set,
        struct nft_rbtree_elem *rbe = elem->priv;
        int err;
 
-       write_lock_bh(&priv->lock);
-       write_seqcount_begin(&priv->count);
-       err = __nft_rbtree_insert(net, set, rbe, ext);
-       write_seqcount_end(&priv->count);
-       write_unlock_bh(&priv->lock);
+       do {
+               if (fatal_signal_pending(current))
+                       return -EINTR;
+
+               cond_resched();
+
+               write_lock_bh(&priv->lock);
+               write_seqcount_begin(&priv->count);
+               err = __nft_rbtree_insert(net, set, rbe, ext);
+               write_seqcount_end(&priv->count);
+               write_unlock_bh(&priv->lock);
+       } while (err == -EAGAIN);
 
        return err;
 }
@@ -622,8 +634,7 @@ static void nft_rbtree_gc(struct work_struct *work)
        if (!gc)
                goto done;
 
-       write_lock_bh(&priv->lock);
-       write_seqcount_begin(&priv->count);
+       read_lock_bh(&priv->lock);
        for (node = rb_first(&priv->root); node != NULL; node = rb_next(node)) {
 
                /* Ruleset has been updated, try later. */
@@ -670,11 +681,10 @@ dead_elem:
                nft_trans_gc_elem_add(gc, rbe);
        }
 
-       gc = nft_trans_gc_catchall(gc, gc_seq);
+       gc = nft_trans_gc_catchall_async(gc, gc_seq);
 
 try_later:
-       write_seqcount_end(&priv->count);
-       write_unlock_bh(&priv->lock);
+       read_unlock_bh(&priv->lock);
 
        if (gc)
                nft_trans_gc_queue_async_done(gc);
index 642b9d3..eb086b0 100644 (file)
@@ -352,7 +352,7 @@ static void netlink_overrun(struct sock *sk)
        if (!nlk_test_bit(RECV_NO_ENOBUFS, sk)) {
                if (!test_and_set_bit(NETLINK_S_CONGESTED,
                                      &nlk_sk(sk)->state)) {
-                       sk->sk_err = ENOBUFS;
+                       WRITE_ONCE(sk->sk_err, ENOBUFS);
                        sk_error_report(sk);
                }
        }
@@ -1605,7 +1605,7 @@ static int do_one_set_err(struct sock *sk, struct netlink_set_err_data *p)
                goto out;
        }
 
-       sk->sk_err = p->code;
+       WRITE_ONCE(sk->sk_err, p->code);
        sk_error_report(sk);
 out:
        return ret;
@@ -1991,7 +1991,7 @@ static int netlink_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
            atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf / 2) {
                ret = netlink_dump(sk);
                if (ret) {
-                       sk->sk_err = -ret;
+                       WRITE_ONCE(sk->sk_err, -ret);
                        sk_error_report(sk);
                }
        }
@@ -2511,7 +2511,7 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err,
 err_bad_put:
        nlmsg_free(skb);
 err_skb:
-       NETLINK_CB(in_skb).sk->sk_err = ENOBUFS;
+       WRITE_ONCE(NETLINK_CB(in_skb).sk->sk_err, ENOBUFS);
        sk_error_report(NETLINK_CB(in_skb).sk);
 }
 EXPORT_SYMBOL(netlink_ack);
index f60e424..6705bb8 100644 (file)
@@ -1636,7 +1636,9 @@ int nfc_llcp_register_device(struct nfc_dev *ndev)
        timer_setup(&local->sdreq_timer, nfc_llcp_sdreq_timer, 0);
        INIT_WORK(&local->sdreq_timeout_work, nfc_llcp_sdreq_timeout_work);
 
+       spin_lock(&llcp_devices_lock);
        list_add(&local->list, &llcp_devices);
+       spin_unlock(&llcp_devices_lock);
 
        return 0;
 }
index d36f3f6..b15cf31 100644 (file)
@@ -86,11 +86,13 @@ static int rds_rdma_cm_event_handler_cmn(struct rdma_cm_id *cm_id,
                break;
 
        case RDMA_CM_EVENT_ADDR_RESOLVED:
-               rdma_set_service_type(cm_id, conn->c_tos);
-               rdma_set_min_rnr_timer(cm_id, IB_RNR_TIMER_000_32);
-               /* XXX do we need to clean up if this fails? */
-               ret = rdma_resolve_route(cm_id,
-                                        RDS_RDMA_RESOLVE_TIMEOUT_MS);
+               if (conn) {
+                       rdma_set_service_type(cm_id, conn->c_tos);
+                       rdma_set_min_rnr_timer(cm_id, IB_RNR_TIMER_000_32);
+                       /* XXX do we need to clean up if this fails? */
+                       ret = rdma_resolve_route(cm_id,
+                                                RDS_RDMA_RESOLVE_TIMEOUT_MS);
+               }
                break;
 
        case RDMA_CM_EVENT_ROUTE_RESOLVED:
index f0c477c..a0046e9 100644 (file)
@@ -145,7 +145,7 @@ int rds_tcp_conn_path_connect(struct rds_conn_path *cp)
                addrlen = sizeof(sin);
        }
 
-       ret = sock->ops->bind(sock, addr, addrlen);
+       ret = kernel_bind(sock, addr, addrlen);
        if (ret) {
                rdsdebug("bind failed with %d at address %pI6c\n",
                         ret, &conn->c_laddr);
@@ -173,7 +173,7 @@ int rds_tcp_conn_path_connect(struct rds_conn_path *cp)
         * own the socket
         */
        rds_tcp_set_callbacks(sock, cp);
-       ret = sock->ops->connect(sock, addr, addrlen, O_NONBLOCK);
+       ret = kernel_connect(sock, addr, addrlen, O_NONBLOCK);
 
        rdsdebug("connect to address %pI6c returned %d\n", &conn->c_faddr, ret);
        if (ret == -EINPROGRESS)
index 014fa24..53b3535 100644 (file)
@@ -306,7 +306,7 @@ struct socket *rds_tcp_listen_init(struct net *net, bool isv6)
                addr_len = sizeof(*sin);
        }
 
-       ret = sock->ops->bind(sock, (struct sockaddr *)&ss, addr_len);
+       ret = kernel_bind(sock, (struct sockaddr *)&ss, addr_len);
        if (ret < 0) {
                rdsdebug("could not bind %s listener socket: %d\n",
                         isv6 ? "IPv6" : "IPv4", ret);
index 01fca7a..0863089 100644 (file)
@@ -48,6 +48,7 @@ struct rfkill {
        bool                    persistent;
        bool                    polling_paused;
        bool                    suspended;
+       bool                    need_sync;
 
        const struct rfkill_ops *ops;
        void                    *data;
@@ -368,6 +369,17 @@ static void rfkill_set_block(struct rfkill *rfkill, bool blocked)
                rfkill_event(rfkill);
 }
 
+static void rfkill_sync(struct rfkill *rfkill)
+{
+       lockdep_assert_held(&rfkill_global_mutex);
+
+       if (!rfkill->need_sync)
+               return;
+
+       rfkill_set_block(rfkill, rfkill_global_states[rfkill->type].cur);
+       rfkill->need_sync = false;
+}
+
 static void rfkill_update_global_state(enum rfkill_type type, bool blocked)
 {
        int i;
@@ -730,6 +742,10 @@ static ssize_t soft_show(struct device *dev, struct device_attribute *attr,
 {
        struct rfkill *rfkill = to_rfkill(dev);
 
+       mutex_lock(&rfkill_global_mutex);
+       rfkill_sync(rfkill);
+       mutex_unlock(&rfkill_global_mutex);
+
        return sysfs_emit(buf, "%d\n", (rfkill->state & RFKILL_BLOCK_SW) ? 1 : 0);
 }
 
@@ -751,6 +767,7 @@ static ssize_t soft_store(struct device *dev, struct device_attribute *attr,
                return -EINVAL;
 
        mutex_lock(&rfkill_global_mutex);
+       rfkill_sync(rfkill);
        rfkill_set_block(rfkill, state);
        mutex_unlock(&rfkill_global_mutex);
 
@@ -783,6 +800,10 @@ static ssize_t state_show(struct device *dev, struct device_attribute *attr,
 {
        struct rfkill *rfkill = to_rfkill(dev);
 
+       mutex_lock(&rfkill_global_mutex);
+       rfkill_sync(rfkill);
+       mutex_unlock(&rfkill_global_mutex);
+
        return sysfs_emit(buf, "%d\n", user_state_from_blocked(rfkill->state));
 }
 
@@ -805,6 +826,7 @@ static ssize_t state_store(struct device *dev, struct device_attribute *attr,
                return -EINVAL;
 
        mutex_lock(&rfkill_global_mutex);
+       rfkill_sync(rfkill);
        rfkill_set_block(rfkill, state == RFKILL_USER_STATE_SOFT_BLOCKED);
        mutex_unlock(&rfkill_global_mutex);
 
@@ -1032,14 +1054,10 @@ static void rfkill_uevent_work(struct work_struct *work)
 
 static void rfkill_sync_work(struct work_struct *work)
 {
-       struct rfkill *rfkill;
-       bool cur;
-
-       rfkill = container_of(work, struct rfkill, sync_work);
+       struct rfkill *rfkill = container_of(work, struct rfkill, sync_work);
 
        mutex_lock(&rfkill_global_mutex);
-       cur = rfkill_global_states[rfkill->type].cur;
-       rfkill_set_block(rfkill, cur);
+       rfkill_sync(rfkill);
        mutex_unlock(&rfkill_global_mutex);
 }
 
@@ -1087,6 +1105,7 @@ int __must_check rfkill_register(struct rfkill *rfkill)
                        round_jiffies_relative(POLL_INTERVAL));
 
        if (!rfkill->persistent || rfkill_epo_lock_active) {
+               rfkill->need_sync = true;
                schedule_work(&rfkill->sync_work);
        } else {
 #ifdef CONFIG_RFKILL_INPUT
@@ -1171,6 +1190,7 @@ static int rfkill_fop_open(struct inode *inode, struct file *file)
                ev = kzalloc(sizeof(*ev), GFP_KERNEL);
                if (!ev)
                        goto free;
+               rfkill_sync(rfkill);
                rfkill_fill_event(&ev->ev, rfkill, RFKILL_OP_ADD);
                list_add_tail(&ev->list, &data->events);
        }
index 7965291..c45c192 100644 (file)
@@ -1159,8 +1159,7 @@ int sctp_assoc_update(struct sctp_association *asoc,
                /* Add any peer addresses from the new association. */
                list_for_each_entry(trans, &new->peer.transport_addr_list,
                                    transports)
-                       if (!sctp_assoc_lookup_paddr(asoc, &trans->ipaddr) &&
-                           !sctp_assoc_add_peer(asoc, &trans->ipaddr,
+                       if (!sctp_assoc_add_peer(asoc, &trans->ipaddr,
                                                 GFP_ATOMIC, trans->state))
                                return -ENOMEM;
 
index ab943e8..7f89e43 100644 (file)
@@ -2450,6 +2450,7 @@ static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params,
                        if (trans) {
                                trans->hbinterval =
                                    msecs_to_jiffies(params->spp_hbinterval);
+                               sctp_transport_reset_hb_timer(trans);
                        } else if (asoc) {
                                asoc->hbinterval =
                                    msecs_to_jiffies(params->spp_hbinterval);
index c8b08b3..c4a6f55 100644 (file)
@@ -737,6 +737,14 @@ static inline int sock_sendmsg_nosec(struct socket *sock, struct msghdr *msg)
        return ret;
 }
 
+static int __sock_sendmsg(struct socket *sock, struct msghdr *msg)
+{
+       int err = security_socket_sendmsg(sock, msg,
+                                         msg_data_left(msg));
+
+       return err ?: sock_sendmsg_nosec(sock, msg);
+}
+
 /**
  *     sock_sendmsg - send a message through @sock
  *     @sock: socket
@@ -747,10 +755,19 @@ static inline int sock_sendmsg_nosec(struct socket *sock, struct msghdr *msg)
  */
 int sock_sendmsg(struct socket *sock, struct msghdr *msg)
 {
-       int err = security_socket_sendmsg(sock, msg,
-                                         msg_data_left(msg));
+       struct sockaddr_storage *save_addr = (struct sockaddr_storage *)msg->msg_name;
+       struct sockaddr_storage address;
+       int ret;
 
-       return err ?: sock_sendmsg_nosec(sock, msg);
+       if (msg->msg_name) {
+               memcpy(&address, msg->msg_name, msg->msg_namelen);
+               msg->msg_name = &address;
+       }
+
+       ret = __sock_sendmsg(sock, msg);
+       msg->msg_name = save_addr;
+
+       return ret;
 }
 EXPORT_SYMBOL(sock_sendmsg);
 
@@ -1138,7 +1155,7 @@ static ssize_t sock_write_iter(struct kiocb *iocb, struct iov_iter *from)
        if (sock->type == SOCK_SEQPACKET)
                msg.msg_flags |= MSG_EOR;
 
-       res = sock_sendmsg(sock, &msg);
+       res = __sock_sendmsg(sock, &msg);
        *from = msg.msg_iter;
        return res;
 }
@@ -2174,7 +2191,7 @@ int __sys_sendto(int fd, void __user *buff, size_t len, unsigned int flags,
        if (sock->file->f_flags & O_NONBLOCK)
                flags |= MSG_DONTWAIT;
        msg.msg_flags = flags;
-       err = sock_sendmsg(sock, &msg);
+       err = __sock_sendmsg(sock, &msg);
 
 out_put:
        fput_light(sock->file, fput_needed);
@@ -2538,7 +2555,7 @@ static int ____sys_sendmsg(struct socket *sock, struct msghdr *msg_sys,
                err = sock_sendmsg_nosec(sock, msg_sys);
                goto out_freectl;
        }
-       err = sock_sendmsg(sock, msg_sys);
+       err = __sock_sendmsg(sock, msg_sys);
        /*
         * If this is sendmmsg() and sending to current destination address was
         * successful, remember it.
@@ -3499,7 +3516,12 @@ static long compat_sock_ioctl(struct file *file, unsigned int cmd,
 
 int kernel_bind(struct socket *sock, struct sockaddr *addr, int addrlen)
 {
-       return READ_ONCE(sock->ops)->bind(sock, addr, addrlen);
+       struct sockaddr_storage address;
+
+       memcpy(&address, addr, addrlen);
+
+       return READ_ONCE(sock->ops)->bind(sock, (struct sockaddr *)&address,
+                                         addrlen);
 }
 EXPORT_SYMBOL(kernel_bind);
 
index 2f16f9d..814b016 100644 (file)
@@ -769,9 +769,14 @@ int rpcauth_wrap_req(struct rpc_task *task, struct xdr_stream *xdr)
  * @task: controlling RPC task
  * @xdr: xdr_stream containing RPC Reply header
  *
- * On success, @xdr is updated to point past the verifier and
- * zero is returned. Otherwise, @xdr is in an undefined state
- * and a negative errno is returned.
+ * Return values:
+ *   %0: Verifier is valid. @xdr now points past the verifier.
+ *   %-EIO: Verifier is corrupted or message ended early.
+ *   %-EACCES: Verifier is intact but not valid.
+ *   %-EPROTONOSUPPORT: Server does not support the requested auth type.
+ *
+ * When a negative errno is returned, @xdr is left in an undefined
+ * state.
  */
 int
 rpcauth_checkverf(struct rpc_task *task, struct xdr_stream *xdr)
index de7678f..87f570f 100644 (file)
@@ -129,9 +129,9 @@ static int tls_validate(struct rpc_task *task, struct xdr_stream *xdr)
        if (*p != rpc_auth_null)
                return -EIO;
        if (xdr_stream_decode_opaque_inline(xdr, &str, starttls_len) != starttls_len)
-               return -EIO;
+               return -EPROTONOSUPPORT;
        if (memcmp(str, starttls_token, starttls_len))
-               return -EIO;
+               return -EPROTONOSUPPORT;
        return 0;
 }
 
index 8d75290..9c21027 100644 (file)
@@ -2476,8 +2476,7 @@ call_status(struct rpc_task *task)
                goto out_exit;
        }
        task->tk_action = call_encode;
-       if (status != -ECONNRESET && status != -ECONNABORTED)
-               rpc_check_timeout(task);
+       rpc_check_timeout(task);
        return;
 out_exit:
        rpc_call_rpcerror(task, status);
@@ -2725,7 +2724,15 @@ out_unparsable:
 
 out_verifier:
        trace_rpc_bad_verifier(task);
-       goto out_err;
+       switch (error) {
+       case -EPROTONOSUPPORT:
+               goto out_err;
+       case -EACCES:
+               /* Re-encode with a fresh cred */
+               fallthrough;
+       default:
+               goto out_garbage;
+       }
 
 out_msg_denied:
        error = -EACCES;
@@ -2751,6 +2758,7 @@ out_msg_denied:
        case rpc_autherr_rejectedverf:
        case rpcsec_gsserr_credproblem:
        case rpcsec_gsserr_ctxproblem:
+               rpcauth_invalcred(task);
                if (!task->tk_cred_retry)
                        break;
                task->tk_cred_retry--;
@@ -2907,19 +2915,22 @@ static const struct rpc_call_ops rpc_cb_add_xprt_call_ops = {
  * @clnt: pointer to struct rpc_clnt
  * @xps: pointer to struct rpc_xprt_switch,
  * @xprt: pointer struct rpc_xprt
- * @dummy: unused
+ * @in_max_connect: pointer to the max_connect value for the passed in xprt transport
  */
 int rpc_clnt_test_and_add_xprt(struct rpc_clnt *clnt,
                struct rpc_xprt_switch *xps, struct rpc_xprt *xprt,
-               void *dummy)
+               void *in_max_connect)
 {
        struct rpc_cb_add_xprt_calldata *data;
        struct rpc_task *task;
+       int max_connect = clnt->cl_max_connect;
 
-       if (xps->xps_nunique_destaddr_xprts + 1 > clnt->cl_max_connect) {
+       if (in_max_connect)
+               max_connect = *(int *)in_max_connect;
+       if (xps->xps_nunique_destaddr_xprts + 1 > max_connect) {
                rcu_read_lock();
                pr_warn("SUNRPC: reached max allowed number (%d) did not add "
-                       "transport to server: %s\n", clnt->cl_max_connect,
+                       "transport to server: %s\n", max_connect,
                        rpc_peeraddr2str(clnt, RPC_DISPLAY_ADDR));
                rcu_read_unlock();
                return -EINVAL;
index 71cd916..a15bf2e 100644 (file)
@@ -2672,6 +2672,10 @@ static void xs_tcp_tls_setup_socket(struct work_struct *work)
        rcu_read_lock();
        lower_xprt = rcu_dereference(lower_clnt->cl_xprt);
        rcu_read_unlock();
+
+       if (wait_on_bit_lock(&lower_xprt->state, XPRT_LOCKED, TASK_KILLABLE))
+               goto out_unlock;
+
        status = xs_tls_handshake_sync(lower_xprt, &upper_xprt->xprtsec);
        if (status) {
                trace_rpc_tls_not_started(upper_clnt, upper_xprt);
@@ -2681,6 +2685,7 @@ static void xs_tcp_tls_setup_socket(struct work_struct *work)
        status = xs_tcp_tls_finish_connecting(lower_xprt, upper_transport);
        if (status)
                goto out_close;
+       xprt_release_write(lower_xprt, NULL);
 
        trace_rpc_socket_connect(upper_xprt, upper_transport->sock, 0);
        if (!xprt_test_and_set_connected(upper_xprt)) {
@@ -2702,6 +2707,7 @@ out_unlock:
        return;
 
 out_close:
+       xprt_release_write(lower_xprt, NULL);
        rpc_shutdown_client(lower_clnt);
 
        /* xprt_force_disconnect() wakes tasks with a fixed tk_status code.
index 302fd74..43c3f1c 100644 (file)
@@ -1441,14 +1441,14 @@ static int tipc_crypto_key_revoke(struct net *net, u8 tx_key)
        struct tipc_crypto *tx = tipc_net(net)->crypto_tx;
        struct tipc_key key;
 
-       spin_lock(&tx->lock);
+       spin_lock_bh(&tx->lock);
        key = tx->key;
        WARN_ON(!key.active || tx_key != key.active);
 
        /* Free the active key */
        tipc_crypto_key_set_state(tx, key.passive, 0, key.pending);
        tipc_crypto_key_detach(tx->aead[key.active], &tx->lock);
-       spin_unlock(&tx->lock);
+       spin_unlock_bh(&tx->lock);
 
        pr_warn("%s: key is revoked\n", tx->name);
        return -EKEYREVOKED;
index 25bc2e5..64e8616 100644 (file)
@@ -1181,16 +1181,11 @@ void wiphy_rfkill_set_hw_state_reason(struct wiphy *wiphy, bool blocked,
 }
 EXPORT_SYMBOL(wiphy_rfkill_set_hw_state_reason);
 
-void cfg80211_cqm_config_free(struct wireless_dev *wdev)
-{
-       kfree(wdev->cqm_config);
-       wdev->cqm_config = NULL;
-}
-
 static void _cfg80211_unregister_wdev(struct wireless_dev *wdev,
                                      bool unregister_netdev)
 {
        struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
+       struct cfg80211_cqm_config *cqm_config;
        unsigned int link_id;
 
        ASSERT_RTNL();
@@ -1227,7 +1222,10 @@ static void _cfg80211_unregister_wdev(struct wireless_dev *wdev,
        kfree_sensitive(wdev->wext.keys);
        wdev->wext.keys = NULL;
 #endif
-       cfg80211_cqm_config_free(wdev);
+       wiphy_work_cancel(wdev->wiphy, &wdev->cqm_rssi_work);
+       /* deleted from the list, so can't be found from nl80211 any more */
+       cqm_config = rcu_access_pointer(wdev->cqm_config);
+       kfree_rcu(cqm_config, rcu_head);
 
        /*
         * Ensure that all events have been processed and
@@ -1379,6 +1377,8 @@ void cfg80211_init_wdev(struct wireless_dev *wdev)
        wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
 #endif
 
+       wiphy_work_init(&wdev->cqm_rssi_work, cfg80211_cqm_rssi_notify_work);
+
        if (wdev->wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT)
                wdev->ps = true;
        else
index 507d184..ba9c717 100644 (file)
@@ -295,12 +295,17 @@ struct cfg80211_beacon_registration {
 };
 
 struct cfg80211_cqm_config {
+       struct rcu_head rcu_head;
        u32 rssi_hyst;
        s32 last_rssi_event_value;
+       enum nl80211_cqm_rssi_threshold_event last_rssi_event_type;
        int n_rssi_thresholds;
        s32 rssi_thresholds[] __counted_by(n_rssi_thresholds);
 };
 
+void cfg80211_cqm_rssi_notify_work(struct wiphy *wiphy,
+                                  struct wiphy_work *work);
+
 void cfg80211_destroy_ifaces(struct cfg80211_registered_device *rdev);
 
 /* free object */
@@ -566,8 +571,6 @@ cfg80211_bss_update(struct cfg80211_registered_device *rdev,
 #define CFG80211_DEV_WARN_ON(cond)     ({bool __r = (cond); __r; })
 #endif
 
-void cfg80211_cqm_config_free(struct wireless_dev *wdev);
-
 void cfg80211_release_pmsr(struct wireless_dev *wdev, u32 portid);
 void cfg80211_pmsr_wdev_down(struct wireless_dev *wdev);
 void cfg80211_pmsr_free_wk(struct work_struct *work);
index 775cac4..3e2c398 100644 (file)
@@ -52,7 +52,8 @@ void cfg80211_rx_assoc_resp(struct net_device *dev,
                cr.links[link_id].bssid = data->links[link_id].bss->bssid;
                cr.links[link_id].addr = data->links[link_id].addr;
                /* need to have local link addresses for MLO connections */
-               WARN_ON(cr.ap_mld_addr && !cr.links[link_id].addr);
+               WARN_ON(cr.ap_mld_addr &&
+                       !is_valid_ether_addr(cr.links[link_id].addr));
 
                BUG_ON(!cr.links[link_id].bss->channel);
 
index de47838..931a03f 100644 (file)
@@ -5909,6 +5909,21 @@ out:
        nlmsg_free(msg);
 }
 
+static int nl80211_validate_ap_phy_operation(struct cfg80211_ap_settings *params)
+{
+       struct ieee80211_channel *channel = params->chandef.chan;
+
+       if ((params->he_cap ||  params->he_oper) &&
+           (channel->flags & IEEE80211_CHAN_NO_HE))
+               return -EOPNOTSUPP;
+
+       if ((params->eht_cap || params->eht_oper) &&
+           (channel->flags & IEEE80211_CHAN_NO_EHT))
+               return -EOPNOTSUPP;
+
+       return 0;
+}
+
 static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
 {
        struct cfg80211_registered_device *rdev = info->user_ptr[0];
@@ -6178,6 +6193,10 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
        if (err)
                goto out_unlock;
 
+       err = nl80211_validate_ap_phy_operation(params);
+       if (err)
+               goto out_unlock;
+
        if (info->attrs[NL80211_ATTR_AP_SETTINGS_FLAGS])
                params->flags = nla_get_u32(
                        info->attrs[NL80211_ATTR_AP_SETTINGS_FLAGS]);
@@ -8482,7 +8501,7 @@ static int nl80211_update_mesh_config(struct sk_buff *skb,
        struct cfg80211_registered_device *rdev = info->user_ptr[0];
        struct net_device *dev = info->user_ptr[1];
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct mesh_config cfg;
+       struct mesh_config cfg = {};
        u32 mask;
        int err;
 
@@ -12796,7 +12815,8 @@ static int nl80211_set_cqm_txe(struct genl_info *info,
 }
 
 static int cfg80211_cqm_rssi_update(struct cfg80211_registered_device *rdev,
-                                   struct net_device *dev)
+                                   struct net_device *dev,
+                                   struct cfg80211_cqm_config *cqm_config)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        s32 last, low, high;
@@ -12805,7 +12825,7 @@ static int cfg80211_cqm_rssi_update(struct cfg80211_registered_device *rdev,
        int err;
 
        /* RSSI reporting disabled? */
-       if (!wdev->cqm_config)
+       if (!cqm_config)
                return rdev_set_cqm_rssi_range_config(rdev, dev, 0, 0);
 
        /*
@@ -12814,7 +12834,7 @@ static int cfg80211_cqm_rssi_update(struct cfg80211_registered_device *rdev,
         * connection is established and enough beacons received to calculate
         * the average.
         */
-       if (!wdev->cqm_config->last_rssi_event_value &&
+       if (!cqm_config->last_rssi_event_value &&
            wdev->links[0].client.current_bss &&
            rdev->ops->get_station) {
                struct station_info sinfo = {};
@@ -12828,30 +12848,30 @@ static int cfg80211_cqm_rssi_update(struct cfg80211_registered_device *rdev,
 
                cfg80211_sinfo_release_content(&sinfo);
                if (sinfo.filled & BIT_ULL(NL80211_STA_INFO_BEACON_SIGNAL_AVG))
-                       wdev->cqm_config->last_rssi_event_value =
+                       cqm_config->last_rssi_event_value =
                                (s8) sinfo.rx_beacon_signal_avg;
        }
 
-       last = wdev->cqm_config->last_rssi_event_value;
-       hyst = wdev->cqm_config->rssi_hyst;
-       n = wdev->cqm_config->n_rssi_thresholds;
+       last = cqm_config->last_rssi_event_value;
+       hyst = cqm_config->rssi_hyst;
+       n = cqm_config->n_rssi_thresholds;
 
        for (i = 0; i < n; i++) {
                i = array_index_nospec(i, n);
-               if (last < wdev->cqm_config->rssi_thresholds[i])
+               if (last < cqm_config->rssi_thresholds[i])
                        break;
        }
 
        low_index = i - 1;
        if (low_index >= 0) {
                low_index = array_index_nospec(low_index, n);
-               low = wdev->cqm_config->rssi_thresholds[low_index] - hyst;
+               low = cqm_config->rssi_thresholds[low_index] - hyst;
        } else {
                low = S32_MIN;
        }
        if (i < n) {
                i = array_index_nospec(i, n);
-               high = wdev->cqm_config->rssi_thresholds[i] + hyst - 1;
+               high = cqm_config->rssi_thresholds[i] + hyst - 1;
        } else {
                high = S32_MAX;
        }
@@ -12864,6 +12884,7 @@ static int nl80211_set_cqm_rssi(struct genl_info *info,
                                u32 hysteresis)
 {
        struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct cfg80211_cqm_config *cqm_config = NULL, *old;
        struct net_device *dev = info->user_ptr[1];
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        int i, err;
@@ -12881,10 +12902,6 @@ static int nl80211_set_cqm_rssi(struct genl_info *info,
            wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
                return -EOPNOTSUPP;
 
-       wdev_lock(wdev);
-       cfg80211_cqm_config_free(wdev);
-       wdev_unlock(wdev);
-
        if (n_thresholds <= 1 && rdev->ops->set_cqm_rssi_config) {
                if (n_thresholds == 0 || thresholds[0] == 0) /* Disabling */
                        return rdev_set_cqm_rssi_config(rdev, dev, 0, 0);
@@ -12901,9 +12918,10 @@ static int nl80211_set_cqm_rssi(struct genl_info *info,
                n_thresholds = 0;
 
        wdev_lock(wdev);
-       if (n_thresholds) {
-               struct cfg80211_cqm_config *cqm_config;
+       old = rcu_dereference_protected(wdev->cqm_config,
+                                       lockdep_is_held(&wdev->mtx));
 
+       if (n_thresholds) {
                cqm_config = kzalloc(struct_size(cqm_config, rssi_thresholds,
                                                 n_thresholds),
                                     GFP_KERNEL);
@@ -12918,11 +12936,18 @@ static int nl80211_set_cqm_rssi(struct genl_info *info,
                       flex_array_size(cqm_config, rssi_thresholds,
                                       n_thresholds));
 
-               wdev->cqm_config = cqm_config;
+               rcu_assign_pointer(wdev->cqm_config, cqm_config);
+       } else {
+               RCU_INIT_POINTER(wdev->cqm_config, NULL);
        }
 
-       err = cfg80211_cqm_rssi_update(rdev, dev);
-
+       err = cfg80211_cqm_rssi_update(rdev, dev, cqm_config);
+       if (err) {
+               rcu_assign_pointer(wdev->cqm_config, old);
+               kfree_rcu(cqm_config, rcu_head);
+       } else {
+               kfree_rcu(old, rcu_head);
+       }
 unlock:
        wdev_unlock(wdev);
 
@@ -19073,9 +19098,8 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev,
                              enum nl80211_cqm_rssi_threshold_event rssi_event,
                              s32 rssi_level, gfp_t gfp)
 {
-       struct sk_buff *msg;
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
+       struct cfg80211_cqm_config *cqm_config;
 
        trace_cfg80211_cqm_rssi_notify(dev, rssi_event, rssi_level);
 
@@ -19083,18 +19107,41 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev,
                    rssi_event != NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH))
                return;
 
-       if (wdev->cqm_config) {
-               wdev->cqm_config->last_rssi_event_value = rssi_level;
+       rcu_read_lock();
+       cqm_config = rcu_dereference(wdev->cqm_config);
+       if (cqm_config) {
+               cqm_config->last_rssi_event_value = rssi_level;
+               cqm_config->last_rssi_event_type = rssi_event;
+               wiphy_work_queue(wdev->wiphy, &wdev->cqm_rssi_work);
+       }
+       rcu_read_unlock();
+}
+EXPORT_SYMBOL(cfg80211_cqm_rssi_notify);
 
-               cfg80211_cqm_rssi_update(rdev, dev);
+void cfg80211_cqm_rssi_notify_work(struct wiphy *wiphy, struct wiphy_work *work)
+{
+       struct wireless_dev *wdev = container_of(work, struct wireless_dev,
+                                                cqm_rssi_work);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
+       enum nl80211_cqm_rssi_threshold_event rssi_event;
+       struct cfg80211_cqm_config *cqm_config;
+       struct sk_buff *msg;
+       s32 rssi_level;
 
-               if (rssi_level == 0)
-                       rssi_level = wdev->cqm_config->last_rssi_event_value;
-       }
+       wdev_lock(wdev);
+       cqm_config = rcu_dereference_protected(wdev->cqm_config,
+                                              lockdep_is_held(&wdev->mtx));
+       if (!wdev->cqm_config)
+               goto unlock;
 
-       msg = cfg80211_prepare_cqm(dev, NULL, gfp);
+       cfg80211_cqm_rssi_update(rdev, wdev->netdev, cqm_config);
+
+       rssi_level = cqm_config->last_rssi_event_value;
+       rssi_event = cqm_config->last_rssi_event_type;
+
+       msg = cfg80211_prepare_cqm(wdev->netdev, NULL, GFP_KERNEL);
        if (!msg)
-               return;
+               goto unlock;
 
        if (nla_put_u32(msg, NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT,
                        rssi_event))
@@ -19104,14 +19151,15 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev,
                                      rssi_level))
                goto nla_put_failure;
 
-       cfg80211_send_cqm(msg, gfp);
+       cfg80211_send_cqm(msg, GFP_KERNEL);
 
-       return;
+       goto unlock;
 
  nla_put_failure:
        nlmsg_free(msg);
+ unlock:
+       wdev_unlock(wdev);
 }
-EXPORT_SYMBOL(cfg80211_cqm_rssi_notify);
 
 void cfg80211_cqm_txe_notify(struct net_device *dev,
                             const u8 *peer, u32 num_packets,
index 0cf1ce7..939deec 100644 (file)
@@ -908,6 +908,10 @@ static int cfg80211_scan_6ghz(struct cfg80211_registered_device *rdev)
                    !cfg80211_find_ssid_match(ap, request))
                        continue;
 
+               if (!is_broadcast_ether_addr(request->bssid) &&
+                   !ether_addr_equal(request->bssid, ap->bssid))
+                       continue;
+
                if (!request->n_ssids && ap->multi_bss && !ap->transmitted_bssid)
                        continue;
 
index 346f5ec..0afd754 100644 (file)
@@ -144,7 +144,7 @@ endif
 quiet_cmd_gzip = GZIP    $@
       cmd_gzip = $(KGZIP) -n -f $<
 quiet_cmd_xz = XZ      $@
-      cmd_xz = $(XZ) --lzma2=dict=2MiB -f $<
+      cmd_xz = $(XZ) --check=crc32 --lzma2=dict=1MiB -f $<
 quiet_cmd_zstd = ZSTD    $@
       cmd_zstd = $(ZSTD) -T0 --rm -f -q $<
 
index c0c8a85..a45154c 100755 (executable)
@@ -102,7 +102,7 @@ gen_proto_order_variant()
        fi
 
        # Allow ACQUIRE/RELEASE/RELAXED ops to be defined in terms of FULL ops
-       if [ ! -z "${order}" ]; then
+       if [ ! -z "${order}" ] && ! meta_is_implicitly_relaxed "${meta}"; then
                printf "#elif defined(arch_${basename})\n"
                printf "\t${retstmt}arch_${basename}(${args});\n"
        fi
index 5179edd..c8047f4 100644 (file)
@@ -111,12 +111,11 @@ lx-symbols command."""
         return "{textaddr} {sections}".format(
             textaddr=textaddr, sections="".join(args))
 
-    def load_module_symbols(self, module, module_file=None):
+    def load_module_symbols(self, module):
         module_name = module['name'].string()
         module_addr = str(module['mem'][constants.LX_MOD_TEXT]['base']).split()[0]
 
-        if not module_file:
-            module_file = self._get_module_file(module_name)
+        module_file = self._get_module_file(module_name)
         if not module_file and not self.module_files_updated:
             self._update_module_files()
             module_file = self._get_module_file(module_name)
@@ -139,19 +138,6 @@ lx-symbols command."""
         else:
             gdb.write("no module object found for '{0}'\n".format(module_name))
 
-    def load_ko_symbols(self, mod_path):
-        self.loaded_modules = []
-        module_list = modules.module_list()
-
-        for module in module_list:
-            module_name = module['name'].string()
-            module_pattern = ".*/{0}\.ko(?:.debug)?$".format(
-                module_name.replace("_", r"[_\-]"))
-            if re.match(module_pattern, mod_path) and os.path.exists(mod_path):
-                self.load_module_symbols(module, mod_path)
-                return
-        raise gdb.GdbError("%s is not a valid .ko\n" % mod_path)
-
     def load_all_symbols(self):
         gdb.write("loading vmlinux\n")
 
@@ -190,11 +176,6 @@ lx-symbols command."""
         self.module_files = []
         self.module_files_updated = False
 
-        argv = gdb.string_to_argv(arg)
-        if len(argv) == 1:
-            self.load_ko_symbols(argv[0])
-            return
-
         self.load_all_symbols()
 
         if hasattr(gdb, 'Breakpoint'):
index 38120f9..7056751 100644 (file)
@@ -1604,7 +1604,7 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
        /* First handle the "special" cases */
        if (sym_is(name, namelen, "usb"))
                do_usb_table(symval, sym->st_size, mod);
-       if (sym_is(name, namelen, "of"))
+       else if (sym_is(name, namelen, "of"))
                do_of_table(symval, sym->st_size, mod);
        else if (sym_is(name, namelen, "pnp"))
                do_pnp_device_entry(symval, sym->st_size, mod);
index de499dc..b3dee80 100644 (file)
@@ -1015,9 +1015,20 @@ static int secref_whitelist(const char *fromsec, const char *fromsym,
                                    "*_console")))
                return 0;
 
-       /* symbols in data sections that may refer to meminit/exit sections */
+       /* symbols in data sections that may refer to meminit sections */
        if (match(fromsec, PATTERNS(DATA_SECTIONS)) &&
-           match(tosec, PATTERNS(ALL_XXXINIT_SECTIONS, ALL_EXIT_SECTIONS)) &&
+           match(tosec, PATTERNS(ALL_XXXINIT_SECTIONS, ALL_XXXEXIT_SECTIONS)) &&
+           match(fromsym, PATTERNS("*driver")))
+               return 0;
+
+       /*
+        * symbols in data sections must not refer to .exit.*, but there are
+        * quite a few offenders, so hide these unless for W=1 builds until
+        * these are fixed.
+        */
+       if (!extra_warn &&
+           match(fromsec, PATTERNS(DATA_SECTIONS)) &&
+           match(tosec, PATTERNS(EXIT_SECTIONS)) &&
            match(fromsym, PATTERNS("*driver")))
                return 0;
 
index bf3f856..d7dd0d0 100755 (executable)
@@ -64,7 +64,6 @@ install_linux_image () {
 
        ${MAKE} -f ${srctree}/Makefile INSTALL_MOD_PATH="${pdir}" modules_install
        rm -f "${pdir}/lib/modules/${KERNELRELEASE}/build"
-       rm -f "${pdir}/lib/modules/${KERNELRELEASE}/source"
 
        # Install the kernel
        if [ "${ARCH}" = um ] ; then
index ac3f2ee..3eee014 100644 (file)
@@ -68,7 +68,6 @@ cp $(%{make} %{makeflags} -s image_name) %{buildroot}/boot/vmlinuz-%{KERNELRELEA
 cp System.map %{buildroot}/boot/System.map-%{KERNELRELEASE}
 cp .config %{buildroot}/boot/config-%{KERNELRELEASE}
 ln -fns /usr/src/kernels/%{KERNELRELEASE} %{buildroot}/lib/modules/%{KERNELRELEASE}/build
-ln -fns /usr/src/kernels/%{KERNELRELEASE} %{buildroot}/lib/modules/%{KERNELRELEASE}/source
 %if %{with_devel}
 %{make} %{makeflags} run-command KBUILD_RUN_COMMAND='${srctree}/scripts/package/install-extmod-build %{buildroot}/usr/src/kernels/%{KERNELRELEASE}'
 %endif
@@ -101,7 +100,6 @@ fi
 %defattr (-, root, root)
 /lib/modules/%{KERNELRELEASE}
 %exclude /lib/modules/%{KERNELRELEASE}/build
-%exclude /lib/modules/%{KERNELRELEASE}/source
 /boot/*
 
 %files headers
@@ -113,5 +111,4 @@ fi
 %defattr (-, root, root)
 /usr/src/kernels/%{KERNELRELEASE}
 /lib/modules/%{KERNELRELEASE}/build
-/lib/modules/%{KERNELRELEASE}/source
 %endif
index ecddc80..a6bd817 100644 (file)
@@ -29,9 +29,11 @@ config IMA
          to learn more about IMA.
          If unsure, say N.
 
+if IMA
+
 config IMA_KEXEC
        bool "Enable carrying the IMA measurement list across a soft boot"
-       depends on IMA && TCG_TPM && HAVE_IMA_KEXEC
+       depends on TCG_TPM && HAVE_IMA_KEXEC
        default n
        help
           TPM PCRs are only reset on a hard reboot.  In order to validate
@@ -43,7 +45,6 @@ config IMA_KEXEC
 
 config IMA_MEASURE_PCR_IDX
        int
-       depends on IMA
        range 8 14
        default 10
        help
@@ -53,7 +54,7 @@ config IMA_MEASURE_PCR_IDX
 
 config IMA_LSM_RULES
        bool
-       depends on IMA && AUDIT && (SECURITY_SELINUX || SECURITY_SMACK || SECURITY_APPARMOR)
+       depends on AUDIT && (SECURITY_SELINUX || SECURITY_SMACK || SECURITY_APPARMOR)
        default y
        help
          Disabling this option will disregard LSM based policy rules.
@@ -61,7 +62,6 @@ config IMA_LSM_RULES
 choice
        prompt "Default template"
        default IMA_NG_TEMPLATE
-       depends on IMA
        help
          Select the default IMA measurement template.
 
@@ -80,14 +80,12 @@ endchoice
 
 config IMA_DEFAULT_TEMPLATE
        string
-       depends on IMA
        default "ima-ng" if IMA_NG_TEMPLATE
        default "ima-sig" if IMA_SIG_TEMPLATE
 
 choice
        prompt "Default integrity hash algorithm"
        default IMA_DEFAULT_HASH_SHA1
-       depends on IMA
        help
           Select the default hash algorithm used for the measurement
           list, integrity appraisal and audit log.  The compiled default
@@ -117,7 +115,6 @@ endchoice
 
 config IMA_DEFAULT_HASH
        string
-       depends on IMA
        default "sha1" if IMA_DEFAULT_HASH_SHA1
        default "sha256" if IMA_DEFAULT_HASH_SHA256
        default "sha512" if IMA_DEFAULT_HASH_SHA512
@@ -126,7 +123,6 @@ config IMA_DEFAULT_HASH
 
 config IMA_WRITE_POLICY
        bool "Enable multiple writes to the IMA policy"
-       depends on IMA
        default n
        help
          IMA policy can now be updated multiple times.  The new rules get
@@ -137,7 +133,6 @@ config IMA_WRITE_POLICY
 
 config IMA_READ_POLICY
        bool "Enable reading back the current IMA policy"
-       depends on IMA
        default y if IMA_WRITE_POLICY
        default n if !IMA_WRITE_POLICY
        help
@@ -147,7 +142,6 @@ config IMA_READ_POLICY
 
 config IMA_APPRAISE
        bool "Appraise integrity measurements"
-       depends on IMA
        default n
        help
          This option enables local measurement integrity appraisal.
@@ -269,7 +263,7 @@ config IMA_KEYRINGS_PERMIT_SIGNED_BY_BUILTIN_OR_SECONDARY
 config IMA_BLACKLIST_KEYRING
        bool "Create IMA machine owner blacklist keyrings (EXPERIMENTAL)"
        depends on SYSTEM_TRUSTED_KEYRING
-       depends on IMA_TRUSTED_KEYRING
+       depends on INTEGRITY_TRUSTED_KEYRING
        default n
        help
           This option creates an IMA blacklist keyring, which contains all
@@ -279,7 +273,7 @@ config IMA_BLACKLIST_KEYRING
 
 config IMA_LOAD_X509
        bool "Load X509 certificate onto the '.ima' trusted keyring"
-       depends on IMA_TRUSTED_KEYRING
+       depends on INTEGRITY_TRUSTED_KEYRING
        default n
        help
           File signature verification is based on the public keys
@@ -304,7 +298,6 @@ config IMA_APPRAISE_SIGNED_INIT
 
 config IMA_MEASURE_ASYMMETRIC_KEYS
        bool
-       depends on IMA
        depends on ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y
        default y
 
@@ -323,7 +316,8 @@ config IMA_SECURE_AND_OR_TRUSTED_BOOT
 
 config IMA_DISABLE_HTABLE
        bool "Disable htable to allow measurement of duplicate records"
-       depends on IMA
        default n
        help
           This option disables htable to allow measurement of duplicate records.
+
+endif
index c6fc50d..85fb5c2 100644 (file)
@@ -44,13 +44,12 @@ static const struct trusted_key_source trusted_key_sources[] = {
 #endif
 };
 
-DEFINE_STATIC_CALL_NULL(trusted_key_init, *trusted_key_sources[0].ops->init);
 DEFINE_STATIC_CALL_NULL(trusted_key_seal, *trusted_key_sources[0].ops->seal);
 DEFINE_STATIC_CALL_NULL(trusted_key_unseal,
                        *trusted_key_sources[0].ops->unseal);
 DEFINE_STATIC_CALL_NULL(trusted_key_get_random,
                        *trusted_key_sources[0].ops->get_random);
-DEFINE_STATIC_CALL_NULL(trusted_key_exit, *trusted_key_sources[0].ops->exit);
+static void (*trusted_key_exit)(void);
 static unsigned char migratable;
 
 enum {
@@ -359,19 +358,16 @@ static int __init init_trusted(void)
                if (!get_random)
                        get_random = kernel_get_random;
 
-               static_call_update(trusted_key_init,
-                                  trusted_key_sources[i].ops->init);
                static_call_update(trusted_key_seal,
                                   trusted_key_sources[i].ops->seal);
                static_call_update(trusted_key_unseal,
                                   trusted_key_sources[i].ops->unseal);
                static_call_update(trusted_key_get_random,
                                   get_random);
-               static_call_update(trusted_key_exit,
-                                  trusted_key_sources[i].ops->exit);
+               trusted_key_exit = trusted_key_sources[i].ops->exit;
                migratable = trusted_key_sources[i].ops->migratable;
 
-               ret = static_call(trusted_key_init)();
+               ret = trusted_key_sources[i].ops->init();
                if (!ret)
                        break;
        }
@@ -388,7 +384,8 @@ static int __init init_trusted(void)
 
 static void __exit cleanup_trusted(void)
 {
-       static_call_cond(trusted_key_exit)();
+       if (trusted_key_exit)
+               (*trusted_key_exit)();
 }
 
 late_initcall(init_trusted);
index d61bde1..22c0d21 100644 (file)
@@ -278,9 +278,6 @@ static int snd_card_init(struct snd_card *card, struct device *parent,
                         size_t extra_size)
 {
        int err;
-#ifdef CONFIG_SND_DEBUG
-       char name[8];
-#endif
 
        if (extra_size > 0)
                card->private_data = (char *)card + sizeof(struct snd_card);
@@ -364,8 +361,8 @@ static int snd_card_init(struct snd_card *card, struct device *parent,
        }
 
 #ifdef CONFIG_SND_DEBUG
-       sprintf(name, "card%d", idx);
-       card->debugfs_root = debugfs_create_dir(name, sound_debugfs_root);
+       card->debugfs_root = debugfs_create_dir(dev_name(&card->card_dev),
+                                               sound_debugfs_root);
 #endif
        return 0;
 
index ba06484..1431cb9 100644 (file)
@@ -1770,7 +1770,7 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry,
        if (IS_ENABLED(CONFIG_SND_UMP))
                snd_iprintf(buffer, "Type: %s\n",
                            rawmidi_is_ump(rmidi) ? "UMP" : "Legacy");
-       if (rmidi->ops->proc_read)
+       if (rmidi->ops && rmidi->ops->proc_read)
                rmidi->ops->proc_read(entry, buffer);
        mutex_lock(&rmidi->open_mutex);
        if (rmidi->info_flags & SNDRV_RAWMIDI_INFO_OUTPUT) {
index 44302d9..18320a2 100644 (file)
@@ -349,9 +349,9 @@ snd_seq_midisynth_probe(struct device *_dev)
                if (! port->name[0]) {
                        if (info->name[0]) {
                                if (ports > 1)
-                                       snprintf(port->name, sizeof(port->name), "%s-%u", info->name, p);
+                                       scnprintf(port->name, sizeof(port->name), "%s-%u", info->name, p);
                                else
-                                       snprintf(port->name, sizeof(port->name), "%s", info->name);
+                                       scnprintf(port->name, sizeof(port->name), "%s", info->name);
                        } else {
                                /* last resort */
                                if (ports > 1)
index f26a181..2db371d 100644 (file)
@@ -207,7 +207,7 @@ static void fill_port_info(struct snd_seq_port_info *port,
                SNDRV_SEQ_PORT_TYPE_PORT;
        port->midi_channels = 16;
        if (*group->name)
-               snprintf(port->name, sizeof(port->name), "Group %d (%s)",
+               snprintf(port->name, sizeof(port->name), "Group %d (%.53s)",
                         group->group + 1, group->name);
        else
                sprintf(port->name, "Group %d", group->group + 1);
@@ -416,6 +416,25 @@ static void setup_client_midi_version(struct seq_ump_client *client)
        snd_seq_kernel_client_put(cptr);
 }
 
+/* set up client's group_filter bitmap */
+static void setup_client_group_filter(struct seq_ump_client *client)
+{
+       struct snd_seq_client *cptr;
+       unsigned int filter;
+       int p;
+
+       cptr = snd_seq_kernel_client_get(client->seq_client);
+       if (!cptr)
+               return;
+       filter = ~(1U << 0); /* always allow groupless messages */
+       for (p = 0; p < SNDRV_UMP_MAX_GROUPS; p++) {
+               if (client->groups[p].active)
+                       filter &= ~(1U << (p + 1));
+       }
+       cptr->group_filter = filter;
+       snd_seq_kernel_client_put(cptr);
+}
+
 /* UMP group change notification */
 static void handle_group_notify(struct work_struct *work)
 {
@@ -424,6 +443,7 @@ static void handle_group_notify(struct work_struct *work)
 
        update_group_attrs(client);
        update_port_infos(client);
+       setup_client_group_filter(client);
 }
 
 /* UMP FB change notification */
@@ -492,6 +512,8 @@ static int snd_seq_ump_probe(struct device *_dev)
                        goto error;
        }
 
+       setup_client_group_filter(client);
+
        err = create_ump_endpoint_port(client);
        if (err < 0)
                goto error;
index 7cc84e1..b141024 100644 (file)
@@ -1197,6 +1197,8 @@ int snd_seq_deliver_to_ump(struct snd_seq_client *source,
                           struct snd_seq_event *event,
                           int atomic, int hop)
 {
+       if (dest->group_filter & (1U << dest_port->ump_group))
+               return 0; /* group filtered - skip the event */
        if (event->type == SNDRV_SEQ_EVENT_SYSEX)
                return cvt_sysex_to_ump(dest, dest_port, event, atomic, hop);
        else if (snd_seq_client_is_midi2(dest))
index 6f597d0..b1425bf 100644 (file)
@@ -84,9 +84,9 @@ static void set_midi_substream_names(struct snd_bebob *bebob,
        struct snd_rawmidi_substream *subs;
 
        list_for_each_entry(subs, &str->substreams, list) {
-               snprintf(subs->name, sizeof(subs->name),
-                        "%s MIDI %d",
-                        bebob->card->shortname, subs->number + 1);
+               scnprintf(subs->name, sizeof(subs->name),
+                         "%s MIDI %d",
+                         bebob->card->shortname, subs->number + 1);
        }
 }
 
index 4c29980..78988e4 100644 (file)
@@ -88,8 +88,8 @@ static void set_midi_substream_names(struct snd_dice *dice,
        struct snd_rawmidi_substream *subs;
 
        list_for_each_entry(subs, &str->substreams, list) {
-               snprintf(subs->name, sizeof(subs->name),
-                        "%s MIDI %d", dice->card->shortname, subs->number + 1);
+               scnprintf(subs->name, sizeof(subs->name),
+                         "%s MIDI %d", dice->card->shortname, subs->number + 1);
        }
 }
 
index 68eb8c3..8f4bace 100644 (file)
@@ -100,14 +100,14 @@ static void set_substream_names(struct snd_dg00x *dg00x,
 
                list_for_each_entry(subs, &str->substreams, list) {
                        if (!is_console) {
-                               snprintf(subs->name, sizeof(subs->name),
-                                        "%s MIDI %d",
-                                        dg00x->card->shortname,
-                                        subs->number + 1);
+                               scnprintf(subs->name, sizeof(subs->name),
+                                         "%s MIDI %d",
+                                         dg00x->card->shortname,
+                                         subs->number + 1);
                        } else {
-                               snprintf(subs->name, sizeof(subs->name),
-                                        "%s control",
-                                        dg00x->card->shortname);
+                               scnprintf(subs->name, sizeof(subs->name),
+                                         "%s control",
+                                         dg00x->card->shortname);
                        }
                }
        }
index 25821d1..da3054f 100644 (file)
@@ -79,8 +79,8 @@ static void set_midi_substream_names(struct snd_rawmidi_str *stream,
        struct snd_rawmidi_substream *substream;
 
        list_for_each_entry(substream, &stream->substreams, list) {
-               snprintf(substream->name, sizeof(substream->name),
-                        "%s MIDI %d", name, substream->number + 1);
+               scnprintf(substream->name, sizeof(substream->name),
+                         "%s MIDI %d", name, substream->number + 1);
        }
 }
 
index dd42988..e3ed4e0 100644 (file)
@@ -93,11 +93,11 @@ get_hardware_info(struct snd_efw *efw)
        strcpy(efw->card->driver, "Fireworks");
        strcpy(efw->card->shortname, hwinfo->model_name);
        strcpy(efw->card->mixername, hwinfo->model_name);
-       snprintf(efw->card->longname, sizeof(efw->card->longname),
-                "%s %s v%s, GUID %08x%08x at %s, S%d",
-                hwinfo->vendor_name, hwinfo->model_name, version,
-                hwinfo->guid_hi, hwinfo->guid_lo,
-                dev_name(&efw->unit->device), 100 << fw_dev->max_speed);
+       scnprintf(efw->card->longname, sizeof(efw->card->longname),
+                 "%s %s v%s, GUID %08x%08x at %s, S%d",
+                 hwinfo->vendor_name, hwinfo->model_name, version,
+                 hwinfo->guid_hi, hwinfo->guid_lo,
+                 dev_name(&efw->unit->device), 100 << fw_dev->max_speed);
 
        if (hwinfo->flags & BIT(FLAG_RESP_ADDR_CHANGABLE))
                efw->resp_addr_changable = true;
index 84621e3..350bf4d 100644 (file)
@@ -84,8 +84,8 @@ static void set_midi_substream_names(struct snd_efw *efw,
        struct snd_rawmidi_substream *subs;
 
        list_for_each_entry(subs, &str->substreams, list) {
-               snprintf(subs->name, sizeof(subs->name),
-                        "%s MIDI %d", efw->card->shortname, subs->number + 1);
+               scnprintf(subs->name, sizeof(subs->name),
+                         "%s MIDI %d", efw->card->shortname, subs->number + 1);
        }
 }
 
index 2365f7d..eebc7e7 100644 (file)
@@ -88,8 +88,8 @@ static void set_midi_substream_names(struct snd_motu *motu,
        struct snd_rawmidi_substream *subs;
 
        list_for_each_entry(subs, &str->substreams, list) {
-               snprintf(subs->name, sizeof(subs->name),
-                        "%s MIDI %d", motu->card->shortname, subs->number + 1);
+               scnprintf(subs->name, sizeof(subs->name),
+                         "%s MIDI %d", motu->card->shortname, subs->number + 1);
        }
 }
 
index 775cba3..c215fa6 100644 (file)
@@ -129,9 +129,9 @@ static void set_midi_substream_names(struct snd_oxfw *oxfw,
        struct snd_rawmidi_substream *subs;
 
        list_for_each_entry(subs, &str->substreams, list) {
-               snprintf(subs->name, sizeof(subs->name),
-                        "%s MIDI %d",
-                        oxfw->card->shortname, subs->number + 1);
+               scnprintf(subs->name, sizeof(subs->name),
+                         "%s MIDI %d",
+                         oxfw->card->shortname, subs->number + 1);
        }
 }
 
index 63d40f1..241a697 100644 (file)
@@ -108,11 +108,11 @@ static int name_card(struct snd_oxfw *oxfw, const struct ieee1394_device_id *ent
        strcpy(oxfw->card->mixername, m);
        strcpy(oxfw->card->shortname, m);
 
-       snprintf(oxfw->card->longname, sizeof(oxfw->card->longname),
-                "%s %s (OXFW%x %04x), GUID %08x%08x at %s, S%d",
-                v, m, firmware >> 20, firmware & 0xffff,
-                fw_dev->config_rom[3], fw_dev->config_rom[4],
-                dev_name(&oxfw->unit->device), 100 << fw_dev->max_speed);
+       scnprintf(oxfw->card->longname, sizeof(oxfw->card->longname),
+                 "%s %s (OXFW%x %04x), GUID %08x%08x at %s, S%d",
+                 v, m, firmware >> 20, firmware & 0xffff,
+                 fw_dev->config_rom[3], fw_dev->config_rom[4],
+                 dev_name(&oxfw->unit->device), 100 << fw_dev->max_speed);
 end:
        return err;
 }
index 02eed2d..c57fac4 100644 (file)
@@ -108,9 +108,9 @@ int snd_tscm_create_midi_devices(struct snd_tscm *tscm)
                /* TODO: support virtual MIDI ports. */
                if (subs->number < tscm->spec->midi_capture_ports) {
                        /* Hardware MIDI ports. */
-                       snprintf(subs->name, sizeof(subs->name),
-                                "%s MIDI %d",
-                                tscm->card->shortname, subs->number + 1);
+                       scnprintf(subs->name, sizeof(subs->name),
+                                 "%s MIDI %d",
+                                 tscm->card->shortname, subs->number + 1);
                }
        }
 
@@ -123,9 +123,9 @@ int snd_tscm_create_midi_devices(struct snd_tscm *tscm)
        list_for_each_entry(subs, &stream->substreams, list) {
                if (subs->number < tscm->spec->midi_playback_ports) {
                        /* Hardware MIDI ports only. */
-                       snprintf(subs->name, sizeof(subs->name),
-                                "%s MIDI %d",
-                                tscm->card->shortname, subs->number + 1);
+                       scnprintf(subs->name, sizeof(subs->name),
+                                 "%s MIDI %d",
+                                 tscm->card->shortname, subs->number + 1);
                }
        }
 
index 5cb92f7..b57d72e 100644 (file)
@@ -23,7 +23,7 @@ static int ctrl_link_mask;
 module_param_named(sdw_link_mask, ctrl_link_mask, int, 0444);
 MODULE_PARM_DESC(sdw_link_mask, "Intel link mask (one bit per link)");
 
-static bool is_link_enabled(struct fwnode_handle *fw_node, int i)
+static bool is_link_enabled(struct fwnode_handle *fw_node, u8 idx)
 {
        struct fwnode_handle *link;
        char name[32];
@@ -31,7 +31,7 @@ static bool is_link_enabled(struct fwnode_handle *fw_node, int i)
 
        /* Find master handle */
        snprintf(name, sizeof(name),
-                "mipi-sdw-link-%d-subproperties", i);
+                "mipi-sdw-link-%hhu-subproperties", idx);
 
        link = fwnode_get_named_child_node(fw_node, name);
        if (!link)
@@ -51,8 +51,8 @@ static int
 sdw_intel_scan_controller(struct sdw_intel_acpi_info *info)
 {
        struct acpi_device *adev = acpi_fetch_acpi_dev(info->handle);
-       int ret, i;
-       u8 count;
+       u8 count, i;
+       int ret;
 
        if (!adev)
                return -EINVAL;
index c471ac2..401d8df 100644 (file)
@@ -96,13 +96,13 @@ static int snd_ad1848_probe(struct device *dev, unsigned int n)
        strscpy(card->shortname, chip->pcm->name, sizeof(card->shortname));
 
        if (!thinkpad[n])
-               snprintf(card->longname, sizeof(card->longname),
-                        "%s at 0x%lx, irq %d, dma %d",
-                        chip->pcm->name, chip->port, irq[n], dma1[n]);
+               scnprintf(card->longname, sizeof(card->longname),
+                         "%s at 0x%lx, irq %d, dma %d",
+                         chip->pcm->name, chip->port, irq[n], dma1[n]);
        else
-               snprintf(card->longname, sizeof(card->longname),
-                        "%s at 0x%lx, irq %d, dma %d [Thinkpad]",
-                        chip->pcm->name, chip->port, irq[n], dma1[n]);
+               scnprintf(card->longname, sizeof(card->longname),
+                         "%s at 0x%lx, irq %d, dma %d [Thinkpad]",
+                         chip->pcm->name, chip->port, irq[n], dma1[n]);
 
        error = snd_card_register(card);
        if (error < 0)
index 1e89233..c87be4b 100644 (file)
@@ -98,13 +98,13 @@ static int snd_cs4231_probe(struct device *dev, unsigned int n)
        strscpy(card->shortname, chip->pcm->name, sizeof(card->shortname));
 
        if (dma2[n] < 0)
-               snprintf(card->longname, sizeof(card->longname),
-                        "%s at 0x%lx, irq %d, dma %d",
-                        chip->pcm->name, chip->port, irq[n], dma1[n]);
+               scnprintf(card->longname, sizeof(card->longname),
+                         "%s at 0x%lx, irq %d, dma %d",
+                         chip->pcm->name, chip->port, irq[n], dma1[n]);
        else
-               snprintf(card->longname, sizeof(card->longname),
-                        "%s at 0x%lx, irq %d, dma %d&%d",
-                        chip->pcm->name, chip->port, irq[n], dma1[n], dma2[n]);
+               scnprintf(card->longname, sizeof(card->longname),
+                         "%s at 0x%lx, irq %d, dma %d&%d",
+                         chip->pcm->name, chip->port, irq[n], dma1[n], dma2[n]);
 
        error = snd_wss_mixer(chip);
        if (error < 0)
index 10112e1..7226cbf 100644 (file)
@@ -367,14 +367,14 @@ static int snd_cs423x_probe(struct snd_card *card, int dev)
        strscpy(card->driver, chip->pcm->name, sizeof(card->driver));
        strscpy(card->shortname, chip->pcm->name, sizeof(card->shortname));
        if (dma2[dev] < 0)
-               snprintf(card->longname, sizeof(card->longname),
-                        "%s at 0x%lx, irq %i, dma %i",
-                        chip->pcm->name, chip->port, irq[dev], dma1[dev]);
+               scnprintf(card->longname, sizeof(card->longname),
+                         "%s at 0x%lx, irq %i, dma %i",
+                         chip->pcm->name, chip->port, irq[dev], dma1[dev]);
        else
-               snprintf(card->longname, sizeof(card->longname),
-                        "%s at 0x%lx, irq %i, dma %i&%d",
-                        chip->pcm->name, chip->port, irq[dev], dma1[dev],
-                        dma2[dev]);
+               scnprintf(card->longname, sizeof(card->longname),
+                         "%s at 0x%lx, irq %i, dma %i&%d",
+                         chip->pcm->name, chip->port, irq[dev], dma1[dev],
+                         dma2[dev]);
 
        err = snd_wss_timer(chip, 0);
        if (err < 0)
index f935b56..97728bf 100644 (file)
@@ -130,9 +130,9 @@ static int snd_es1688_probe(struct snd_card *card, unsigned int n)
 
        strscpy(card->driver, "ES1688", sizeof(card->driver));
        strscpy(card->shortname, chip->pcm->name, sizeof(card->shortname));
-       snprintf(card->longname, sizeof(card->longname),
-               "%s at 0x%lx, irq %i, dma %i", chip->pcm->name, chip->port,
-                chip->irq, chip->dma8);
+       scnprintf(card->longname, sizeof(card->longname),
+                 "%s at 0x%lx, irq %i, dma %i", chip->pcm->name, chip->port,
+                 chip->irq, chip->dma8);
 
        if (fm_port[n] == SNDRV_AUTO_PORT)
                fm_port[n] = port[n];   /* share the same port */
index 59242ba..59792f2 100644 (file)
@@ -1344,10 +1344,10 @@ static int snd_miro_probe(struct snd_card *card)
        }
 
        strcpy(card->driver, "miro");
-       snprintf(card->longname, sizeof(card->longname),
-                "%s: OPTi%s, %s at 0x%lx, irq %d, dma %d&%d",
-                card->shortname, miro->name, codec->pcm->name,
-                miro->wss_base + 4, miro->irq, miro->dma1, miro->dma2);
+       scnprintf(card->longname, sizeof(card->longname),
+                 "%s: OPTi%s, %s at 0x%lx, irq %d, dma %d&%d",
+                 card->shortname, miro->name, codec->pcm->name,
+                 miro->wss_base + 4, miro->irq, miro->dma1, miro->dma2);
 
        if (mpu_port <= 0 || mpu_port == SNDRV_AUTO_PORT)
                rmidi = NULL;
index 4beeb32..c33f67d 100644 (file)
@@ -859,15 +859,15 @@ static int snd_opti9xx_probe(struct snd_card *card)
        strcpy(card->driver, chip->name);
        sprintf(card->shortname, "OPTi %s", card->driver);
 #if defined(CS4231) || defined(OPTi93X)
-       snprintf(card->longname, sizeof(card->longname),
-                "%s, %s at 0x%lx, irq %d, dma %d&%d",
-                card->shortname, codec->pcm->name,
-                chip->wss_base + 4, irq, dma1, xdma2);
+       scnprintf(card->longname, sizeof(card->longname),
+                 "%s, %s at 0x%lx, irq %d, dma %d&%d",
+                 card->shortname, codec->pcm->name,
+                 chip->wss_base + 4, irq, dma1, xdma2);
 #else
-       snprintf(card->longname, sizeof(card->longname),
-                "%s, %s at 0x%lx, irq %d, dma %d",
-                card->shortname, codec->pcm->name, chip->wss_base + 4, irq,
-                dma1);
+       scnprintf(card->longname, sizeof(card->longname),
+                 "%s, %s at 0x%lx, irq %d, dma %d",
+                 card->shortname, codec->pcm->name, chip->wss_base + 4, irq,
+                 dma1);
 #endif /* CS4231 || OPTi93X */
 
        if (mpu_port <= 0 || mpu_port == SNDRV_AUTO_PORT)
index 0bc0025..cc56faf 100644 (file)
@@ -557,7 +557,7 @@ static int sscape_upload_microcode(struct snd_card *card, int version)
        char name[14];
        int err;
 
-       snprintf(name, sizeof(name), "sndscape.co%d", version);
+       scnprintf(name, sizeof(name), "sndscape.co%d", version);
 
        err = request_firmware(&init_fw, name, card->dev);
        if (err < 0) {
index 1415baa..08e34b1 100644 (file)
@@ -3102,11 +3102,13 @@ static int snd_cmipci_create(struct snd_card *card, struct pci_dev *pci,
        }
        sprintf(card->shortname, "C-Media CMI%d", val);
        if (cm->chip_version < 68)
-               sprintf(modelstr, " (model %d)", cm->chip_version);
+               scnprintf(modelstr, sizeof(modelstr),
+                         " (model %d)", cm->chip_version);
        else
                modelstr[0] = '\0';
-       sprintf(card->longname, "%s%s at %#lx, irq %i",
-               card->shortname, modelstr, cm->iobase, cm->irq);
+       scnprintf(card->longname, sizeof(card->longname),
+                 "%s%s at %#lx, irq %i",
+                 card->shortname, modelstr, cm->iobase, cm->irq);
 
        if (cm->chip_version >= 39) {
                val = snd_cmipci_read_b(cm, CM_REG_MPU_PCI + 1);
index f9b7735..c6031f7 100644 (file)
@@ -185,10 +185,14 @@ static int cs35l41_request_firmware_files_spkid(struct cs35l41_hda *cs35l41,
                                            cs35l41->speaker_id, "wmfw");
        if (!ret) {
                /* try cirrus/part-dspN-fwtype-sub<-spkidN><-ampname>.bin */
-               return cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
-                                                    CS35L41_FIRMWARE_ROOT,
-                                                    cs35l41->acpi_subsystem_id, cs35l41->amp_name,
-                                                    cs35l41->speaker_id, "bin");
+               ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
+                                                   CS35L41_FIRMWARE_ROOT,
+                                                   cs35l41->acpi_subsystem_id, cs35l41->amp_name,
+                                                   cs35l41->speaker_id, "bin");
+               if (ret)
+                       goto coeff_err;
+
+               return 0;
        }
 
        /* try cirrus/part-dspN-fwtype-sub<-ampname>.wmfw */
@@ -197,10 +201,14 @@ static int cs35l41_request_firmware_files_spkid(struct cs35l41_hda *cs35l41,
                                            cs35l41->amp_name, -1, "wmfw");
        if (!ret) {
                /* try cirrus/part-dspN-fwtype-sub<-spkidN><-ampname>.bin */
-               return cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
-                                                    CS35L41_FIRMWARE_ROOT,
-                                                    cs35l41->acpi_subsystem_id, cs35l41->amp_name,
-                                                    cs35l41->speaker_id, "bin");
+               ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
+                                                   CS35L41_FIRMWARE_ROOT,
+                                                   cs35l41->acpi_subsystem_id, cs35l41->amp_name,
+                                                   cs35l41->speaker_id, "bin");
+               if (ret)
+                       goto coeff_err;
+
+               return 0;
        }
 
        /* try cirrus/part-dspN-fwtype-sub<-spkidN>.wmfw */
@@ -215,10 +223,14 @@ static int cs35l41_request_firmware_files_spkid(struct cs35l41_hda *cs35l41,
                                                    cs35l41->amp_name, cs35l41->speaker_id, "bin");
                if (ret)
                        /* try cirrus/part-dspN-fwtype-sub<-spkidN>.bin */
-                       return cs35l41_request_firmware_file(cs35l41, coeff_firmware,
-                                                            coeff_filename, CS35L41_FIRMWARE_ROOT,
-                                                            cs35l41->acpi_subsystem_id, NULL,
-                                                            cs35l41->speaker_id, "bin");
+                       ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware,
+                                                           coeff_filename, CS35L41_FIRMWARE_ROOT,
+                                                           cs35l41->acpi_subsystem_id, NULL,
+                                                           cs35l41->speaker_id, "bin");
+               if (ret)
+                       goto coeff_err;
+
+               return 0;
        }
 
        /* try cirrus/part-dspN-fwtype-sub.wmfw */
@@ -233,12 +245,50 @@ static int cs35l41_request_firmware_files_spkid(struct cs35l41_hda *cs35l41,
                                                    cs35l41->speaker_id, "bin");
                if (ret)
                        /* try cirrus/part-dspN-fwtype-sub<-spkidN>.bin */
-                       return cs35l41_request_firmware_file(cs35l41, coeff_firmware,
-                                                            coeff_filename, CS35L41_FIRMWARE_ROOT,
-                                                            cs35l41->acpi_subsystem_id, NULL,
-                                                            cs35l41->speaker_id, "bin");
+                       ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware,
+                                                           coeff_filename, CS35L41_FIRMWARE_ROOT,
+                                                           cs35l41->acpi_subsystem_id, NULL,
+                                                           cs35l41->speaker_id, "bin");
+               if (ret)
+                       goto coeff_err;
+       }
+
+       return ret;
+coeff_err:
+       release_firmware(*wmfw_firmware);
+       kfree(*wmfw_filename);
+       return ret;
+}
+
+static int cs35l41_fallback_firmware_file(struct cs35l41_hda *cs35l41,
+                                         const struct firmware **wmfw_firmware,
+                                         char **wmfw_filename,
+                                         const struct firmware **coeff_firmware,
+                                         char **coeff_filename)
+{
+       int ret;
+
+       /* Handle fallback */
+       dev_warn(cs35l41->dev, "Falling back to default firmware.\n");
+
+       /* fallback try cirrus/part-dspN-fwtype.wmfw */
+       ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
+                                           CS35L41_FIRMWARE_ROOT, NULL, NULL, -1, "wmfw");
+       if (ret)
+               goto err;
+
+       /* fallback try cirrus/part-dspN-fwtype.bin */
+       ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
+                                           CS35L41_FIRMWARE_ROOT, NULL, NULL, -1, "bin");
+       if (ret) {
+               release_firmware(*wmfw_firmware);
+               kfree(*wmfw_filename);
+               goto err;
        }
+       return 0;
 
+err:
+       dev_warn(cs35l41->dev, "Unable to find firmware and tuning\n");
        return ret;
 }
 
@@ -254,7 +304,6 @@ static int cs35l41_request_firmware_files(struct cs35l41_hda *cs35l41,
                ret = cs35l41_request_firmware_files_spkid(cs35l41, wmfw_firmware, wmfw_filename,
                                                           coeff_firmware, coeff_filename);
                goto out;
-
        }
 
        /* try cirrus/part-dspN-fwtype-sub<-ampname>.wmfw */
@@ -267,6 +316,9 @@ static int cs35l41_request_firmware_files(struct cs35l41_hda *cs35l41,
                                                    CS35L41_FIRMWARE_ROOT,
                                                    cs35l41->acpi_subsystem_id, cs35l41->amp_name,
                                                    -1, "bin");
+               if (ret)
+                       goto coeff_err;
+
                goto out;
        }
 
@@ -286,32 +338,23 @@ static int cs35l41_request_firmware_files(struct cs35l41_hda *cs35l41,
                                                            CS35L41_FIRMWARE_ROOT,
                                                            cs35l41->acpi_subsystem_id, NULL, -1,
                                                            "bin");
+               if (ret)
+                       goto coeff_err;
        }
 
 out:
-       if (!ret)
-               return 0;
+       if (ret)
+               /* if all attempts at finding firmware fail, try fallback */
+               goto fallback;
 
-       /* Handle fallback */
-       dev_warn(cs35l41->dev, "Falling back to default firmware.\n");
+       return 0;
 
+coeff_err:
        release_firmware(*wmfw_firmware);
        kfree(*wmfw_filename);
-
-       /* fallback try cirrus/part-dspN-fwtype.wmfw */
-       ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
-                                           CS35L41_FIRMWARE_ROOT, NULL, NULL, -1, "wmfw");
-       if (!ret)
-               /* fallback try cirrus/part-dspN-fwtype.bin */
-               ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
-                                                   CS35L41_FIRMWARE_ROOT, NULL, NULL, -1, "bin");
-
-       if (ret) {
-               release_firmware(*wmfw_firmware);
-               kfree(*wmfw_filename);
-               dev_warn(cs35l41->dev, "Unable to find firmware and tuning\n");
-       }
-       return ret;
+fallback:
+       return cs35l41_fallback_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
+                                             coeff_firmware, coeff_filename);
 }
 
 #if IS_ENABLED(CONFIG_EFI)
index 76b9c68..7adc1d3 100644 (file)
@@ -105,7 +105,7 @@ static void cs35l56_hda_playback_hook(struct device *dev, int action)
        }
 }
 
-static int __maybe_unused cs35l56_hda_runtime_suspend(struct device *dev)
+static int cs35l56_hda_runtime_suspend(struct device *dev)
 {
        struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
 
@@ -115,7 +115,7 @@ static int __maybe_unused cs35l56_hda_runtime_suspend(struct device *dev)
        return cs35l56_runtime_suspend_common(&cs35l56->base);
 }
 
-static int __maybe_unused cs35l56_hda_runtime_resume(struct device *dev)
+static int cs35l56_hda_runtime_resume(struct device *dev)
 {
        struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
        int ret;
@@ -218,7 +218,7 @@ static int cs35l56_hda_posture_get(struct snd_kcontrol *kcontrol,
 
        ucontrol->value.integer.value[0] = pos;
 
-       return ret;
+       return 0;
 }
 
 static int cs35l56_hda_posture_put(struct snd_kcontrol *kcontrol,
@@ -865,15 +865,13 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int id)
        sub = acpi_get_subsystem_id(ACPI_HANDLE(cs35l56->base.dev));
 
        if (IS_ERR(sub)) {
-               /* If no ACPI SUB, return 0 and fallback to legacy firmware path, otherwise fail */
-               if (PTR_ERR(sub) == -ENODATA)
-                       return 0;
-               else
-                       return PTR_ERR(sub);
+               dev_info(cs35l56->base.dev,
+                        "Read ACPI _SUB failed(%ld): fallback to generic firmware\n",
+                        PTR_ERR(sub));
+       } else {
+               cs35l56->system_name = sub;
        }
 
-       cs35l56->system_name = sub;
-
        cs35l56->base.reset_gpio = devm_gpiod_get_index_optional(cs35l56->base.dev,
                                                                 "reset",
                                                                 cs35l56->index,
@@ -1003,6 +1001,7 @@ void cs35l56_hda_remove(struct device *dev)
 {
        struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
 
+       pm_runtime_dont_use_autosuspend(cs35l56->base.dev);
        pm_runtime_get_sync(cs35l56->base.dev);
        pm_runtime_disable(cs35l56->base.dev);
 
@@ -1016,7 +1015,7 @@ void cs35l56_hda_remove(struct device *dev)
 EXPORT_SYMBOL_NS_GPL(cs35l56_hda_remove, SND_HDA_SCODEC_CS35L56);
 
 const struct dev_pm_ops cs35l56_hda_pm_ops = {
-       SET_RUNTIME_PM_OPS(cs35l56_hda_runtime_suspend, cs35l56_hda_runtime_resume, NULL)
+       RUNTIME_PM_OPS(cs35l56_hda_runtime_suspend, cs35l56_hda_runtime_resume, NULL)
        SYSTEM_SLEEP_PM_OPS(cs35l56_hda_system_suspend, cs35l56_hda_system_resume)
        LATE_SYSTEM_SLEEP_PM_OPS(cs35l56_hda_system_suspend_late,
                                 cs35l56_hda_system_resume_early)
index 83e4acd..757a4d1 100644 (file)
@@ -21,7 +21,6 @@ static int cs35l56_hda_i2c_probe(struct i2c_client *clt)
                return -ENOMEM;
 
        cs35l56->base.dev = &clt->dev;
-       cs35l56->base.can_hibernate = true;
        cs35l56->base.regmap = devm_regmap_init_i2c(clt, &cs35l56_regmap_i2c);
        if (IS_ERR(cs35l56->base.regmap)) {
                ret = PTR_ERR(cs35l56->base.regmap);
index dbf7aa8..bf685d0 100644 (file)
@@ -998,7 +998,11 @@ static int add_control_with_pfx(struct hda_gen_spec *spec, int type,
                                const char *sfx, int cidx, unsigned long val)
 {
        char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
-       snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
+       int len;
+
+       len = snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
+       if (snd_BUG_ON(len >= sizeof(name)))
+               return -EINVAL;
        if (!add_control(spec, type, name, cidx, val))
                return -ENOMEM;
        return 0;
index 765d95e..ca765ac 100644 (file)
@@ -2211,6 +2211,7 @@ static const struct snd_pci_quirk power_save_denylist[] = {
        SND_PCI_QUIRK(0x8086, 0x2068, "Intel NUC7i3BNB", 0),
        /* https://bugzilla.kernel.org/show_bug.cgi?id=198611 */
        SND_PCI_QUIRK(0x17aa, 0x2227, "Lenovo X1 Carbon 3rd Gen", 0),
+       SND_PCI_QUIRK(0x17aa, 0x316e, "Lenovo ThinkCentre M70q", 0),
        /* https://bugzilla.redhat.com/show_bug.cgi?id=1689623 */
        SND_PCI_QUIRK(0x17aa, 0x367b, "Lenovo IdeaCentre B550", 0),
        /* https://bugzilla.redhat.com/show_bug.cgi?id=1572975 */
index b7e78bf..3eeecf6 100644 (file)
@@ -7073,8 +7073,10 @@ static void alc287_fixup_bind_dacs(struct hda_codec *codec,
        snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
        spec->gen.preferred_dacs = preferred_pairs;
        spec->gen.auto_mute_via_amp = 1;
-       snd_hda_codec_write_cache(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-                           0x0); /* Make sure 0x14 was disable */
+       if (spec->gen.autocfg.speaker_pins[0] != 0x14) {
+               snd_hda_codec_write_cache(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+                                       0x0); /* Make sure 0x14 was disable */
+       }
 }
 
 
@@ -7341,6 +7343,7 @@ enum {
        ALC245_FIXUP_HP_MUTE_LED_COEFBIT,
        ALC245_FIXUP_HP_X360_MUTE_LEDS,
        ALC287_FIXUP_THINKPAD_I2S_SPK,
+       ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD,
 };
 
 /* A special fixup for Lenovo C940 and Yoga Duet 7;
@@ -9439,6 +9442,12 @@ static const struct hda_fixup alc269_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc287_fixup_bind_dacs,
        },
+       [ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc287_fixup_bind_dacs,
+               .chained = true,
+               .chain_id = ALC287_FIXUP_CS35L41_I2C_2_THINKPAD_ACPI,
+       },
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -9812,7 +9821,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x1d1f, "ASUS ROG Strix G17 2023 (G713PV)", ALC287_FIXUP_CS35L41_I2C_2),
        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, 0x1e02, "ASUS UX3402", ALC245_FIXUP_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1043, 0x1e02, "ASUS UX3402ZA", ALC245_FIXUP_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS UX3402VA", ALC245_FIXUP_CS35L41_SPI_2),
        SND_PCI_QUIRK(0x1043, 0x1e11, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA502),
        SND_PCI_QUIRK(0x1043, 0x1e12, "ASUS UM3402", ALC287_FIXUP_CS35L41_I2C_2),
        SND_PCI_QUIRK(0x1043, 0x1e51, "ASUS Zephyrus M15", ALC294_FIXUP_ASUS_GU502_PINS),
@@ -9851,7 +9861,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x10ec, 0x124c, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
        SND_PCI_QUIRK(0x10ec, 0x1252, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
        SND_PCI_QUIRK(0x10ec, 0x1254, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
-       SND_PCI_QUIRK(0x10ec, 0x12cc, "Intel Reference board", ALC225_FIXUP_HEADSET_JACK),
+       SND_PCI_QUIRK(0x10ec, 0x12cc, "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_AMP),
@@ -9985,14 +9995,14 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x22be, "Thinkpad X1 Carbon 8th", ALC285_FIXUP_THINKPAD_HEADSET_JACK),
        SND_PCI_QUIRK(0x17aa, 0x22c1, "Thinkpad P1 Gen 3", ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK),
        SND_PCI_QUIRK(0x17aa, 0x22c2, "Thinkpad X1 Extreme Gen 3", ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK),
-       SND_PCI_QUIRK(0x17aa, 0x22f1, "Thinkpad", ALC287_FIXUP_CS35L41_I2C_2_THINKPAD_ACPI),
-       SND_PCI_QUIRK(0x17aa, 0x22f2, "Thinkpad", ALC287_FIXUP_CS35L41_I2C_2_THINKPAD_ACPI),
-       SND_PCI_QUIRK(0x17aa, 0x22f3, "Thinkpad", ALC287_FIXUP_CS35L41_I2C_2_THINKPAD_ACPI),
-       SND_PCI_QUIRK(0x17aa, 0x2316, "Thinkpad P1 Gen 6", ALC287_FIXUP_CS35L41_I2C_2_THINKPAD_ACPI),
-       SND_PCI_QUIRK(0x17aa, 0x2317, "Thinkpad P1 Gen 6", ALC287_FIXUP_CS35L41_I2C_2_THINKPAD_ACPI),
-       SND_PCI_QUIRK(0x17aa, 0x2318, "Thinkpad Z13 Gen2", ALC287_FIXUP_CS35L41_I2C_2_THINKPAD_ACPI),
-       SND_PCI_QUIRK(0x17aa, 0x2319, "Thinkpad Z16 Gen2", ALC287_FIXUP_CS35L41_I2C_2_THINKPAD_ACPI),
-       SND_PCI_QUIRK(0x17aa, 0x231a, "Thinkpad Z16 Gen2", ALC287_FIXUP_CS35L41_I2C_2_THINKPAD_ACPI),
+       SND_PCI_QUIRK(0x17aa, 0x22f1, "Thinkpad", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
+       SND_PCI_QUIRK(0x17aa, 0x22f2, "Thinkpad", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
+       SND_PCI_QUIRK(0x17aa, 0x22f3, "Thinkpad", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
+       SND_PCI_QUIRK(0x17aa, 0x2316, "Thinkpad P1 Gen 6", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
+       SND_PCI_QUIRK(0x17aa, 0x2317, "Thinkpad P1 Gen 6", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
+       SND_PCI_QUIRK(0x17aa, 0x2318, "Thinkpad Z13 Gen2", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
+       SND_PCI_QUIRK(0x17aa, 0x2319, "Thinkpad Z16 Gen2", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
+       SND_PCI_QUIRK(0x17aa, 0x231a, "Thinkpad Z16 Gen2", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
        SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
        SND_PCI_QUIRK(0x17aa, 0x30e2, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
        SND_PCI_QUIRK(0x17aa, 0x310c, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION),
@@ -10088,7 +10098,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x8086, 0x2074, "Intel NUC 8", ALC233_FIXUP_INTEL_NUC8_DMIC),
        SND_PCI_QUIRK(0x8086, 0x2080, "Intel NUC 8 Rugged", ALC256_FIXUP_INTEL_NUC8_RUGGED),
        SND_PCI_QUIRK(0x8086, 0x2081, "Intel NUC 10", ALC256_FIXUP_INTEL_NUC10),
-       SND_PCI_QUIRK(0x8086, 0x3038, "Intel NUC 13", ALC225_FIXUP_HEADSET_JACK),
+       SND_PCI_QUIRK(0x8086, 0x3038, "Intel NUC 13", ALC295_FIXUP_CHROME_BOOK),
        SND_PCI_QUIRK(0xf111, 0x0001, "Framework Laptop", ALC295_FIXUP_FRAMEWORK_LAPTOP_MIC_NO_PRESENCE),
 
 #if 0
@@ -10574,6 +10584,10 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
                {0x17, 0x90170110},
                {0x19, 0x03a11030},
                {0x21, 0x03211020}),
+       SND_HDA_PIN_QUIRK(0x10ec0287, 0x17aa, "Lenovo", ALC287_FIXUP_THINKPAD_I2S_SPK,
+               {0x17, 0x90170110}, /* 0x231f with RTK I2S AMP */
+               {0x19, 0x04a11040},
+               {0x21, 0x04211020}),
        SND_HDA_PIN_QUIRK(0x10ec0286, 0x1025, "Acer", ALC286_FIXUP_ACER_AIO_MIC_NO_PRESENCE,
                {0x12, 0x90a60130},
                {0x17, 0x90170110},
index b37c877..9dee034 100644 (file)
@@ -2105,15 +2105,15 @@ __snd_card_riptide_probe(struct pci_dev *pci, const struct pci_device_id *pci_id
        strcpy(card->driver, "RIPTIDE");
        strcpy(card->shortname, "Riptide");
 #ifdef SUPPORT_JOYSTICK
-       snprintf(card->longname, sizeof(card->longname),
-                "%s at 0x%lx, irq %i mpu 0x%x opl3 0x%x gameport 0x%x",
-                card->shortname, chip->port, chip->irq, chip->mpuaddr,
-                chip->opladdr, chip->gameaddr);
+       scnprintf(card->longname, sizeof(card->longname),
+                 "%s at 0x%lx, irq %i mpu 0x%x opl3 0x%x gameport 0x%x",
+                 card->shortname, chip->port, chip->irq, chip->mpuaddr,
+                 chip->opladdr, chip->gameaddr);
 #else
-       snprintf(card->longname, sizeof(card->longname),
-                "%s at 0x%lx, irq %i mpu 0x%x opl3 0x%x",
-                card->shortname, chip->port, chip->irq, chip->mpuaddr,
-                chip->opladdr);
+       scnprintf(card->longname, sizeof(card->longname),
+                 "%s at 0x%lx, irq %i mpu 0x%x opl3 0x%x",
+                 card->shortname, chip->port, chip->irq, chip->mpuaddr,
+                 chip->opladdr);
 #endif
        snd_riptide_proc_init(chip);
        err = snd_card_register(card);
index 3ec15b4..15a864d 100644 (file)
@@ -217,6 +217,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
                .driver_data = &acp6x_card,
                .matches = {
                        DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "82QF"),
+               }
+       },
+       {
+               .driver_data = &acp6x_card,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "82TL"),
                }
        },
@@ -224,12 +231,26 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
                .driver_data = &acp6x_card,
                .matches = {
                        DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "82UG"),
+               }
+       },
+       {
+               .driver_data = &acp6x_card,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "82V2"),
                }
        },
        {
                .driver_data = &acp6x_card,
                .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "82YM"),
+               }
+       },
+       {
+               .driver_data = &acp6x_card,
+               .matches = {
                        DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."),
                        DMI_MATCH(DMI_PRODUCT_NAME, "UM5302TA"),
                }
@@ -265,6 +286,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
        {
                .driver_data = &acp6x_card,
                .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Micro-Star International Co., Ltd."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Bravo 15 B7ED"),
+               }
+       },
+       {
+               .driver_data = &acp6x_card,
+               .matches = {
                        DMI_MATCH(DMI_BOARD_VENDOR, "Alienware"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m17 R5 AMD"),
                }
index 8ee1baa..87dd0cc 100644 (file)
@@ -452,11 +452,13 @@ static int aw_dev_parse_reg_bin_with_hdr(struct aw_device *aw_dev,
        if ((aw_bin->all_bin_parse_num != 1) ||
                (aw_bin->header_info[0].bin_data_type != DATA_TYPE_REGISTER)) {
                dev_err(aw_dev->dev, "bin num or type error");
+               ret = -EINVAL;
                goto parse_bin_failed;
        }
 
        if (aw_bin->header_info[0].valid_data_len % 4) {
                dev_err(aw_dev->dev, "bin data len get error!");
+               ret = -EINVAL;
                goto parse_bin_failed;
        }
 
index 9f4f2f4..d10e0e2 100644 (file)
@@ -27,7 +27,6 @@ static int cs35l56_i2c_probe(struct i2c_client *client)
                return -ENOMEM;
 
        cs35l56->base.dev = dev;
-       cs35l56->base.can_hibernate = true;
 
        i2c_set_clientdata(client, cs35l56);
        cs35l56->base.regmap = devm_regmap_init_i2c(client, regmap_config);
index 600b79c..f2e7c6d 100644 (file)
@@ -1207,6 +1207,7 @@ void cs35l56_remove(struct cs35l56_private *cs35l56)
        flush_workqueue(cs35l56->dsp_wq);
        destroy_workqueue(cs35l56->dsp_wq);
 
+       pm_runtime_dont_use_autosuspend(cs35l56->base.dev);
        pm_runtime_suspend(cs35l56->base.dev);
        pm_runtime_disable(cs35l56->base.dev);
 
index eeab07c..974bae4 100644 (file)
@@ -344,6 +344,16 @@ static int cs42l42_sdw_update_status(struct sdw_slave *peripheral,
        switch (status) {
        case SDW_SLAVE_ATTACHED:
                dev_dbg(cs42l42->dev, "ATTACHED\n");
+
+               /*
+                * The SoundWire core can report stale ATTACH notifications
+                * if we hard-reset CS42L42 in probe() but it had already been
+                * enumerated. Reject the ATTACH if we haven't yet seen an
+                * UNATTACH report for the device being in reset.
+                */
+               if (cs42l42->sdw_waiting_first_unattach)
+                       break;
+
                /*
                 * Initialise codec, this only needs to be done once.
                 * When resuming from suspend, resume callback will handle re-init of codec,
@@ -354,6 +364,16 @@ static int cs42l42_sdw_update_status(struct sdw_slave *peripheral,
                break;
        case SDW_SLAVE_UNATTACHED:
                dev_dbg(cs42l42->dev, "UNATTACHED\n");
+
+               if (cs42l42->sdw_waiting_first_unattach) {
+                       /*
+                        * SoundWire core has seen that CS42L42 is not on
+                        * the bus so release RESET and wait for ATTACH.
+                        */
+                       cs42l42->sdw_waiting_first_unattach = false;
+                       gpiod_set_value_cansleep(cs42l42->reset_gpio, 1);
+               }
+
                break;
        default:
                break;
index a0de032..2961340 100644 (file)
@@ -2320,7 +2320,26 @@ int cs42l42_common_probe(struct cs42l42_private *cs42l42,
 
        if (cs42l42->reset_gpio) {
                dev_dbg(cs42l42->dev, "Found reset GPIO\n");
-               gpiod_set_value_cansleep(cs42l42->reset_gpio, 1);
+
+               /*
+                * ACPI can override the default GPIO state we requested
+                * so ensure that we start with RESET low.
+                */
+               gpiod_set_value_cansleep(cs42l42->reset_gpio, 0);
+
+               /* Ensure minimum reset pulse width */
+               usleep_range(10, 500);
+
+               /*
+                * On SoundWire keep the chip in reset until we get an UNATTACH
+                * notification from the SoundWire core. This acts as a
+                * synchronization point to reject stale ATTACH notifications
+                * if the chip was already enumerated before we reset it.
+                */
+               if (cs42l42->sdw_peripheral)
+                       cs42l42->sdw_waiting_first_unattach = true;
+               else
+                       gpiod_set_value_cansleep(cs42l42->reset_gpio, 1);
        }
        usleep_range(CS42L42_BOOT_TIME_US, CS42L42_BOOT_TIME_US * 2);
 
index 4bd7b85..7785125 100644 (file)
@@ -53,6 +53,7 @@ struct  cs42l42_private {
        u8 stream_use;
        bool hp_adc_up_pending;
        bool suspended;
+       bool sdw_waiting_first_unattach;
        bool init_done;
 };
 
index 1a95c37..5643c66 100644 (file)
@@ -2077,7 +2077,8 @@ static const struct cs42l43_irq cs42l43_irqs[] = {
 
 static int cs42l43_request_irq(struct cs42l43_codec *priv,
                               struct irq_domain *dom, const char * const name,
-                              unsigned int irq, irq_handler_t handler)
+                              unsigned int irq, irq_handler_t handler,
+                              unsigned long flags)
 {
        int ret;
 
@@ -2087,8 +2088,8 @@ static int cs42l43_request_irq(struct cs42l43_codec *priv,
 
        dev_dbg(priv->dev, "Request IRQ %d for %s\n", ret, name);
 
-       ret = devm_request_threaded_irq(priv->dev, ret, NULL, handler, IRQF_ONESHOT,
-                                       name, priv);
+       ret = devm_request_threaded_irq(priv->dev, ret, NULL, handler,
+                                       IRQF_ONESHOT | flags, name, priv);
        if (ret)
                return dev_err_probe(priv->dev, ret, "Failed to request IRQ %s\n", name);
 
@@ -2124,11 +2125,11 @@ static int cs42l43_shutter_irq(struct cs42l43_codec *priv,
                return 0;
        }
 
-       ret = cs42l43_request_irq(priv, dom, close_name, close_irq, handler);
+       ret = cs42l43_request_irq(priv, dom, close_name, close_irq, handler, IRQF_SHARED);
        if (ret)
                return ret;
 
-       return cs42l43_request_irq(priv, dom, open_name, open_irq, handler);
+       return cs42l43_request_irq(priv, dom, open_name, open_irq, handler, IRQF_SHARED);
 }
 
 static int cs42l43_codec_probe(struct platform_device *pdev)
@@ -2178,7 +2179,8 @@ static int cs42l43_codec_probe(struct platform_device *pdev)
 
        for (i = 0; i < ARRAY_SIZE(cs42l43_irqs); i++) {
                ret = cs42l43_request_irq(priv, dom, cs42l43_irqs[i].name,
-                                         cs42l43_irqs[i].irq, cs42l43_irqs[i].handler);
+                                         cs42l43_irqs[i].irq,
+                                         cs42l43_irqs[i].handler, 0);
                if (ret)
                        goto err_pm;
        }
index 13689e7..09eef60 100644 (file)
@@ -531,7 +531,10 @@ static int hdmi_codec_fill_codec_params(struct snd_soc_dai *dai,
        hp->sample_rate = sample_rate;
        hp->channels = channels;
 
-       hcp->chmap_idx = idx;
+       if (pcm_audio)
+               hcp->chmap_idx = ca_id;
+       else
+               hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN;
 
        return 0;
 }
index 15e1a62..e8cdc16 100644 (file)
@@ -2403,13 +2403,11 @@ static irqreturn_t rt5640_irq(int irq, void *data)
        struct rt5640_priv *rt5640 = data;
        int delay = 0;
 
-       if (rt5640->jd_src == RT5640_JD_SRC_HDA_HEADER) {
-               cancel_delayed_work_sync(&rt5640->jack_work);
+       if (rt5640->jd_src == RT5640_JD_SRC_HDA_HEADER)
                delay = 100;
-       }
 
        if (rt5640->jack)
-               queue_delayed_work(system_long_wq, &rt5640->jack_work, delay);
+               mod_delayed_work(system_long_wq, &rt5640->jack_work, delay);
 
        return IRQ_HANDLED;
 }
@@ -2565,10 +2563,9 @@ static void rt5640_enable_jack_detect(struct snd_soc_component *component,
        if (jack_data && jack_data->use_platform_clock)
                rt5640->use_platform_clock = jack_data->use_platform_clock;
 
-       ret = devm_request_threaded_irq(component->dev, rt5640->irq,
-                                       NULL, rt5640_irq,
-                                       IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
-                                       "rt5640", rt5640);
+       ret = request_irq(rt5640->irq, rt5640_irq,
+                         IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+                         "rt5640", rt5640);
        if (ret) {
                dev_warn(component->dev, "Failed to request IRQ %d: %d\n", rt5640->irq, ret);
                rt5640_disable_jack_detect(component);
@@ -2621,14 +2618,14 @@ static void rt5640_enable_hda_jack_detect(
 
        rt5640->jack = jack;
 
-       ret = devm_request_threaded_irq(component->dev, rt5640->irq,
-                                       NULL, rt5640_irq, IRQF_TRIGGER_RISING | IRQF_ONESHOT,
-                                       "rt5640", rt5640);
+       ret = request_irq(rt5640->irq, rt5640_irq,
+                         IRQF_TRIGGER_RISING | IRQF_ONESHOT, "rt5640", rt5640);
        if (ret) {
                dev_warn(component->dev, "Failed to request IRQ %d: %d\n", rt5640->irq, ret);
-               rt5640->irq = -ENXIO;
+               rt5640->jack = NULL;
                return;
        }
+       rt5640->irq_requested = true;
 
        /* sync initial jack state */
        queue_delayed_work(system_long_wq, &rt5640->jack_work, 0);
@@ -2801,12 +2798,12 @@ static int rt5640_suspend(struct snd_soc_component *component)
 {
        struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
 
-       if (rt5640->irq) {
+       if (rt5640->jack) {
                /* disable jack interrupts during system suspend */
                disable_irq(rt5640->irq);
+               rt5640_cancel_work(rt5640);
        }
 
-       rt5640_cancel_work(rt5640);
        snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
        rt5640_reset(component);
        regcache_cache_only(rt5640->regmap, true);
@@ -2829,9 +2826,6 @@ static int rt5640_resume(struct snd_soc_component *component)
        regcache_cache_only(rt5640->regmap, false);
        regcache_sync(rt5640->regmap);
 
-       if (rt5640->irq)
-               enable_irq(rt5640->irq);
-
        if (rt5640->jack) {
                if (rt5640->jd_src == RT5640_JD_SRC_HDA_HEADER) {
                        snd_soc_component_update_bits(component,
@@ -2859,6 +2853,7 @@ static int rt5640_resume(struct snd_soc_component *component)
                        }
                }
 
+               enable_irq(rt5640->irq);
                queue_delayed_work(system_long_wq, &rt5640->jack_work, 0);
        }
 
index b05b4f7..fbad1ed 100644 (file)
@@ -157,11 +157,6 @@ static int rt5682_i2c_probe(struct i2c_client *i2c)
                return ret;
        }
 
-       ret = devm_add_action_or_reset(&i2c->dev, rt5682_i2c_disable_regulators,
-                                      rt5682);
-       if (ret)
-               return ret;
-
        ret = regulator_bulk_enable(ARRAY_SIZE(rt5682->supplies),
                                    rt5682->supplies);
        if (ret) {
@@ -169,6 +164,11 @@ static int rt5682_i2c_probe(struct i2c_client *i2c)
                return ret;
        }
 
+       ret = devm_add_action_or_reset(&i2c->dev, rt5682_i2c_disable_regulators,
+                                      rt5682);
+       if (ret)
+               return ret;
+
        ret = rt5682_get_ldo1(rt5682, &i2c->dev);
        if (ret)
                return ret;
index b976c19..420bbf5 100644 (file)
 #define ADC3XXX_BYPASS_RPGA            0x80
 
 /* MICBIAS control bits */
-#define ADC3XXX_MICBIAS_MASK           0x2
+#define ADC3XXX_MICBIAS_MASK           0x3
 #define ADC3XXX_MICBIAS1_SHIFT         5
 #define ADC3XXX_MICBIAS2_SHIFT         3
 
@@ -1099,7 +1099,7 @@ static int adc3xxx_parse_dt_micbias(struct adc3xxx *adc3xxx,
        unsigned int val;
 
        if (!of_property_read_u32(np, propname, &val)) {
-               if (val >= ADC3XXX_MICBIAS_AVDD) {
+               if (val > ADC3XXX_MICBIAS_AVDD) {
                        dev_err(dev, "Invalid property value for '%s'\n", propname);
                        return -EINVAL;
                }
index 0a50180..7689fe3 100644 (file)
@@ -1468,8 +1468,10 @@ static int wm8960_i2c_probe(struct i2c_client *i2c)
        }
 
        wm8960->regmap = devm_regmap_init_i2c(i2c, &wm8960_regmap);
-       if (IS_ERR(wm8960->regmap))
-               return PTR_ERR(wm8960->regmap);
+       if (IS_ERR(wm8960->regmap)) {
+               ret = PTR_ERR(wm8960->regmap);
+               goto bulk_disable;
+       }
 
        if (pdata)
                memcpy(&wm8960->pdata, pdata, sizeof(struct wm8960_data));
@@ -1479,13 +1481,14 @@ static int wm8960_i2c_probe(struct i2c_client *i2c)
        ret = i2c_master_recv(i2c, &val, sizeof(val));
        if (ret >= 0) {
                dev_err(&i2c->dev, "Not wm8960, wm8960 reg can not read by i2c\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto bulk_disable;
        }
 
        ret = wm8960_reset(wm8960->regmap);
        if (ret != 0) {
                dev_err(&i2c->dev, "Failed to issue reset\n");
-               return ret;
+               goto bulk_disable;
        }
 
        if (wm8960->pdata.shared_lrclk) {
@@ -1494,7 +1497,7 @@ static int wm8960_i2c_probe(struct i2c_client *i2c)
                if (ret != 0) {
                        dev_err(&i2c->dev, "Failed to enable LRCM: %d\n",
                                ret);
-                       return ret;
+                       goto bulk_disable;
                }
        }
 
@@ -1528,7 +1531,13 @@ static int wm8960_i2c_probe(struct i2c_client *i2c)
 
        ret = devm_snd_soc_register_component(&i2c->dev,
                        &soc_component_dev_wm8960, &wm8960_dai, 1);
+       if (ret)
+               goto bulk_disable;
 
+       return 0;
+
+bulk_disable:
+       regulator_bulk_disable(ARRAY_SIZE(wm8960->supplies), wm8960->supplies);
        return ret;
 }
 
index 6fc34f4..d1b9238 100644 (file)
@@ -687,7 +687,10 @@ int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type,
        struct wm_coeff_ctl *ctl;
        int ret;
 
+       mutex_lock(&dsp->cs_dsp.pwr_lock);
        ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, buf, len);
+       mutex_unlock(&dsp->cs_dsp.pwr_lock);
+
        if (ret < 0)
                return ret;
 
@@ -703,8 +706,14 @@ EXPORT_SYMBOL_GPL(wm_adsp_write_ctl);
 int wm_adsp_read_ctl(struct wm_adsp *dsp, const char *name, int type,
                     unsigned int alg, void *buf, size_t len)
 {
-       return cs_dsp_coeff_read_ctrl(cs_dsp_get_ctl(&dsp->cs_dsp, name, type, alg),
-                                     0, buf, len);
+       int ret;
+
+       mutex_lock(&dsp->cs_dsp.pwr_lock);
+       ret = cs_dsp_coeff_read_ctrl(cs_dsp_get_ctl(&dsp->cs_dsp, name, type, alg),
+                                    0, buf, len);
+       mutex_unlock(&dsp->cs_dsp.pwr_lock);
+
+       return ret;
 }
 EXPORT_SYMBOL_GPL(wm_adsp_read_ctl);
 
index 76b5bfc..bab7d34 100644 (file)
@@ -52,8 +52,8 @@ struct codec_priv {
        unsigned long mclk_freq;
        unsigned long free_freq;
        u32 mclk_id;
-       u32 fll_id;
-       u32 pll_id;
+       int fll_id;
+       int pll_id;
 };
 
 /**
@@ -206,7 +206,7 @@ static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream,
        }
 
        /* Specific configuration for PLL */
-       if (codec_priv->pll_id && codec_priv->fll_id) {
+       if (codec_priv->pll_id >= 0 && codec_priv->fll_id >= 0) {
                if (priv->sample_format == SNDRV_PCM_FORMAT_S24_LE)
                        pll_out = priv->sample_rate * 384;
                else
@@ -248,7 +248,7 @@ static int fsl_asoc_card_hw_free(struct snd_pcm_substream *substream)
 
        priv->streams &= ~BIT(substream->stream);
 
-       if (!priv->streams && codec_priv->pll_id && codec_priv->fll_id) {
+       if (!priv->streams && codec_priv->pll_id >= 0 && codec_priv->fll_id >= 0) {
                /* Force freq to be free_freq to avoid error message in codec */
                ret = snd_soc_dai_set_sysclk(asoc_rtd_to_codec(rtd, 0),
                                             codec_priv->mclk_id,
@@ -621,6 +621,10 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
        priv->card.dapm_routes = audio_map;
        priv->card.num_dapm_routes = ARRAY_SIZE(audio_map);
        priv->card.driver_name = DRIVER_NAME;
+
+       priv->codec_priv.fll_id = -1;
+       priv->codec_priv.pll_id = -1;
+
        /* Diversify the card configurations */
        if (of_device_is_compatible(np, "fsl,imx-audio-cs42888")) {
                codec_dai_name = "cs42888";
index 1e4020f..8a9a30d 100644 (file)
@@ -710,10 +710,15 @@ static void fsl_sai_config_disable(struct fsl_sai *sai, int dir)
 {
        unsigned int ofs = sai->soc_data->reg_offset;
        bool tx = dir == TX;
-       u32 xcsr, count = 100;
+       u32 xcsr, count = 100, mask;
+
+       if (sai->soc_data->mclk_with_tere && sai->mclk_direction_output)
+               mask = FSL_SAI_CSR_TERE;
+       else
+               mask = FSL_SAI_CSR_TERE | FSL_SAI_CSR_BCE;
 
        regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs),
-                          FSL_SAI_CSR_TERE | FSL_SAI_CSR_BCE, 0);
+                          mask, 0);
 
        /* TERE will remain set till the end of current frame */
        do {
index 0b58df5..aeb81aa 100644 (file)
@@ -315,7 +315,7 @@ static int imx_audmix_probe(struct platform_device *pdev)
        if (IS_ERR(priv->cpu_mclk)) {
                ret = PTR_ERR(priv->cpu_mclk);
                dev_err(&cpu_pdev->dev, "failed to get DAI mclk1: %d\n", ret);
-               return -EINVAL;
+               return ret;
        }
 
        priv->audmix_pdev = audmix_pdev;
index d63782b..bb736d4 100644 (file)
@@ -19,6 +19,7 @@
 static struct snd_pcm_hardware imx_rpmsg_pcm_hardware = {
        .info = SNDRV_PCM_INFO_INTERLEAVED |
                SNDRV_PCM_INFO_BLOCK_TRANSFER |
+               SNDRV_PCM_INFO_BATCH |
                SNDRV_PCM_INFO_MMAP |
                SNDRV_PCM_INFO_MMAP_VALID |
                SNDRV_PCM_INFO_NO_PERIOD_WAKEUP |
index 3c7b95d..b578f9a 100644 (file)
@@ -89,6 +89,14 @@ static int imx_rpmsg_probe(struct platform_device *pdev)
                            SND_SOC_DAIFMT_NB_NF |
                            SND_SOC_DAIFMT_CBC_CFC;
 
+       /*
+        * i.MX rpmsg sound cards work on codec slave mode. MCLK will be
+        * disabled by CPU DAI driver in hw_free(). Some codec requires MCLK
+        * present at power up/down sequence. So need to set ignore_pmdown_time
+        * to power down codec immediately before MCLK is turned off.
+        */
+       data->dai.ignore_pmdown_time = 1;
+
        /* Optional codec node */
        ret = of_parse_phandle_with_fixed_args(np, "audio-codec", 0, 0, &args);
        if (ret) {
index 5b18a4a..2588ec7 100644 (file)
@@ -310,7 +310,8 @@ int asoc_simple_startup(struct snd_pcm_substream *substream)
                if (fixed_sysclk % props->mclk_fs) {
                        dev_err(rtd->dev, "fixed sysclk %u not divisible by mclk_fs %u\n",
                                fixed_sysclk, props->mclk_fs);
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       goto codec_err;
                }
                ret = snd_pcm_hw_constraint_minmax(substream->runtime, SNDRV_PCM_HW_PARAM_RATE,
                        fixed_rate, fixed_rate);
index 190f113..274417e 100644 (file)
@@ -759,10 +759,12 @@ static int asoc_simple_probe(struct platform_device *pdev)
                struct snd_soc_dai_link *dai_link = priv->dai_link;
                struct simple_dai_props *dai_props = priv->dai_props;
 
+               ret = -EINVAL;
+
                cinfo = dev->platform_data;
                if (!cinfo) {
                        dev_err(dev, "no info for asoc-simple-card\n");
-                       return -EINVAL;
+                       goto err;
                }
 
                if (!cinfo->name ||
@@ -771,7 +773,7 @@ static int asoc_simple_probe(struct platform_device *pdev)
                    !cinfo->platform ||
                    !cinfo->cpu_dai.name) {
                        dev_err(dev, "insufficient asoc_simple_card_info settings\n");
-                       return -EINVAL;
+                       goto err;
                }
 
                cpus                    = dai_link->cpus;
index cb00bc8..8876558 100644 (file)
@@ -55,6 +55,9 @@ static int avs_create_dai_links(struct device *dev, struct hda_codec *codec, int
                        return -ENOMEM;
 
                dl[i].codecs->name = devm_kstrdup(dev, cname, GFP_KERNEL);
+               if (!dl[i].codecs->name)
+                       return -ENOMEM;
+
                dl[i].codecs->dai_name = pcm->name;
                dl[i].num_codecs = 1;
                dl[i].num_cpus = 1;
index f8a3e8a..9904a9e 100644 (file)
@@ -808,6 +808,16 @@ static const struct platform_device_id board_ids[] = {
                                        SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK |
                                        SOF_ES8336_JD_INVERTED),
        },
+       {
+               .name = "mtl_es83x6_c1_h02",
+               .driver_data = (kernel_ulong_t)(SOF_ES8336_SSP_CODEC(1) |
+                                       SOF_NO_OF_HDMI_CAPTURE_SSP(2) |
+                                       SOF_HDMI_CAPTURE_1_SSP(0) |
+                                       SOF_HDMI_CAPTURE_2_SSP(2) |
+                                       SOF_SSP_HDMI_CAPTURE_PRESENT |
+                                       SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK |
+                                       SOF_ES8336_JD_INVERTED),
+       },
        { }
 };
 MODULE_DEVICE_TABLE(platform, board_ids);
index 5a1c750..8426495 100644 (file)
@@ -380,6 +380,16 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
                .callback = sof_sdw_quirk_cb,
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B14"),
+               },
+               /* No Jack */
+               .driver_data = (void *)SOF_SDW_TGL_HDMI,
+       },
+
+       {
+               .callback = sof_sdw_quirk_cb,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
                        DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B29"),
                },
                .driver_data = (void *)(SOF_SDW_TGL_HDMI |
index 8e995ed..5103e75 100644 (file)
@@ -656,18 +656,18 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_sdw_machines[] = {
                .sof_tplg_filename = "sof-adl-rt1316-l2-mono-rt714-l3.tplg",
        },
        {
-               .link_mask = 0x3, /* rt1316 on link1 & rt714 on link0 */
-               .links = adl_sdw_rt1316_link1_rt714_link0,
-               .drv_name = "sof_sdw",
-               .sof_tplg_filename = "sof-adl-rt1316-l1-mono-rt714-l0.tplg",
-       },
-       {
                .link_mask = 0x7, /* rt714 on link0 & two rt1316s on link1 and link2 */
                .links = adl_sdw_rt1316_link12_rt714_link0,
                .drv_name = "sof_sdw",
                .sof_tplg_filename = "sof-adl-rt1316-l12-rt714-l0.tplg",
        },
        {
+               .link_mask = 0x3, /* rt1316 on link1 & rt714 on link0 */
+               .links = adl_sdw_rt1316_link1_rt714_link0,
+               .drv_name = "sof_sdw",
+               .sof_tplg_filename = "sof-adl-rt1316-l1-mono-rt714-l0.tplg",
+       },
+       {
                .link_mask = 0x5, /* 2 active links required */
                .links = adl_sdw_rt1316_link2_rt714_link0,
                .drv_name = "sof_sdw",
index 0304246..92498d1 100644 (file)
@@ -30,6 +30,16 @@ static const struct snd_soc_acpi_codecs mtl_rt5682_rt5682s_hp = {
        .codecs = {"10EC5682", "RTL5682"},
 };
 
+static const struct snd_soc_acpi_codecs mtl_essx_83x6 = {
+       .num_codecs = 3,
+       .codecs = { "ESSX8316", "ESSX8326", "ESSX8336"},
+};
+
+static const struct snd_soc_acpi_codecs mtl_lt6911_hdmi = {
+       .num_codecs = 1,
+       .codecs = {"INTC10B0"}
+};
+
 struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_machines[] = {
        {
                .comp_ids = &mtl_rt5682_rt5682s_hp,
@@ -52,6 +62,21 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_machines[] = {
                .quirk_data = &mtl_rt1019p_amp,
                .sof_tplg_filename = "sof-mtl-rt1019-rt5682.tplg",
        },
+       {
+               .comp_ids = &mtl_essx_83x6,
+               .drv_name = "mtl_es83x6_c1_h02",
+               .machine_quirk = snd_soc_acpi_codec_list,
+               .quirk_data = &mtl_lt6911_hdmi,
+               .sof_tplg_filename = "sof-mtl-es83x6-ssp1-hdmi-ssp02.tplg",
+       },
+       {
+               .comp_ids = &mtl_essx_83x6,
+               .drv_name = "sof-essx8336",
+               .sof_tplg_filename = "sof-mtl-es8336", /* the tplg suffix is added at run time */
+               .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER |
+                                       SND_SOC_ACPI_TPLG_INTEL_SSP_MSB |
+                                       SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER,
+       },
        {},
 };
 EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_mtl_machines);
index d868801..bc2f284 100644 (file)
@@ -112,34 +112,6 @@ static int axg_spdifin_prepare(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static int axg_spdifin_startup(struct snd_pcm_substream *substream,
-                              struct snd_soc_dai *dai)
-{
-       struct axg_spdifin *priv = snd_soc_dai_get_drvdata(dai);
-       int ret;
-
-       ret = clk_prepare_enable(priv->refclk);
-       if (ret) {
-               dev_err(dai->dev,
-                       "failed to enable spdifin reference clock\n");
-               return ret;
-       }
-
-       regmap_update_bits(priv->map, SPDIFIN_CTRL0, SPDIFIN_CTRL0_EN,
-                          SPDIFIN_CTRL0_EN);
-
-       return 0;
-}
-
-static void axg_spdifin_shutdown(struct snd_pcm_substream *substream,
-                                struct snd_soc_dai *dai)
-{
-       struct axg_spdifin *priv = snd_soc_dai_get_drvdata(dai);
-
-       regmap_update_bits(priv->map, SPDIFIN_CTRL0, SPDIFIN_CTRL0_EN, 0);
-       clk_disable_unprepare(priv->refclk);
-}
-
 static void axg_spdifin_write_mode_param(struct regmap *map, int mode,
                                         unsigned int val,
                                         unsigned int num_per_reg,
@@ -251,17 +223,32 @@ static int axg_spdifin_dai_probe(struct snd_soc_dai *dai)
        ret = axg_spdifin_sample_mode_config(dai, priv);
        if (ret) {
                dev_err(dai->dev, "mode configuration failed\n");
-               clk_disable_unprepare(priv->pclk);
-               return ret;
+               goto pclk_err;
        }
 
+       ret = clk_prepare_enable(priv->refclk);
+       if (ret) {
+               dev_err(dai->dev,
+                       "failed to enable spdifin reference clock\n");
+               goto pclk_err;
+       }
+
+       regmap_update_bits(priv->map, SPDIFIN_CTRL0, SPDIFIN_CTRL0_EN,
+                          SPDIFIN_CTRL0_EN);
+
        return 0;
+
+pclk_err:
+       clk_disable_unprepare(priv->pclk);
+       return ret;
 }
 
 static int axg_spdifin_dai_remove(struct snd_soc_dai *dai)
 {
        struct axg_spdifin *priv = snd_soc_dai_get_drvdata(dai);
 
+       regmap_update_bits(priv->map, SPDIFIN_CTRL0, SPDIFIN_CTRL0_EN, 0);
+       clk_disable_unprepare(priv->refclk);
        clk_disable_unprepare(priv->pclk);
        return 0;
 }
@@ -270,8 +257,6 @@ static const struct snd_soc_dai_ops axg_spdifin_ops = {
        .probe          = axg_spdifin_dai_probe,
        .remove         = axg_spdifin_dai_remove,
        .prepare        = axg_spdifin_prepare,
-       .startup        = axg_spdifin_startup,
-       .shutdown       = axg_spdifin_shutdown,
 };
 
 static int axg_spdifin_iec958_info(struct snd_kcontrol *kcontrol,
index e29c2fe..1bd7114 100644 (file)
@@ -1303,6 +1303,7 @@ audio_graph:
                if (i >= RSND_MAX_COMPONENT) {
                        dev_info(dev, "reach to max component\n");
                        of_node_put(node);
+                       of_node_put(ports);
                        break;
                }
        }
index cc442c5..9de98c0 100644 (file)
@@ -1347,7 +1347,7 @@ static int soc_init_pcm_runtime(struct snd_soc_card *card,
        snd_soc_runtime_get_dai_fmt(rtd);
        ret = snd_soc_runtime_set_dai_fmt(rtd, dai_link->dai_fmt);
        if (ret)
-               return ret;
+               goto err;
 
        /* add DPCM sysfs entries */
        soc_dpcm_debugfs_add(rtd);
@@ -1372,17 +1372,26 @@ static int soc_init_pcm_runtime(struct snd_soc_card *card,
        /* create compress_device if possible */
        ret = snd_soc_dai_compress_new(cpu_dai, rtd, num);
        if (ret != -ENOTSUPP)
-               return ret;
+               goto err;
 
        /* create the pcm */
        ret = soc_new_pcm(rtd, num);
        if (ret < 0) {
                dev_err(card->dev, "ASoC: can't create pcm %s :%d\n",
                        dai_link->stream_name, ret);
-               return ret;
+               goto err;
        }
 
-       return snd_soc_pcm_dai_new(rtd);
+       ret = snd_soc_pcm_dai_new(rtd);
+       if (ret < 0)
+               goto err;
+
+       rtd->initialized = true;
+
+       return 0;
+err:
+       snd_soc_link_exit(rtd);
+       return ret;
 }
 
 static void soc_set_name_prefix(struct snd_soc_card *card,
@@ -1445,8 +1454,8 @@ static int soc_probe_component(struct snd_soc_card *card,
        if (component->card) {
                if (component->card != card) {
                        dev_err(component->dev,
-                               "Trying to bind component to card \"%s\" but is already bound to card \"%s\"\n",
-                               card->name, component->card->name);
+                               "Trying to bind component \"%s\" to card \"%s\" but is already bound to card \"%s\"\n",
+                               component->name, card->name, component->card->name);
                        return -ENODEV;
                }
                return 0;
@@ -1980,7 +1989,8 @@ static void soc_cleanup_card_resources(struct snd_soc_card *card)
 
        /* release machine specific resources */
        for_each_card_rtds(card, rtd)
-               snd_soc_link_exit(rtd);
+               if (rtd->initialized)
+                       snd_soc_link_exit(rtd);
        /* remove and free each DAI */
        soc_remove_link_dais(card);
        soc_remove_link_components(card);
index d0653d7..cad222e 100644 (file)
@@ -44,8 +44,8 @@ static struct device *dmaengine_dma_dev(struct dmaengine_pcm *pcm,
  * platforms which make use of the snd_dmaengine_dai_dma_data struct for their
  * DAI DMA data. Internally the function will first call
  * snd_hwparams_to_dma_slave_config to fill in the slave config based on the
- * hw_params, followed by snd_dmaengine_set_config_from_dai_data to fill in the
- * remaining fields based on the DAI DMA data.
+ * hw_params, followed by snd_dmaengine_pcm_set_config_from_dai_data to fill in
+ * the remaining fields based on the DAI DMA data.
  */
 int snd_dmaengine_pcm_prepare_slave_config(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params, struct dma_slave_config *slave_config)
index eb07238..5470425 100644 (file)
@@ -985,6 +985,7 @@ static int __soc_pcm_hw_params(struct snd_soc_pcm_runtime *rtd,
 {
        struct snd_soc_dai *cpu_dai;
        struct snd_soc_dai *codec_dai;
+       struct snd_pcm_hw_params tmp_params;
        int i, ret = 0;
 
        snd_soc_dpcm_mutex_assert_held(rtd);
@@ -998,7 +999,6 @@ static int __soc_pcm_hw_params(struct snd_soc_pcm_runtime *rtd,
                goto out;
 
        for_each_rtd_codec_dais(rtd, i, codec_dai) {
-               struct snd_pcm_hw_params codec_params;
                unsigned int tdm_mask = snd_soc_dai_tdm_mask_get(codec_dai, substream->stream);
 
                /*
@@ -1019,23 +1019,22 @@ static int __soc_pcm_hw_params(struct snd_soc_pcm_runtime *rtd,
                        continue;
 
                /* copy params for each codec */
-               codec_params = *params;
+               tmp_params = *params;
 
                /* fixup params based on TDM slot masks */
                if (tdm_mask)
-                       soc_pcm_codec_params_fixup(&codec_params, tdm_mask);
+                       soc_pcm_codec_params_fixup(&tmp_params, tdm_mask);
 
                ret = snd_soc_dai_hw_params(codec_dai, substream,
-                                           &codec_params);
+                                           &tmp_params);
                if(ret < 0)
                        goto out;
 
-               soc_pcm_set_dai_params(codec_dai, &codec_params);
-               snd_soc_dapm_update_dai(substream, &codec_params, codec_dai);
+               soc_pcm_set_dai_params(codec_dai, &tmp_params);
+               snd_soc_dapm_update_dai(substream, &tmp_params, codec_dai);
        }
 
        for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
-               struct snd_pcm_hw_params cpu_params;
                unsigned int ch_mask = 0;
                int j;
 
@@ -1047,7 +1046,7 @@ static int __soc_pcm_hw_params(struct snd_soc_pcm_runtime *rtd,
                        continue;
 
                /* copy params for each cpu */
-               cpu_params = *params;
+               tmp_params = *params;
 
                if (!rtd->dai_link->codec_ch_maps)
                        goto hw_params;
@@ -1062,16 +1061,16 @@ static int __soc_pcm_hw_params(struct snd_soc_pcm_runtime *rtd,
 
                /* fixup cpu channel number */
                if (ch_mask)
-                       soc_pcm_codec_params_fixup(&cpu_params, ch_mask);
+                       soc_pcm_codec_params_fixup(&tmp_params, ch_mask);
 
 hw_params:
-               ret = snd_soc_dai_hw_params(cpu_dai, substream, &cpu_params);
+               ret = snd_soc_dai_hw_params(cpu_dai, substream, &tmp_params);
                if (ret < 0)
                        goto out;
 
                /* store the parameters for each DAI */
-               soc_pcm_set_dai_params(cpu_dai, &cpu_params);
-               snd_soc_dapm_update_dai(substream, &cpu_params, cpu_dai);
+               soc_pcm_set_dai_params(cpu_dai, &tmp_params);
+               snd_soc_dapm_update_dai(substream, &tmp_params, cpu_dai);
        }
 
        ret = snd_soc_pcm_component_hw_params(substream, params);
index 11607c5..9c746e4 100644 (file)
@@ -217,6 +217,7 @@ int snd_soc_dai_is_dummy(struct snd_soc_dai *dai)
                return 1;
        return 0;
 }
+EXPORT_SYMBOL_GPL(snd_soc_dai_is_dummy);
 
 int snd_soc_component_is_dummy(struct snd_soc_component *component)
 {
index 9935e45..a7ae76e 100644 (file)
@@ -35,7 +35,6 @@ static const struct sof_amd_acp_desc rembrandt_chip_info = {
        .dsp_intr_base  = ACP6X_DSP_SW_INTR_BASE,
        .sram_pte_offset = ACP6X_SRAM_PTE_OFFSET,
        .hw_semaphore_offset = ACP6X_AXI2DAGB_SEM_0,
-       .acp_clkmux_sel = ACP6X_CLKMUX_SEL,
        .fusion_dsp_offset = ACP6X_DSP_FUSION_RUNSTALL,
        .probe_reg_offset = ACP6X_FUTURE_REG_ACLK_0,
 };
index 30db685..2d1616b 100644 (file)
@@ -486,10 +486,9 @@ int snd_sof_device_remove(struct device *dev)
                snd_sof_ipc_free(sdev);
                snd_sof_free_debug(sdev);
                snd_sof_remove(sdev);
+               sof_ops_free(sdev);
        }
 
-       sof_ops_free(sdev);
-
        /* release firmware */
        snd_sof_fw_unload(sdev);
 
index b84ca58..f941251 100644 (file)
@@ -460,7 +460,7 @@ int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot)
        /* step 3: wait for IPC DONE bit from ROM */
        ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, chip->ipc_ack, status,
                                            ((status & chip->ipc_ack_mask) == chip->ipc_ack_mask),
-                                           HDA_DSP_REG_POLL_INTERVAL_US, MTL_DSP_PURGE_TIMEOUT_US);
+                                           HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_INIT_TIMEOUT_US);
        if (ret < 0) {
                if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
                        dev_err(sdev->dev, "timeout waiting for purge IPC done\n");
index 0218149..95696b3 100644 (file)
@@ -62,7 +62,6 @@
 #define MTL_DSP_IRQSTS_IPC             BIT(0)
 #define MTL_DSP_IRQSTS_SDW             BIT(6)
 
-#define MTL_DSP_PURGE_TIMEOUT_US       20000000 /* 20s */
 #define MTL_DSP_REG_POLL_INTERVAL_US   10      /* 10 us */
 
 /* Memory windows */
index f2a30cd..7cb63e6 100644 (file)
@@ -231,7 +231,7 @@ static int sof_ipc4_get_audio_fmt(struct snd_soc_component *scomp,
 
        ret = sof_update_ipc_object(scomp, available_fmt,
                                    SOF_AUDIO_FMT_NUM_TOKENS, swidget->tuples,
-                                   swidget->num_tuples, sizeof(available_fmt), 1);
+                                   swidget->num_tuples, sizeof(*available_fmt), 1);
        if (ret) {
                dev_err(scomp->dev, "Failed to parse audio format token count\n");
                return ret;
index e7ef770..e5405f8 100644 (file)
@@ -212,7 +212,8 @@ widget_free:
        sof_widget_free_unlocked(sdev, swidget);
        use_count_decremented = true;
 core_put:
-       snd_sof_dsp_core_put(sdev, swidget->core);
+       if (!use_count_decremented)
+               snd_sof_dsp_core_put(sdev, swidget->core);
 pipe_widget_free:
        if (swidget->id != snd_soc_dapm_scheduler)
                sof_widget_free_unlocked(sdev, swidget->spipe->pipe_widget);
index 1f2c501..4737e77 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/platform_device.h>
 #include <sound/graph_card.h>
 #include <sound/pcm_params.h>
+#include <sound/soc-dai.h>
 
 #define MAX_PLLA_OUT0_DIV 128
 
@@ -44,6 +45,21 @@ struct tegra_audio_cdata {
        unsigned int plla_out0_rates[NUM_RATE_TYPE];
 };
 
+static bool need_clk_update(struct snd_soc_dai *dai)
+{
+       if (snd_soc_dai_is_dummy(dai) ||
+           !dai->driver->ops ||
+           !dai->driver->name)
+               return false;
+
+       if (strstr(dai->driver->name, "I2S") ||
+           strstr(dai->driver->name, "DMIC") ||
+           strstr(dai->driver->name, "DSPK"))
+               return true;
+
+       return false;
+}
+
 /* Setup PLL clock as per the given sample rate */
 static int tegra_audio_graph_update_pll(struct snd_pcm_substream *substream,
                                        struct snd_pcm_hw_params *params)
@@ -140,19 +156,7 @@ static int tegra_audio_graph_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
        int err;
 
-       /*
-        * This gets called for each DAI link (FE or BE) when DPCM is used.
-        * We may not want to update PLLA rate for each call. So PLLA update
-        * must be restricted to external I/O links (I2S, DMIC or DSPK) since
-        * they actually depend on it. I/O modules update their clocks in
-        * hw_param() of their respective component driver and PLLA rate
-        * update here helps them to derive appropriate rates.
-        *
-        * TODO: When more HW accelerators get added (like sample rate
-        * converter, volume gain controller etc., which don't really
-        * depend on PLLA) we need a better way to filter here.
-        */
-       if (cpu_dai->driver->ops && rtd->dai_link->no_pcm) {
+       if (need_clk_update(cpu_dai)) {
                err = tegra_audio_graph_update_pll(substream, params);
                if (err)
                        return err;
index 49f63f8..b5cbf1f 100644 (file)
@@ -485,7 +485,7 @@ static int init_card(struct snd_usb_caiaqdev *cdev)
        }
 
        usb_make_path(usb_dev, usbpath, sizeof(usbpath));
-       snprintf(card->longname, sizeof(card->longname), "%s %s (%s)",
+       scnprintf(card->longname, sizeof(card->longname), "%s %s (%s)",
                       cdev->vendor_name, cdev->product_name, usbpath);
 
        setup_card(cdev);
index 9105ec6..409fc11 100644 (file)
@@ -1204,6 +1204,13 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval,
                        cval->res = 16;
                }
                break;
+       case USB_ID(0x1bcf, 0x2283): /* NexiGo N930AF FHD Webcam */
+               if (!strcmp(kctl->id.name, "Mic Capture Volume")) {
+                       usb_audio_info(chip,
+                               "set resolution quirk: cval->res = 16\n");
+                       cval->res = 16;
+               }
+               break;
        }
 }
 
@@ -1929,7 +1936,6 @@ static int parse_clock_source_unit(struct mixer_build *state, int unitid,
        struct uac_clock_source_descriptor *hdr = _ftr;
        struct usb_mixer_elem_info *cval;
        struct snd_kcontrol *kctl;
-       char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
        int ret;
 
        if (state->mixer->protocol != UAC_VERSION_2)
@@ -1966,10 +1972,9 @@ static int parse_clock_source_unit(struct mixer_build *state, int unitid,
 
        kctl->private_free = snd_usb_mixer_elem_free;
        ret = snd_usb_copy_string_desc(state->chip, hdr->iClockSource,
-                                      name, sizeof(name));
+                                      kctl->id.name, sizeof(kctl->id.name));
        if (ret > 0)
-               snprintf(kctl->id.name, sizeof(kctl->id.name),
-                        "%s Validity", name);
+               append_ctl_name(kctl, " Validity");
        else
                snprintf(kctl->id.name, sizeof(kctl->id.name),
                         "Clock Source %d Validity", hdr->bClockID);
index 9d11bb0..d260be8 100644 (file)
@@ -3205,8 +3205,8 @@ static int scarlett2_add_line_in_ctls(struct usb_mixer_interface *mixer)
        /* Add input phantom controls */
        if (info->inputs_per_phantom == 1) {
                for (i = 0; i < info->phantom_count; i++) {
-                       snprintf(s, sizeof(s), fmt, i + 1,
-                                "Phantom Power", "Switch");
+                       scnprintf(s, sizeof(s), fmt, i + 1,
+                                 "Phantom Power", "Switch");
                        err = scarlett2_add_new_ctl(
                                mixer, &scarlett2_phantom_ctl,
                                i, 1, s, &private->phantom_ctls[i]);
@@ -3218,8 +3218,8 @@ static int scarlett2_add_line_in_ctls(struct usb_mixer_interface *mixer)
                        int from = i * info->inputs_per_phantom + 1;
                        int to = (i + 1) * info->inputs_per_phantom;
 
-                       snprintf(s, sizeof(s), fmt2, from, to,
-                                "Phantom Power", "Switch");
+                       scnprintf(s, sizeof(s), fmt2, from, to,
+                                 "Phantom Power", "Switch");
                        err = scarlett2_add_new_ctl(
                                mixer, &scarlett2_phantom_ctl,
                                i, 1, s, &private->phantom_ctls[i]);
index 598659d..4e64842 100644 (file)
@@ -1994,7 +1994,11 @@ void snd_usb_audioformat_attributes_quirk(struct snd_usb_audio *chip,
                /* mic works only when ep packet size is set to wMaxPacketSize */
                fp->attributes |= UAC_EP_CS_ATTR_FILL_MAX;
                break;
-
+       case USB_ID(0x3511, 0x2b1e): /* Opencomm2 UC USB Bluetooth dongle */
+               /* mic works only when ep pitch control is not set */
+               if (stream == SNDRV_PCM_STREAM_CAPTURE)
+                       fp->attributes &= ~UAC_EP_CS_ATTR_PITCH_CONTROL;
+               break;
        }
 }
 
@@ -2173,6 +2177,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
                   QUIRK_FLAG_FIXED_RATE),
        DEVICE_FLG(0x0ecb, 0x2069, /* JBL Quantum810 Wireless */
                   QUIRK_FLAG_FIXED_RATE),
+       DEVICE_FLG(0x1bcf, 0x2283, /* NexiGo N930AF FHD Webcam */
+                  QUIRK_FLAG_GET_SAMPLE_RATE),
 
        /* Vendor matches */
        VENDOR_FLG(0x045e, /* MS Lifecam */
index 63b0398..55ecf76 100644 (file)
@@ -483,7 +483,7 @@ int xen_snd_front_cfg_card(struct xen_snd_front_info *front_info,
        *stream_cnt = 0;
        num_devices = 0;
        do {
-               snprintf(node, sizeof(node), "%d", num_devices);
+               scnprintf(node, sizeof(node), "%d", num_devices);
                if (!xenbus_exists(XBT_NIL, xb_dev->nodename, node))
                        break;
 
index a00a53e..1d11135 100644 (file)
@@ -57,6 +57,7 @@
 
 #define MSR_IA32_PRED_CMD              0x00000049 /* Prediction Command */
 #define PRED_CMD_IBPB                  BIT(0)     /* Indirect Branch Prediction Barrier */
+#define PRED_CMD_SBPB                  BIT(7)     /* Selective Branch Prediction Barrier */
 
 #define MSR_PPIN_CTL                   0x0000004e
 #define MSR_PPIN                       0x0000004f
                                                 * Not susceptible to Post-Barrier
                                                 * Return Stack Buffer Predictions.
                                                 */
+#define ARCH_CAP_GDS_CTRL              BIT(25) /*
+                                                * CPU is vulnerable to Gather
+                                                * Data Sampling (GDS) and
+                                                * has controls for mitigation.
+                                                */
+#define ARCH_CAP_GDS_NO                        BIT(26) /*
+                                                * CPU is not vulnerable to Gather
+                                                * Data Sampling (GDS).
+                                                */
 
 #define ARCH_CAP_XAPIC_DISABLE         BIT(21) /*
                                                 * IA32_XAPIC_DISABLE_STATUS MSR
 #define RNGDS_MITG_DIS                 BIT(0)  /* SRBDS support */
 #define RTM_ALLOW                      BIT(1)  /* TSX development mode */
 #define FB_CLEAR_DIS                   BIT(3)  /* CPU Fill buffer clear disable */
+#define GDS_MITG_DIS                   BIT(4)  /* Disable GDS mitigation */
+#define GDS_MITG_LOCKED                        BIT(5)  /* GDS mitigation locked */
 
 #define MSR_IA32_SYSENTER_CS           0x00000174
 #define MSR_IA32_SYSENTER_ESP          0x00000175
index 27f5e7d..264eeb9 100644 (file)
@@ -1171,12 +1171,79 @@ static int process_ip_string(FILE *f, char *ip_string, int type)
        return 0;
 }
 
+/*
+ * Only IPv4 subnet strings needs to be converted to plen
+ * For IPv6 the subnet is already privided in plen format
+ */
+static int kvp_subnet_to_plen(char *subnet_addr_str)
+{
+       int plen = 0;
+       struct in_addr subnet_addr4;
+
+       /*
+        * Convert subnet address to binary representation
+        */
+       if (inet_pton(AF_INET, subnet_addr_str, &subnet_addr4) == 1) {
+               uint32_t subnet_mask = ntohl(subnet_addr4.s_addr);
+
+               while (subnet_mask & 0x80000000) {
+                       plen++;
+                       subnet_mask <<= 1;
+               }
+       } else {
+               return -1;
+       }
+
+       return plen;
+}
+
+static int process_ip_string_nm(FILE *f, char *ip_string, char *subnet,
+                               int is_ipv6)
+{
+       char addr[INET6_ADDRSTRLEN];
+       char subnet_addr[INET6_ADDRSTRLEN];
+       int error, i = 0;
+       int ip_offset = 0, subnet_offset = 0;
+       int plen;
+
+       memset(addr, 0, sizeof(addr));
+       memset(subnet_addr, 0, sizeof(subnet_addr));
+
+       while (parse_ip_val_buffer(ip_string, &ip_offset, addr,
+                                  (MAX_IP_ADDR_SIZE * 2)) &&
+                                  parse_ip_val_buffer(subnet,
+                                                      &subnet_offset,
+                                                      subnet_addr,
+                                                      (MAX_IP_ADDR_SIZE *
+                                                       2))) {
+               if (!is_ipv6)
+                       plen = kvp_subnet_to_plen((char *)subnet_addr);
+               else
+                       plen = atoi(subnet_addr);
+
+               if (plen < 0)
+                       return plen;
+
+               error = fprintf(f, "address%d=%s/%d\n", ++i, (char *)addr,
+                               plen);
+               if (error < 0)
+                       return error;
+
+               memset(addr, 0, sizeof(addr));
+               memset(subnet_addr, 0, sizeof(subnet_addr));
+       }
+
+       return 0;
+}
+
 static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
 {
        int error = 0;
-       char if_file[PATH_MAX];
-       FILE *file;
+       char if_filename[PATH_MAX];
+       char nm_filename[PATH_MAX];
+       FILE *ifcfg_file, *nmfile;
        char cmd[PATH_MAX];
+       int is_ipv6 = 0;
        char *mac_addr;
        int str_len;
 
@@ -1197,7 +1264,7 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
         * in a given distro to configure the interface and so are free
         * ignore information that may not be relevant.
         *
-        * Here is the format of the ip configuration file:
+        * Here is the ifcfg format of the ip configuration file:
         *
         * HWADDR=macaddr
         * DEVICE=interface name
@@ -1220,6 +1287,32 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
         * tagged as IPV6_DEFAULTGW and IPV6 NETMASK will be tagged as
         * IPV6NETMASK.
         *
+        * Here is the keyfile format of the ip configuration file:
+        *
+        * [ethernet]
+        * mac-address=macaddr
+        * [connection]
+        * interface-name=interface name
+        *
+        * [ipv4]
+        * method=<protocol> (where <protocol> is "auto" if DHCP is configured
+        *                       or "manual" if no boot-time protocol should be used)
+        *
+        * address1=ipaddr1/plen
+        * address2=ipaddr2/plen
+        *
+        * gateway=gateway1;gateway2
+        *
+        * dns=dns1;dns2
+        *
+        * [ipv6]
+        * address1=ipaddr1/plen
+        * address2=ipaddr2/plen
+        *
+        * gateway=gateway1;gateway2
+        *
+        * dns=dns1;dns2
+        *
         * The host can specify multiple ipv4 and ipv6 addresses to be
         * configured for the interface. Furthermore, the configuration
         * needs to be persistent. A subsequent GET call on the interface
@@ -1227,14 +1320,29 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
         * call.
         */
 
-       snprintf(if_file, sizeof(if_file), "%s%s%s", KVP_CONFIG_LOC,
-               "/ifcfg-", if_name);
+       /*
+        * We are populating both ifcfg and nmconnection files
+        */
+       snprintf(if_filename, sizeof(if_filename), "%s%s%s", KVP_CONFIG_LOC,
+                "/ifcfg-", if_name);
 
-       file = fopen(if_file, "w");
+       ifcfg_file = fopen(if_filename, "w");
 
-       if (file == NULL) {
+       if (!ifcfg_file) {
                syslog(LOG_ERR, "Failed to open config file; error: %d %s",
-                               errno, strerror(errno));
+                      errno, strerror(errno));
+               return HV_E_FAIL;
+       }
+
+       snprintf(nm_filename, sizeof(nm_filename), "%s%s%s%s", KVP_CONFIG_LOC,
+                "/", if_name, ".nmconnection");
+
+       nmfile = fopen(nm_filename, "w");
+
+       if (!nmfile) {
+               syslog(LOG_ERR, "Failed to open config file; error: %d %s",
+                      errno, strerror(errno));
+               fclose(ifcfg_file);
                return HV_E_FAIL;
        }
 
@@ -1248,14 +1356,31 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
                goto setval_error;
        }
 
-       error = kvp_write_file(file, "HWADDR", "", mac_addr);
-       free(mac_addr);
+       error = kvp_write_file(ifcfg_file, "HWADDR", "", mac_addr);
+       if (error < 0)
+               goto setmac_error;
+
+       error = kvp_write_file(ifcfg_file, "DEVICE", "", if_name);
+       if (error < 0)
+               goto setmac_error;
+
+       error = fprintf(nmfile, "\n[connection]\n");
+       if (error < 0)
+               goto setmac_error;
+
+       error = kvp_write_file(nmfile, "interface-name", "", if_name);
        if (error)
-               goto setval_error;
+               goto setmac_error;
 
-       error = kvp_write_file(file, "DEVICE", "", if_name);
+       error = fprintf(nmfile, "\n[ethernet]\n");
+       if (error < 0)
+               goto setmac_error;
+
+       error = kvp_write_file(nmfile, "mac-address", "", mac_addr);
        if (error)
-               goto setval_error;
+               goto setmac_error;
+
+       free(mac_addr);
 
        /*
         * The dhcp_enabled flag is only for IPv4. In the case the host only
@@ -1263,47 +1388,91 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
         * proceed to parse and pass the IPv6 information to the
         * disto-specific script hv_set_ifconfig.
         */
+
+       /*
+        * First populate the ifcfg file format
+        */
        if (new_val->dhcp_enabled) {
-               error = kvp_write_file(file, "BOOTPROTO", "", "dhcp");
+               error = kvp_write_file(ifcfg_file, "BOOTPROTO", "", "dhcp");
                if (error)
                        goto setval_error;
-
        } else {
-               error = kvp_write_file(file, "BOOTPROTO", "", "none");
+               error = kvp_write_file(ifcfg_file, "BOOTPROTO", "", "none");
                if (error)
                        goto setval_error;
        }
 
-       /*
-        * Write the configuration for ipaddress, netmask, gateway and
-        * name servers.
-        */
-
-       error = process_ip_string(file, (char *)new_val->ip_addr, IPADDR);
+       error = process_ip_string(ifcfg_file, (char *)new_val->ip_addr,
+                                 IPADDR);
        if (error)
                goto setval_error;
 
-       error = process_ip_string(file, (char *)new_val->sub_net, NETMASK);
+       error = process_ip_string(ifcfg_file, (char *)new_val->sub_net,
+                                 NETMASK);
        if (error)
                goto setval_error;
 
-       error = process_ip_string(file, (char *)new_val->gate_way, GATEWAY);
+       error = process_ip_string(ifcfg_file, (char *)new_val->gate_way,
+                                 GATEWAY);
        if (error)
                goto setval_error;
 
-       error = process_ip_string(file, (char *)new_val->dns_addr, DNS);
+       error = process_ip_string(ifcfg_file, (char *)new_val->dns_addr, DNS);
        if (error)
                goto setval_error;
 
-       fclose(file);
+       if (new_val->addr_family == ADDR_FAMILY_IPV6) {
+               error = fprintf(nmfile, "\n[ipv6]\n");
+               if (error < 0)
+                       goto setval_error;
+               is_ipv6 = 1;
+       } else {
+               error = fprintf(nmfile, "\n[ipv4]\n");
+               if (error < 0)
+                       goto setval_error;
+       }
+
+       /*
+        * Now we populate the keyfile format
+        */
+
+       if (new_val->dhcp_enabled) {
+               error = kvp_write_file(nmfile, "method", "", "auto");
+               if (error < 0)
+                       goto setval_error;
+       } else {
+               error = kvp_write_file(nmfile, "method", "", "manual");
+               if (error < 0)
+                       goto setval_error;
+       }
+
+       /*
+        * Write the configuration for ipaddress, netmask, gateway and
+        * name services
+        */
+       error = process_ip_string_nm(nmfile, (char *)new_val->ip_addr,
+                                    (char *)new_val->sub_net, is_ipv6);
+       if (error < 0)
+               goto setval_error;
+
+       error = fprintf(nmfile, "gateway=%s\n", (char *)new_val->gate_way);
+       if (error < 0)
+               goto setval_error;
+
+       error = fprintf(nmfile, "dns=%s\n", (char *)new_val->dns_addr);
+       if (error < 0)
+               goto setval_error;
+
+       fclose(nmfile);
+       fclose(ifcfg_file);
 
        /*
         * Now that we have populated the configuration file,
         * invoke the external script to do its magic.
         */
 
-       str_len = snprintf(cmd, sizeof(cmd), KVP_SCRIPTS_PATH "%s %s",
-                          "hv_set_ifconfig", if_file);
+       str_len = snprintf(cmd, sizeof(cmd), KVP_SCRIPTS_PATH "%s %s %s",
+                          "hv_set_ifconfig", if_filename, nm_filename);
        /*
         * This is a little overcautious, but it's necessary to suppress some
         * false warnings from gcc 8.0.1.
@@ -1316,14 +1485,16 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
 
        if (system(cmd)) {
                syslog(LOG_ERR, "Failed to execute cmd '%s'; error: %d %s",
-                               cmd, errno, strerror(errno));
+                      cmd, errno, strerror(errno));
                return HV_E_FAIL;
        }
        return 0;
-
+setmac_error:
+       free(mac_addr);
 setval_error:
        syslog(LOG_ERR, "Failed to write config file");
-       fclose(file);
+       fclose(ifcfg_file);
+       fclose(nmfile);
        return error;
 }
 
index d10fe35..ae5a7a8 100755 (executable)
 #
 # This example script is based on a RHEL environment.
 #
-# Here is the format of the ip configuration file:
+# Here is the ifcfg format of the ip configuration file:
 #
 # HWADDR=macaddr
 # DEVICE=interface name
 # BOOTPROTO=<protocol> (where <protocol> is "dhcp" if DHCP is configured
-#                       or "none" if no boot-time protocol should be used)
+#                      or "none" if no boot-time protocol should be used)
 #
 # IPADDR0=ipaddr1
 # IPADDR1=ipaddr2
 # tagged as IPV6_DEFAULTGW and IPV6 NETMASK will be tagged as
 # IPV6NETMASK.
 #
+# Here is the keyfile format of the ip configuration file:
+#
+# [ethernet]
+# mac-address=macaddr
+# [connection]
+# interface-name=interface name
+#
+# [ipv4]
+# method=<protocol> (where <protocol> is "auto" if DHCP is configured
+#                       or "manual" if no boot-time protocol should be used)
+#
+# address1=ipaddr1/plen
+# address=ipaddr2/plen
+#
+# gateway=gateway1;gateway2
+#
+# dns=dns1;
+#
+# [ipv6]
+# address1=ipaddr1/plen
+# address2=ipaddr1/plen
+#
+# gateway=gateway1;gateway2
+#
+# dns=dns1;dns2
+#
 # The host can specify multiple ipv4 and ipv6 addresses to be
 # configured for the interface. Furthermore, the configuration
 # needs to be persistent. A subsequent GET call on the interface
 # call.
 #
 
-
-
 echo "IPV6INIT=yes" >> $1
 echo "NM_CONTROLLED=no" >> $1
 echo "PEERDNS=yes" >> $1
 echo "ONBOOT=yes" >> $1
 
-
 cp $1 /etc/sysconfig/network-scripts/
 
+chmod 600 $2
+interface=$(echo $2 | awk -F - '{ print $2 }')
+filename="${2##*/}"
+
+sed '/\[connection\]/a autoconnect=true' $2 > /etc/NetworkManager/system-connections/${filename}
 
-interface=$(echo $1 | awk -F - '{ print $2 }')
 
 /sbin/ifdown $interface 2>/dev/null
 /sbin/ifup $interface 2>/dev/null
index 71e54b1..2f882d5 100644 (file)
@@ -38,7 +38,7 @@ asm(                                                  \
        ____BTF_ID(symbol)
 
 #define __ID(prefix) \
-       __PASTE(prefix, __COUNTER__)
+       __PASTE(__PASTE(prefix, __COUNTER__), __LINE__)
 
 /*
  * The BTF_ID defines unique symbol for each ID pointing
index a03d9bb..f3c82ab 100644 (file)
@@ -11,8 +11,6 @@
 
 #define PHYS_ADDR_MAX  (~(phys_addr_t)0)
 
-#define __ALIGN_KERNEL(x, a)           __ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1)
-#define __ALIGN_KERNEL_MASK(x, mask)   (((x) + (mask)) & ~(mask))
 #define ALIGN(x, a)                    __ALIGN_KERNEL((x), (a))
 #define ALIGN_DOWN(x, a)               __ALIGN_KERNEL((x) - ((a) - 1), (a))
 
@@ -29,7 +27,7 @@ static inline void *phys_to_virt(unsigned long address)
        return __va(address);
 }
 
-void reserve_bootmem_region(phys_addr_t start, phys_addr_t end);
+void reserve_bootmem_region(phys_addr_t start, phys_addr_t end, int nid);
 
 static inline void totalram_pages_inc(void)
 {
index 102fd92..f6bc226 100644 (file)
@@ -1,4 +1,6 @@
 #ifndef _TOOLS_INCLUDE_LINUX_SEQ_FILE_H
 #define _TOOLS_INCLUDE_LINUX_SEQ_FILE_H
 
+struct seq_file;
+
 #endif /* _TOOLS_INCLUDE_LINUX_SEQ_FILE_H */
index fd6c1cb..abe087c 100644 (file)
@@ -820,8 +820,11 @@ __SYSCALL(__NR_set_mempolicy_home_node, sys_set_mempolicy_home_node)
 #define __NR_cachestat 451
 __SYSCALL(__NR_cachestat, sys_cachestat)
 
+#define __NR_fchmodat2 452
+__SYSCALL(__NR_fchmodat2, sys_fchmodat2)
+
 #undef __NR_syscalls
-#define __NR_syscalls 452
+#define __NR_syscalls 453
 
 /*
  * 32 bit systems traditionally used different
index a87bbbb..794c1d8 100644 (file)
@@ -673,8 +673,11 @@ struct drm_gem_open {
  * Bitfield of supported PRIME sharing capabilities. See &DRM_PRIME_CAP_IMPORT
  * and &DRM_PRIME_CAP_EXPORT.
  *
- * PRIME buffers are exposed as dma-buf file descriptors. See
- * Documentation/gpu/drm-mm.rst, section "PRIME Buffer Sharing".
+ * Starting from kernel version 6.6, both &DRM_PRIME_CAP_IMPORT and
+ * &DRM_PRIME_CAP_EXPORT are always advertised.
+ *
+ * PRIME buffers are exposed as dma-buf file descriptors.
+ * See :ref:`prime_buffer_sharing`.
  */
 #define DRM_CAP_PRIME                  0x5
 /**
@@ -682,6 +685,8 @@ struct drm_gem_open {
  *
  * If this bit is set in &DRM_CAP_PRIME, the driver supports importing PRIME
  * buffers via the &DRM_IOCTL_PRIME_FD_TO_HANDLE ioctl.
+ *
+ * Starting from kernel version 6.6, this bit is always set in &DRM_CAP_PRIME.
  */
 #define  DRM_PRIME_CAP_IMPORT          0x1
 /**
@@ -689,6 +694,8 @@ struct drm_gem_open {
  *
  * If this bit is set in &DRM_CAP_PRIME, the driver supports exporting PRIME
  * buffers via the &DRM_IOCTL_PRIME_HANDLE_TO_FD ioctl.
+ *
+ * Starting from kernel version 6.6, this bit is always set in &DRM_CAP_PRIME.
  */
 #define  DRM_PRIME_CAP_EXPORT          0x2
 /**
@@ -756,15 +763,14 @@ struct drm_gem_open {
 /**
  * DRM_CAP_SYNCOBJ
  *
- * If set to 1, the driver supports sync objects. See
- * Documentation/gpu/drm-mm.rst, section "DRM Sync Objects".
+ * If set to 1, the driver supports sync objects. See :ref:`drm_sync_objects`.
  */
 #define DRM_CAP_SYNCOBJ                0x13
 /**
  * DRM_CAP_SYNCOBJ_TIMELINE
  *
  * If set to 1, the driver supports timeline operations on sync objects. See
- * Documentation/gpu/drm-mm.rst, section "DRM Sync Objects".
+ * :ref:`drm_sync_objects`.
  */
 #define DRM_CAP_SYNCOBJ_TIMELINE       0x14
 
@@ -909,6 +915,27 @@ struct drm_syncobj_timeline_wait {
        __u32 pad;
 };
 
+/**
+ * struct drm_syncobj_eventfd
+ * @handle: syncobj handle.
+ * @flags: Zero to wait for the point to be signalled, or
+ *         &DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE to wait for a fence to be
+ *         available for the point.
+ * @point: syncobj timeline point (set to zero for binary syncobjs).
+ * @fd: Existing eventfd to sent events to.
+ * @pad: Must be zero.
+ *
+ * Register an eventfd to be signalled by a syncobj. The eventfd counter will
+ * be incremented by one.
+ */
+struct drm_syncobj_eventfd {
+       __u32 handle;
+       __u32 flags;
+       __u64 point;
+       __s32 fd;
+       __u32 pad;
+};
+
 
 struct drm_syncobj_array {
        __u64 handles;
@@ -1169,6 +1196,8 @@ extern "C" {
  */
 #define DRM_IOCTL_MODE_GETFB2          DRM_IOWR(0xCE, struct drm_mode_fb_cmd2)
 
+#define DRM_IOCTL_SYNCOBJ_EVENTFD      DRM_IOWR(0xCF, struct drm_syncobj_eventfd)
+
 /*
  * Device specific ioctls should only be in their respective headers
  * The device specific ioctl range is from 0x40 to 0x9f.
@@ -1180,25 +1209,50 @@ extern "C" {
 #define DRM_COMMAND_BASE                0x40
 #define DRM_COMMAND_END                        0xA0
 
-/*
- * Header for events written back to userspace on the drm fd.  The
- * type defines the type of event, the length specifies the total
- * length of the event (including the header), and user_data is
- * typically a 64 bit value passed with the ioctl that triggered the
- * event.  A read on the drm fd will always only return complete
- * events, that is, if for example the read buffer is 100 bytes, and
- * there are two 64 byte events pending, only one will be returned.
+/**
+ * struct drm_event - Header for DRM events
+ * @type: event type.
+ * @length: total number of payload bytes (including header).
  *
- * Event types 0 - 0x7fffffff are generic drm events, 0x80000000 and
- * up are chipset specific.
+ * This struct is a header for events written back to user-space on the DRM FD.
+ * A read on the DRM FD will always only return complete events: e.g. if the
+ * read buffer is 100 bytes large and there are two 64 byte events pending,
+ * only one will be returned.
+ *
+ * Event types 0 - 0x7fffffff are generic DRM events, 0x80000000 and
+ * up are chipset specific. Generic DRM events include &DRM_EVENT_VBLANK,
+ * &DRM_EVENT_FLIP_COMPLETE and &DRM_EVENT_CRTC_SEQUENCE.
  */
 struct drm_event {
        __u32 type;
        __u32 length;
 };
 
+/**
+ * DRM_EVENT_VBLANK - vertical blanking event
+ *
+ * This event is sent in response to &DRM_IOCTL_WAIT_VBLANK with the
+ * &_DRM_VBLANK_EVENT flag set.
+ *
+ * The event payload is a struct drm_event_vblank.
+ */
 #define DRM_EVENT_VBLANK 0x01
+/**
+ * DRM_EVENT_FLIP_COMPLETE - page-flip completion event
+ *
+ * This event is sent in response to an atomic commit or legacy page-flip with
+ * the &DRM_MODE_PAGE_FLIP_EVENT flag set.
+ *
+ * The event payload is a struct drm_event_vblank.
+ */
 #define DRM_EVENT_FLIP_COMPLETE 0x02
+/**
+ * DRM_EVENT_CRTC_SEQUENCE - CRTC sequence event
+ *
+ * This event is sent in response to &DRM_IOCTL_CRTC_QUEUE_SEQUENCE.
+ *
+ * The event payload is a struct drm_event_crtc_sequence.
+ */
 #define DRM_EVENT_CRTC_SEQUENCE        0x03
 
 struct drm_event_vblank {
index 8790b39..0448700 100644 (file)
@@ -1962,7 +1962,9 @@ union bpf_attr {
  *             performed again, if the helper is used in combination with
  *             direct packet access.
  *     Return
- *             0 on success, or a negative error in case of failure.
+ *             0 on success, or a negative error in case of failure. Positive
+ *             error indicates a potential drop or congestion in the target
+ *             device. The particular positive error codes are not defined.
  *
  * u64 bpf_get_current_pid_tgid(void)
  *     Description
diff --git a/tools/include/uapi/linux/seccomp.h b/tools/include/uapi/linux/seccomp.h
new file mode 100644 (file)
index 0000000..dbfc9b3
--- /dev/null
@@ -0,0 +1,157 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _UAPI_LINUX_SECCOMP_H
+#define _UAPI_LINUX_SECCOMP_H
+
+#include <linux/compiler.h>
+#include <linux/types.h>
+
+
+/* Valid values for seccomp.mode and prctl(PR_SET_SECCOMP, <mode>) */
+#define SECCOMP_MODE_DISABLED  0 /* seccomp is not in use. */
+#define SECCOMP_MODE_STRICT    1 /* uses hard-coded filter. */
+#define SECCOMP_MODE_FILTER    2 /* uses user-supplied filter. */
+
+/* Valid operations for seccomp syscall. */
+#define SECCOMP_SET_MODE_STRICT                0
+#define SECCOMP_SET_MODE_FILTER                1
+#define SECCOMP_GET_ACTION_AVAIL       2
+#define SECCOMP_GET_NOTIF_SIZES                3
+
+/* Valid flags for SECCOMP_SET_MODE_FILTER */
+#define SECCOMP_FILTER_FLAG_TSYNC              (1UL << 0)
+#define SECCOMP_FILTER_FLAG_LOG                        (1UL << 1)
+#define SECCOMP_FILTER_FLAG_SPEC_ALLOW         (1UL << 2)
+#define SECCOMP_FILTER_FLAG_NEW_LISTENER       (1UL << 3)
+#define SECCOMP_FILTER_FLAG_TSYNC_ESRCH                (1UL << 4)
+/* Received notifications wait in killable state (only respond to fatal signals) */
+#define SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV (1UL << 5)
+
+/*
+ * All BPF programs must return a 32-bit value.
+ * The bottom 16-bits are for optional return data.
+ * The upper 16-bits are ordered from least permissive values to most,
+ * as a signed value (so 0x8000000 is negative).
+ *
+ * The ordering ensures that a min_t() over composed return values always
+ * selects the least permissive choice.
+ */
+#define SECCOMP_RET_KILL_PROCESS 0x80000000U /* kill the process */
+#define SECCOMP_RET_KILL_THREAD         0x00000000U /* kill the thread */
+#define SECCOMP_RET_KILL        SECCOMP_RET_KILL_THREAD
+#define SECCOMP_RET_TRAP        0x00030000U /* disallow and force a SIGSYS */
+#define SECCOMP_RET_ERRNO       0x00050000U /* returns an errno */
+#define SECCOMP_RET_USER_NOTIF  0x7fc00000U /* notifies userspace */
+#define SECCOMP_RET_TRACE       0x7ff00000U /* pass to a tracer or disallow */
+#define SECCOMP_RET_LOG                 0x7ffc0000U /* allow after logging */
+#define SECCOMP_RET_ALLOW       0x7fff0000U /* allow */
+
+/* Masks for the return value sections. */
+#define SECCOMP_RET_ACTION_FULL        0xffff0000U
+#define SECCOMP_RET_ACTION     0x7fff0000U
+#define SECCOMP_RET_DATA       0x0000ffffU
+
+/**
+ * struct seccomp_data - the format the BPF program executes over.
+ * @nr: the system call number
+ * @arch: indicates system call convention as an AUDIT_ARCH_* value
+ *        as defined in <linux/audit.h>.
+ * @instruction_pointer: at the time of the system call.
+ * @args: up to 6 system call arguments always stored as 64-bit values
+ *        regardless of the architecture.
+ */
+struct seccomp_data {
+       int nr;
+       __u32 arch;
+       __u64 instruction_pointer;
+       __u64 args[6];
+};
+
+struct seccomp_notif_sizes {
+       __u16 seccomp_notif;
+       __u16 seccomp_notif_resp;
+       __u16 seccomp_data;
+};
+
+struct seccomp_notif {
+       __u64 id;
+       __u32 pid;
+       __u32 flags;
+       struct seccomp_data data;
+};
+
+/*
+ * Valid flags for struct seccomp_notif_resp
+ *
+ * Note, the SECCOMP_USER_NOTIF_FLAG_CONTINUE flag must be used with caution!
+ * If set by the process supervising the syscalls of another process the
+ * syscall will continue. This is problematic because of an inherent TOCTOU.
+ * An attacker can exploit the time while the supervised process is waiting on
+ * a response from the supervising process to rewrite syscall arguments which
+ * are passed as pointers of the intercepted syscall.
+ * It should be absolutely clear that this means that the seccomp notifier
+ * _cannot_ be used to implement a security policy! It should only ever be used
+ * in scenarios where a more privileged process supervises the syscalls of a
+ * lesser privileged process to get around kernel-enforced security
+ * restrictions when the privileged process deems this safe. In other words,
+ * in order to continue a syscall the supervising process should be sure that
+ * another security mechanism or the kernel itself will sufficiently block
+ * syscalls if arguments are rewritten to something unsafe.
+ *
+ * Similar precautions should be applied when stacking SECCOMP_RET_USER_NOTIF
+ * or SECCOMP_RET_TRACE. For SECCOMP_RET_USER_NOTIF filters acting on the
+ * same syscall, the most recently added filter takes precedence. This means
+ * that the new SECCOMP_RET_USER_NOTIF filter can override any
+ * SECCOMP_IOCTL_NOTIF_SEND from earlier filters, essentially allowing all
+ * such filtered syscalls to be executed by sending the response
+ * SECCOMP_USER_NOTIF_FLAG_CONTINUE. Note that SECCOMP_RET_TRACE can equally
+ * be overriden by SECCOMP_USER_NOTIF_FLAG_CONTINUE.
+ */
+#define SECCOMP_USER_NOTIF_FLAG_CONTINUE (1UL << 0)
+
+struct seccomp_notif_resp {
+       __u64 id;
+       __s64 val;
+       __s32 error;
+       __u32 flags;
+};
+
+#define SECCOMP_USER_NOTIF_FD_SYNC_WAKE_UP (1UL << 0)
+
+/* valid flags for seccomp_notif_addfd */
+#define SECCOMP_ADDFD_FLAG_SETFD       (1UL << 0) /* Specify remote fd */
+#define SECCOMP_ADDFD_FLAG_SEND                (1UL << 1) /* Addfd and return it, atomically */
+
+/**
+ * struct seccomp_notif_addfd
+ * @id: The ID of the seccomp notification
+ * @flags: SECCOMP_ADDFD_FLAG_*
+ * @srcfd: The local fd number
+ * @newfd: Optional remote FD number if SETFD option is set, otherwise 0.
+ * @newfd_flags: The O_* flags the remote FD should have applied
+ */
+struct seccomp_notif_addfd {
+       __u64 id;
+       __u32 flags;
+       __u32 srcfd;
+       __u32 newfd;
+       __u32 newfd_flags;
+};
+
+#define SECCOMP_IOC_MAGIC              '!'
+#define SECCOMP_IO(nr)                 _IO(SECCOMP_IOC_MAGIC, nr)
+#define SECCOMP_IOR(nr, type)          _IOR(SECCOMP_IOC_MAGIC, nr, type)
+#define SECCOMP_IOW(nr, type)          _IOW(SECCOMP_IOC_MAGIC, nr, type)
+#define SECCOMP_IOWR(nr, type)         _IOWR(SECCOMP_IOC_MAGIC, nr, type)
+
+/* Flags for seccomp notification fd ioctl. */
+#define SECCOMP_IOCTL_NOTIF_RECV       SECCOMP_IOWR(0, struct seccomp_notif)
+#define SECCOMP_IOCTL_NOTIF_SEND       SECCOMP_IOWR(1, \
+                                               struct seccomp_notif_resp)
+#define SECCOMP_IOCTL_NOTIF_ID_VALID   SECCOMP_IOW(2, __u64)
+/* On success, the return value is the remote process's added fd number */
+#define SECCOMP_IOCTL_NOTIF_ADDFD      SECCOMP_IOW(3, \
+                                               struct seccomp_notif_addfd)
+
+#define SECCOMP_IOCTL_NOTIF_SET_FLAGS  SECCOMP_IOW(4, __u64)
+
+#endif /* _UAPI_LINUX_SECCOMP_H */
index cfda251..cb5e757 100644 (file)
 449    n64     futex_waitv                     sys_futex_waitv
 450    common  set_mempolicy_home_node         sys_set_mempolicy_home_node
 451    n64     cachestat                       sys_cachestat
+452    n64     fchmodat2                       sys_fchmodat2
index 8c0b08b..20e5058 100644 (file)
 449    common  futex_waitv                     sys_futex_waitv
 450    nospu   set_mempolicy_home_node         sys_set_mempolicy_home_node
 451    common  cachestat                       sys_cachestat
+452    common  fchmodat2                       sys_fchmodat2
index a6935af..0122cc1 100644 (file)
 449  common    futex_waitv             sys_futex_waitv                 sys_futex_waitv
 450  common    set_mempolicy_home_node sys_set_mempolicy_home_node     sys_set_mempolicy_home_node
 451  common    cachestat               sys_cachestat                   sys_cachestat
+452  common    fchmodat2               sys_fchmodat2                   sys_fchmodat2
index 227538b..1d6eee3 100644 (file)
 449    common  futex_waitv             sys_futex_waitv
 450    common  set_mempolicy_home_node sys_set_mempolicy_home_node
 451    common  cachestat               sys_cachestat
+452    common  fchmodat2               sys_fchmodat2
+453    64      map_shadow_stack        sys_map_shadow_stack
 
 #
 # Due to a historical design error, certain syscalls are numbered differently
index b04ebcd..a01c401 100644 (file)
@@ -9,7 +9,7 @@
 #include <sys/syscall.h>
 #include <sys/ioctl.h>
 #include <linux/time64.h>
-#include <linux/seccomp.h>
+#include <uapi/linux/seccomp.h>
 #include <sys/prctl.h>
 
 #include <unistd.h>
index 4314c91..e21caad 100755 (executable)
@@ -21,6 +21,7 @@ FILES=(
   "include/uapi/linux/perf_event.h"
   "include/uapi/linux/prctl.h"
   "include/uapi/linux/sched.h"
+  "include/uapi/linux/seccomp.h"
   "include/uapi/linux/stat.h"
   "include/uapi/linux/usbdevice_fs.h"
   "include/uapi/linux/vhost.h"
index a7e8833..72ba4a9 100755 (executable)
@@ -991,7 +991,7 @@ const struct pmu_events_table *perf_pmu__find_events_table(struct perf_pmu *pmu)
                 }
         }
         free(cpuid);
-        if (!pmu)
+        if (!pmu || !table)
                 return table;
 
         for (i = 0; i < table->num_pmus; i++) {
index 0e9ec65..3e673f2 100644 (file)
@@ -413,10 +413,10 @@ def has_event(event: Event) -> Function:
   # pylint: disable=invalid-name
   return Function('has_event', event)
 
-def strcmp_cpuid_str(event: str) -> Function:
+def strcmp_cpuid_str(cpuid: Event) -> Function:
   # pylint: disable=redefined-builtin
   # pylint: disable=invalid-name
-  return Function('strcmp_cpuid_str', event)
+  return Function('strcmp_cpuid_str', cpuid)
 
 class Metric:
   """An individual metric that will specifiable on the perf command line."""
diff --git a/tools/perf/util/bpf-prologue.c b/tools/perf/util/bpf-prologue.c
deleted file mode 100644 (file)
index 9887ae0..0000000
+++ /dev/null
@@ -1,508 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * bpf-prologue.c
- *
- * Copyright (C) 2015 He Kuang <hekuang@huawei.com>
- * Copyright (C) 2015 Wang Nan <wangnan0@huawei.com>
- * Copyright (C) 2015 Huawei Inc.
- */
-
-#include <bpf/libbpf.h>
-#include "debug.h"
-#include "bpf-loader.h"
-#include "bpf-prologue.h"
-#include "probe-finder.h"
-#include <errno.h>
-#include <stdlib.h>
-#include <dwarf-regs.h>
-#include <linux/filter.h>
-
-#define BPF_REG_SIZE           8
-
-#define JMP_TO_ERROR_CODE      -1
-#define JMP_TO_SUCCESS_CODE    -2
-#define JMP_TO_USER_CODE       -3
-
-struct bpf_insn_pos {
-       struct bpf_insn *begin;
-       struct bpf_insn *end;
-       struct bpf_insn *pos;
-};
-
-static inline int
-pos_get_cnt(struct bpf_insn_pos *pos)
-{
-       return pos->pos - pos->begin;
-}
-
-static int
-append_insn(struct bpf_insn new_insn, struct bpf_insn_pos *pos)
-{
-       if (!pos->pos)
-               return -BPF_LOADER_ERRNO__PROLOGUE2BIG;
-
-       if (pos->pos + 1 >= pos->end) {
-               pr_err("bpf prologue: prologue too long\n");
-               pos->pos = NULL;
-               return -BPF_LOADER_ERRNO__PROLOGUE2BIG;
-       }
-
-       *(pos->pos)++ = new_insn;
-       return 0;
-}
-
-static int
-check_pos(struct bpf_insn_pos *pos)
-{
-       if (!pos->pos || pos->pos >= pos->end)
-               return -BPF_LOADER_ERRNO__PROLOGUE2BIG;
-       return 0;
-}
-
-/*
- * Convert type string (u8/u16/u32/u64/s8/s16/s32/s64 ..., see
- * Documentation/trace/kprobetrace.rst) to size field of BPF_LDX_MEM
- * instruction (BPF_{B,H,W,DW}).
- */
-static int
-argtype_to_ldx_size(const char *type)
-{
-       int arg_size = type ? atoi(&type[1]) : 64;
-
-       switch (arg_size) {
-       case 8:
-               return BPF_B;
-       case 16:
-               return BPF_H;
-       case 32:
-               return BPF_W;
-       case 64:
-       default:
-               return BPF_DW;
-       }
-}
-
-static const char *
-insn_sz_to_str(int insn_sz)
-{
-       switch (insn_sz) {
-       case BPF_B:
-               return "BPF_B";
-       case BPF_H:
-               return "BPF_H";
-       case BPF_W:
-               return "BPF_W";
-       case BPF_DW:
-               return "BPF_DW";
-       default:
-               return "UNKNOWN";
-       }
-}
-
-/* Give it a shorter name */
-#define ins(i, p) append_insn((i), (p))
-
-/*
- * Give a register name (in 'reg'), generate instruction to
- * load register into an eBPF register rd:
- *   'ldd target_reg, offset(ctx_reg)', where:
- * ctx_reg is pre initialized to pointer of 'struct pt_regs'.
- */
-static int
-gen_ldx_reg_from_ctx(struct bpf_insn_pos *pos, int ctx_reg,
-                    const char *reg, int target_reg)
-{
-       int offset = regs_query_register_offset(reg);
-
-       if (offset < 0) {
-               pr_err("bpf: prologue: failed to get register %s\n",
-                      reg);
-               return offset;
-       }
-       ins(BPF_LDX_MEM(BPF_DW, target_reg, ctx_reg, offset), pos);
-
-       return check_pos(pos);
-}
-
-/*
- * Generate a BPF_FUNC_probe_read function call.
- *
- * src_base_addr_reg is a register holding base address,
- * dst_addr_reg is a register holding dest address (on stack),
- * result is:
- *
- *  *[dst_addr_reg] = *([src_base_addr_reg] + offset)
- *
- * Arguments of BPF_FUNC_probe_read:
- *     ARG1: ptr to stack (dest)
- *     ARG2: size (8)
- *     ARG3: unsafe ptr (src)
- */
-static int
-gen_read_mem(struct bpf_insn_pos *pos,
-            int src_base_addr_reg,
-            int dst_addr_reg,
-            long offset,
-            int probeid)
-{
-       /* mov arg3, src_base_addr_reg */
-       if (src_base_addr_reg != BPF_REG_ARG3)
-               ins(BPF_MOV64_REG(BPF_REG_ARG3, src_base_addr_reg), pos);
-       /* add arg3, #offset */
-       if (offset)
-               ins(BPF_ALU64_IMM(BPF_ADD, BPF_REG_ARG3, offset), pos);
-
-       /* mov arg2, #reg_size */
-       ins(BPF_ALU64_IMM(BPF_MOV, BPF_REG_ARG2, BPF_REG_SIZE), pos);
-
-       /* mov arg1, dst_addr_reg */
-       if (dst_addr_reg != BPF_REG_ARG1)
-               ins(BPF_MOV64_REG(BPF_REG_ARG1, dst_addr_reg), pos);
-
-       /* Call probe_read  */
-       ins(BPF_EMIT_CALL(probeid), pos);
-       /*
-        * Error processing: if read fail, goto error code,
-        * will be relocated. Target should be the start of
-        * error processing code.
-        */
-       ins(BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, JMP_TO_ERROR_CODE),
-           pos);
-
-       return check_pos(pos);
-}
-
-/*
- * Each arg should be bare register. Fetch and save them into argument
- * registers (r3 - r5).
- *
- * BPF_REG_1 should have been initialized with pointer to
- * 'struct pt_regs'.
- */
-static int
-gen_prologue_fastpath(struct bpf_insn_pos *pos,
-                     struct probe_trace_arg *args, int nargs)
-{
-       int i, err = 0;
-
-       for (i = 0; i < nargs; i++) {
-               err = gen_ldx_reg_from_ctx(pos, BPF_REG_1, args[i].value,
-                                          BPF_PROLOGUE_START_ARG_REG + i);
-               if (err)
-                       goto errout;
-       }
-
-       return check_pos(pos);
-errout:
-       return err;
-}
-
-/*
- * Slow path:
- *   At least one argument has the form of 'offset($rx)'.
- *
- * Following code first stores them into stack, then loads all of then
- * to r2 - r5.
- * Before final loading, the final result should be:
- *
- * low address
- * BPF_REG_FP - 24  ARG3
- * BPF_REG_FP - 16  ARG2
- * BPF_REG_FP - 8   ARG1
- * BPF_REG_FP
- * high address
- *
- * For each argument (described as: offn(...off2(off1(reg)))),
- * generates following code:
- *
- *  r7 <- fp
- *  r7 <- r7 - stack_offset  // Ideal code should initialize r7 using
- *                           // fp before generating args. However,
- *                           // eBPF won't regard r7 as stack pointer
- *                           // if it is generated by minus 8 from
- *                           // another stack pointer except fp.
- *                           // This is why we have to set r7
- *                           // to fp for each variable.
- *  r3 <- value of 'reg'-> generated using gen_ldx_reg_from_ctx()
- *  (r7) <- r3       // skip following instructions for bare reg
- *  r3 <- r3 + off1  . // skip if off1 == 0
- *  r2 <- 8           \
- *  r1 <- r7           |-> generated by gen_read_mem()
- *  call probe_read    /
- *  jnei r0, 0, err  ./
- *  r3 <- (r7)
- *  r3 <- r3 + off2  . // skip if off2 == 0
- *  r2 <- 8           \  // r2 may be broken by probe_read, so set again
- *  r1 <- r7           |-> generated by gen_read_mem()
- *  call probe_read    /
- *  jnei r0, 0, err  ./
- *  ...
- */
-static int
-gen_prologue_slowpath(struct bpf_insn_pos *pos,
-                     struct probe_trace_arg *args, int nargs)
-{
-       int err, i, probeid;
-
-       for (i = 0; i < nargs; i++) {
-               struct probe_trace_arg *arg = &args[i];
-               const char *reg = arg->value;
-               struct probe_trace_arg_ref *ref = NULL;
-               int stack_offset = (i + 1) * -8;
-
-               pr_debug("prologue: fetch arg %d, base reg is %s\n",
-                        i, reg);
-
-               /* value of base register is stored into ARG3 */
-               err = gen_ldx_reg_from_ctx(pos, BPF_REG_CTX, reg,
-                                          BPF_REG_ARG3);
-               if (err) {
-                       pr_err("prologue: failed to get offset of register %s\n",
-                              reg);
-                       goto errout;
-               }
-
-               /* Make r7 the stack pointer. */
-               ins(BPF_MOV64_REG(BPF_REG_7, BPF_REG_FP), pos);
-               /* r7 += -8 */
-               ins(BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, stack_offset), pos);
-               /*
-                * Store r3 (base register) onto stack
-                * Ensure fp[offset] is set.
-                * fp is the only valid base register when storing
-                * into stack. We are not allowed to use r7 as base
-                * register here.
-                */
-               ins(BPF_STX_MEM(BPF_DW, BPF_REG_FP, BPF_REG_ARG3,
-                               stack_offset), pos);
-
-               ref = arg->ref;
-               probeid = BPF_FUNC_probe_read_kernel;
-               while (ref) {
-                       pr_debug("prologue: arg %d: offset %ld\n",
-                                i, ref->offset);
-
-                       if (ref->user_access)
-                               probeid = BPF_FUNC_probe_read_user;
-
-                       err = gen_read_mem(pos, BPF_REG_3, BPF_REG_7,
-                                          ref->offset, probeid);
-                       if (err) {
-                               pr_err("prologue: failed to generate probe_read function call\n");
-                               goto errout;
-                       }
-
-                       ref = ref->next;
-                       /*
-                        * Load previous result into ARG3. Use
-                        * BPF_REG_FP instead of r7 because verifier
-                        * allows FP based addressing only.
-                        */
-                       if (ref)
-                               ins(BPF_LDX_MEM(BPF_DW, BPF_REG_ARG3,
-                                               BPF_REG_FP, stack_offset), pos);
-               }
-       }
-
-       /* Final pass: read to registers */
-       for (i = 0; i < nargs; i++) {
-               int insn_sz = (args[i].ref) ? argtype_to_ldx_size(args[i].type) : BPF_DW;
-
-               pr_debug("prologue: load arg %d, insn_sz is %s\n",
-                        i, insn_sz_to_str(insn_sz));
-               ins(BPF_LDX_MEM(insn_sz, BPF_PROLOGUE_START_ARG_REG + i,
-                               BPF_REG_FP, -BPF_REG_SIZE * (i + 1)), pos);
-       }
-
-       ins(BPF_JMP_IMM(BPF_JA, BPF_REG_0, 0, JMP_TO_SUCCESS_CODE), pos);
-
-       return check_pos(pos);
-errout:
-       return err;
-}
-
-static int
-prologue_relocate(struct bpf_insn_pos *pos, struct bpf_insn *error_code,
-                 struct bpf_insn *success_code, struct bpf_insn *user_code)
-{
-       struct bpf_insn *insn;
-
-       if (check_pos(pos))
-               return -BPF_LOADER_ERRNO__PROLOGUE2BIG;
-
-       for (insn = pos->begin; insn < pos->pos; insn++) {
-               struct bpf_insn *target;
-               u8 class = BPF_CLASS(insn->code);
-               u8 opcode;
-
-               if (class != BPF_JMP)
-                       continue;
-               opcode = BPF_OP(insn->code);
-               if (opcode == BPF_CALL)
-                       continue;
-
-               switch (insn->off) {
-               case JMP_TO_ERROR_CODE:
-                       target = error_code;
-                       break;
-               case JMP_TO_SUCCESS_CODE:
-                       target = success_code;
-                       break;
-               case JMP_TO_USER_CODE:
-                       target = user_code;
-                       break;
-               default:
-                       pr_err("bpf prologue: internal error: relocation failed\n");
-                       return -BPF_LOADER_ERRNO__PROLOGUE;
-               }
-
-               insn->off = target - (insn + 1);
-       }
-       return 0;
-}
-
-int bpf__gen_prologue(struct probe_trace_arg *args, int nargs,
-                     struct bpf_insn *new_prog, size_t *new_cnt,
-                     size_t cnt_space)
-{
-       struct bpf_insn *success_code = NULL;
-       struct bpf_insn *error_code = NULL;
-       struct bpf_insn *user_code = NULL;
-       struct bpf_insn_pos pos;
-       bool fastpath = true;
-       int err = 0, i;
-
-       if (!new_prog || !new_cnt)
-               return -EINVAL;
-
-       if (cnt_space > BPF_MAXINSNS)
-               cnt_space = BPF_MAXINSNS;
-
-       pos.begin = new_prog;
-       pos.end = new_prog + cnt_space;
-       pos.pos = new_prog;
-
-       if (!nargs) {
-               ins(BPF_ALU64_IMM(BPF_MOV, BPF_PROLOGUE_FETCH_RESULT_REG, 0),
-                   &pos);
-
-               if (check_pos(&pos))
-                       goto errout;
-
-               *new_cnt = pos_get_cnt(&pos);
-               return 0;
-       }
-
-       if (nargs > BPF_PROLOGUE_MAX_ARGS) {
-               pr_warning("bpf: prologue: %d arguments are dropped\n",
-                          nargs - BPF_PROLOGUE_MAX_ARGS);
-               nargs = BPF_PROLOGUE_MAX_ARGS;
-       }
-
-       /* First pass: validation */
-       for (i = 0; i < nargs; i++) {
-               struct probe_trace_arg_ref *ref = args[i].ref;
-
-               if (args[i].value[0] == '@') {
-                       /* TODO: fetch global variable */
-                       pr_err("bpf: prologue: global %s%+ld not support\n",
-                               args[i].value, ref ? ref->offset : 0);
-                       return -ENOTSUP;
-               }
-
-               while (ref) {
-                       /* fastpath is true if all args has ref == NULL */
-                       fastpath = false;
-
-                       /*
-                        * Instruction encodes immediate value using
-                        * s32, ref->offset is long. On systems which
-                        * can't fill long in s32, refuse to process if
-                        * ref->offset too large (or small).
-                        */
-#ifdef __LP64__
-#define OFFSET_MAX     ((1LL << 31) - 1)
-#define OFFSET_MIN     ((1LL << 31) * -1)
-                       if (ref->offset > OFFSET_MAX ||
-                                       ref->offset < OFFSET_MIN) {
-                               pr_err("bpf: prologue: offset out of bound: %ld\n",
-                                      ref->offset);
-                               return -BPF_LOADER_ERRNO__PROLOGUEOOB;
-                       }
-#endif
-                       ref = ref->next;
-               }
-       }
-       pr_debug("prologue: pass validation\n");
-
-       if (fastpath) {
-               /* If all variables are registers... */
-               pr_debug("prologue: fast path\n");
-               err = gen_prologue_fastpath(&pos, args, nargs);
-               if (err)
-                       goto errout;
-       } else {
-               pr_debug("prologue: slow path\n");
-
-               /* Initialization: move ctx to a callee saved register. */
-               ins(BPF_MOV64_REG(BPF_REG_CTX, BPF_REG_ARG1), &pos);
-
-               err = gen_prologue_slowpath(&pos, args, nargs);
-               if (err)
-                       goto errout;
-               /*
-                * start of ERROR_CODE (only slow pass needs error code)
-                *   mov r2 <- 1  // r2 is error number
-                *   mov r3 <- 0  // r3, r4... should be touched or
-                *                // verifier would complain
-                *   mov r4 <- 0
-                *   ...
-                *   goto usercode
-                */
-               error_code = pos.pos;
-               ins(BPF_ALU64_IMM(BPF_MOV, BPF_PROLOGUE_FETCH_RESULT_REG, 1),
-                   &pos);
-
-               for (i = 0; i < nargs; i++)
-                       ins(BPF_ALU64_IMM(BPF_MOV,
-                                         BPF_PROLOGUE_START_ARG_REG + i,
-                                         0),
-                           &pos);
-               ins(BPF_JMP_IMM(BPF_JA, BPF_REG_0, 0, JMP_TO_USER_CODE),
-                               &pos);
-       }
-
-       /*
-        * start of SUCCESS_CODE:
-        *   mov r2 <- 0
-        *   goto usercode  // skip
-        */
-       success_code = pos.pos;
-       ins(BPF_ALU64_IMM(BPF_MOV, BPF_PROLOGUE_FETCH_RESULT_REG, 0), &pos);
-
-       /*
-        * start of USER_CODE:
-        *   Restore ctx to r1
-        */
-       user_code = pos.pos;
-       if (!fastpath) {
-               /*
-                * Only slow path needs restoring of ctx. In fast path,
-                * register are loaded directly from r1.
-                */
-               ins(BPF_MOV64_REG(BPF_REG_ARG1, BPF_REG_CTX), &pos);
-               err = prologue_relocate(&pos, error_code, success_code,
-                                       user_code);
-               if (err)
-                       goto errout;
-       }
-
-       err = check_pos(&pos);
-       if (err)
-               goto errout;
-
-       *new_cnt = pos_get_cnt(&pos);
-       return 0;
-errout:
-       return err;
-}
index 90ce22f..939ec76 100644 (file)
@@ -23,7 +23,9 @@
 #define MAX_CPUS  4096
 
 // FIXME: These should come from system headers
+#ifndef bool
 typedef char bool;
+#endif
 typedef int pid_t;
 typedef long long int __s64;
 typedef __s64 time64_t;
index 0a5bf19..c12f832 100644 (file)
@@ -80,16 +80,6 @@ struct hashmap {
        size_t sz;
 };
 
-#define HASHMAP_INIT(hash_fn, equal_fn, ctx) { \
-       .hash_fn = (hash_fn),                   \
-       .equal_fn = (equal_fn),                 \
-       .ctx = (ctx),                           \
-       .buckets = NULL,                        \
-       .cap = 0,                               \
-       .cap_bits = 0,                          \
-       .sz = 0,                                \
-}
-
 void hashmap__init(struct hashmap *map, hashmap_hash_fn hash_fn,
                   hashmap_equal_fn equal_fn, void *ctx);
 struct hashmap *hashmap__new(hashmap_hash_fn hash_fn,
index d85602a..8de6f39 100644 (file)
@@ -520,7 +520,7 @@ static int perf_pmu__new_alias(struct perf_pmu *pmu, const char *name,
                pmu_name = pe->pmu;
        }
 
-       alias = malloc(sizeof(*alias));
+       alias = zalloc(sizeof(*alias));
        if (!alias)
                return -ENOMEM;
 
index fdb7f5d..f6c6e54 100644 (file)
@@ -20,4 +20,8 @@ void memblock_free_pages(struct page *page, unsigned long pfn,
 {
 }
 
+static inline void accept_memory(phys_addr_t start, phys_addr_t end)
+{
+}
+
 #endif
index 7b0909e..d3d5885 100644 (file)
@@ -11,7 +11,7 @@ struct pglist_data *next_online_pgdat(struct pglist_data *pgdat)
        return NULL;
 }
 
-void reserve_bootmem_region(phys_addr_t start, phys_addr_t end)
+void reserve_bootmem_region(phys_addr_t start, phys_addr_t end, int nid)
 {
 }
 
index 4116470..57bf268 100644 (file)
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
+#include "basic_api.h"
 #include <string.h>
 #include <linux/memblock.h>
-#include "basic_api.h"
 
 #define EXPECTED_MEMBLOCK_REGIONS                      128
 #define FUNC_ADD                                       "memblock_add"
index 4f23302..b5ec59a 100644 (file)
@@ -5,6 +5,7 @@
 #include <stdlib.h>
 #include <assert.h>
 #include <linux/types.h>
+#include <linux/seq_file.h>
 #include <linux/memblock.h>
 #include <linux/sizes.h>
 #include <linux/printk.h>
index 42806ad..1a21d6b 100644 (file)
@@ -92,7 +92,7 @@ endif
 TARGETS += tmpfs
 TARGETS += tpm2
 TARGETS += tty
-TARGETS += uevents
+TARGETS += uevent
 TARGETS += user
 TARGETS += user_events
 TARGETS += vDSO
index d7aafe5..2f1685a 100644 (file)
@@ -431,7 +431,6 @@ long conf_get_long(snd_config_t *root, const char *key1, const char *key2, long
 int conf_get_bool(snd_config_t *root, const char *key1, const char *key2, int def)
 {
        snd_config_t *cfg;
-       long l;
        int ret;
 
        if (!root)
index c95d63e..21e482b 100644 (file)
@@ -188,7 +188,7 @@ static int wait_for_event(struct ctl_data *ctl, int timeout)
 {
        unsigned short revents;
        snd_ctl_event_t *event;
-       int count, err;
+       int err;
        unsigned int mask = 0;
        unsigned int ev_id;
 
@@ -430,7 +430,6 @@ static bool strend(const char *haystack, const char *needle)
 static void test_ctl_name(struct ctl_data *ctl)
 {
        bool name_ok = true;
-       bool check;
 
        ksft_print_msg("%d.%d %s\n", ctl->card->card, ctl->elem,
                       ctl->name);
@@ -863,7 +862,6 @@ static bool test_ctl_write_invalid_value(struct ctl_data *ctl,
                                         snd_ctl_elem_value_t *val)
 {
        int err;
-       long val_read;
 
        /* Ideally this will fail... */
        err = snd_ctl_elem_write(ctl->card->handle, val);
@@ -883,8 +881,7 @@ static bool test_ctl_write_invalid_value(struct ctl_data *ctl,
 
 static bool test_ctl_write_invalid_boolean(struct ctl_data *ctl)
 {
-       int err, i;
-       long val_read;
+       int i;
        bool fail = false;
        snd_ctl_elem_value_t *val;
        snd_ctl_elem_value_alloca(&val);
@@ -994,8 +991,7 @@ static bool test_ctl_write_invalid_integer64(struct ctl_data *ctl)
 
 static bool test_ctl_write_invalid_enumerated(struct ctl_data *ctl)
 {
-       int err, i;
-       unsigned int val_read;
+       int i;
        bool fail = false;
        snd_ctl_elem_value_t *val;
        snd_ctl_elem_value_alloca(&val);
@@ -1027,7 +1023,6 @@ static bool test_ctl_write_invalid_enumerated(struct ctl_data *ctl)
 static void test_ctl_write_invalid(struct ctl_data *ctl)
 {
        bool pass;
-       int err;
 
        /* If the control is turned off let's be polite */
        if (snd_ctl_elem_info_is_inactive(ctl->info)) {
index 2f5e3c4..c0a3981 100644 (file)
@@ -257,7 +257,7 @@ static void find_pcms(void)
 static void test_pcm_time(struct pcm_data *data, enum test_class class,
                          const char *test_name, snd_config_t *pcm_cfg)
 {
-       char name[64], key[128], msg[256];
+       char name[64], msg[256];
        const int duration_s = 2, margin_ms = 100;
        const int duration_ms = duration_s * 1000;
        const char *cs;
@@ -567,7 +567,7 @@ int main(void)
 {
        struct card_data *card;
        struct pcm_data *pcm;
-       snd_config_t *global_config, *cfg, *pcm_cfg;
+       snd_config_t *global_config, *cfg;
        int num_pcm_tests = 0, num_tests, num_std_pcm_tests;
        int ret;
        void *thread_ret;
index 357adc7..a52ecd4 100644 (file)
@@ -313,7 +313,6 @@ TEST_F(pcmtest, ni_playback) {
  */
 TEST_F(pcmtest, reset_ioctl) {
        snd_pcm_t *handle;
-       unsigned char *it;
        int test_res;
        struct pcmtest_test_params *params = &self->params;
 
index 7f768d3..3babaf3 100644 (file)
@@ -1,14 +1,8 @@
 bpf_cookie/multi_kprobe_attach_api               # kprobe_multi_link_api_subtest:FAIL:fentry_raw_skel_load unexpected error: -3
 bpf_cookie/multi_kprobe_link_api                 # kprobe_multi_link_api_subtest:FAIL:fentry_raw_skel_load unexpected error: -3
 fexit_sleep                                      # The test never returns. The remaining tests cannot start.
-kprobe_multi_bench_attach                        # bpf_program__attach_kprobe_multi_opts unexpected error: -95
-kprobe_multi_test/attach_api_addrs               # bpf_program__attach_kprobe_multi_opts unexpected error: -95
-kprobe_multi_test/attach_api_pattern             # bpf_program__attach_kprobe_multi_opts unexpected error: -95
-kprobe_multi_test/attach_api_syms                # bpf_program__attach_kprobe_multi_opts unexpected error: -95
-kprobe_multi_test/bench_attach                   # bpf_program__attach_kprobe_multi_opts unexpected error: -95
-kprobe_multi_test/link_api_addrs                 # link_fd unexpected link_fd: actual -95 < expected 0
-kprobe_multi_test/link_api_syms                  # link_fd unexpected link_fd: actual -95 < expected 0
-kprobe_multi_test/skel_api                       # libbpf: failed to load BPF skeleton 'kprobe_multi': -3
+kprobe_multi_bench_attach                        # needs CONFIG_FPROBE
+kprobe_multi_test                                # needs CONFIG_FPROBE
 module_attach                                    # prog 'kprobe_multi': failed to auto-attach: -95
 fentry_test/fentry_many_args                     # fentry_many_args:FAIL:fentry_many_args_attach unexpected error: -524
 fexit_test/fexit_many_args                       # fexit_many_args:FAIL:fexit_many_args_attach unexpected error: -524
index 1c7584e..e41eb33 100644 (file)
@@ -4,6 +4,7 @@ CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
 CONFIG_BPF=y
 CONFIG_BPF_EVENTS=y
 CONFIG_BPF_JIT=y
+CONFIG_BPF_KPROBE_OVERRIDE=y
 CONFIG_BPF_LIRC_MODE2=y
 CONFIG_BPF_LSM=y
 CONFIG_BPF_STREAM_PARSER=y
index b650b2e..2e70a60 100644 (file)
@@ -20,7 +20,6 @@ CONFIG_BLK_DEV_THROTTLING=y
 CONFIG_BONDING=y
 CONFIG_BOOTTIME_TRACING=y
 CONFIG_BPF_JIT_ALWAYS_ON=y
-CONFIG_BPF_KPROBE_OVERRIDE=y
 CONFIG_BPF_PRELOAD=y
 CONFIG_BPF_PRELOAD_UMD=y
 CONFIG_BPFILTER=y
index a53c254..4aabeaa 100644 (file)
@@ -185,6 +185,8 @@ static void test_cubic(void)
 
        do_test("bpf_cubic", NULL);
 
+       ASSERT_EQ(cubic_skel->bss->bpf_cubic_acked_called, 1, "pkts_acked called");
+
        bpf_link__destroy(link);
        bpf_cubic__destroy(cubic_skel);
 }
index 3b77d8a..261228e 100644 (file)
@@ -24,6 +24,7 @@ void test_empty_skb(void)
                int *ifindex;
                int err;
                int ret;
+               int lwt_egress_ret; /* expected retval at lwt/egress */
                bool success_on_tc;
        } tests[] = {
                /* Empty packets are always rejected. */
@@ -57,6 +58,7 @@ void test_empty_skb(void)
                        .data_size_in = sizeof(eth_hlen),
                        .ifindex = &veth_ifindex,
                        .ret = -ERANGE,
+                       .lwt_egress_ret = -ERANGE,
                        .success_on_tc = true,
                },
                {
@@ -70,6 +72,7 @@ void test_empty_skb(void)
                        .data_size_in = sizeof(eth_hlen),
                        .ifindex = &ipip_ifindex,
                        .ret = -ERANGE,
+                       .lwt_egress_ret = -ERANGE,
                },
 
                /* ETH_HLEN+1-sized packet should be redirected. */
@@ -79,6 +82,7 @@ void test_empty_skb(void)
                        .data_in = eth_hlen_pp,
                        .data_size_in = sizeof(eth_hlen_pp),
                        .ifindex = &veth_ifindex,
+                       .lwt_egress_ret = 1, /* veth_xmit NET_XMIT_DROP */
                },
                {
                        .msg = "ipip ETH_HLEN+1 packet ingress",
@@ -108,8 +112,12 @@ void test_empty_skb(void)
 
        for (i = 0; i < ARRAY_SIZE(tests); i++) {
                bpf_object__for_each_program(prog, bpf_obj->obj) {
-                       char buf[128];
+                       bool at_egress = strstr(bpf_program__name(prog), "egress") != NULL;
                        bool at_tc = !strncmp(bpf_program__section_name(prog), "tc", 2);
+                       int expected_ret;
+                       char buf[128];
+
+                       expected_ret = at_egress && !at_tc ? tests[i].lwt_egress_ret : tests[i].ret;
 
                        tattr.data_in = tests[i].data_in;
                        tattr.data_size_in = tests[i].data_size_in;
@@ -128,7 +136,7 @@ void test_empty_skb(void)
                        if (at_tc && tests[i].success_on_tc)
                                ASSERT_GE(bpf_obj->bss->ret, 0, buf);
                        else
-                               ASSERT_EQ(bpf_obj->bss->ret, tests[i].ret, buf);
+                               ASSERT_EQ(bpf_obj->bss->ret, expected_ret, buf);
                }
        }
 
index 179fe30..4041cfa 100644 (file)
@@ -3,6 +3,7 @@
 #include "kprobe_multi.skel.h"
 #include "trace_helpers.h"
 #include "kprobe_multi_empty.skel.h"
+#include "kprobe_multi_override.skel.h"
 #include "bpf/libbpf_internal.h"
 #include "bpf/hashmap.h"
 
@@ -453,6 +454,40 @@ cleanup:
        }
 }
 
+static void test_attach_override(void)
+{
+       struct kprobe_multi_override *skel = NULL;
+       struct bpf_link *link = NULL;
+
+       skel = kprobe_multi_override__open_and_load();
+       if (!ASSERT_OK_PTR(skel, "kprobe_multi_empty__open_and_load"))
+               goto cleanup;
+
+       /* The test_override calls bpf_override_return so it should fail
+        * to attach to bpf_fentry_test1 function, which is not on error
+        * injection list.
+        */
+       link = bpf_program__attach_kprobe_multi_opts(skel->progs.test_override,
+                                                    "bpf_fentry_test1", NULL);
+       if (!ASSERT_ERR_PTR(link, "override_attached_bpf_fentry_test1")) {
+               bpf_link__destroy(link);
+               goto cleanup;
+       }
+
+       /* The should_fail_bio function is on error injection list,
+        * attach should succeed.
+        */
+       link = bpf_program__attach_kprobe_multi_opts(skel->progs.test_override,
+                                                    "should_fail_bio", NULL);
+       if (!ASSERT_OK_PTR(link, "override_attached_should_fail_bio"))
+               goto cleanup;
+
+       bpf_link__destroy(link);
+
+cleanup:
+       kprobe_multi_override__destroy(skel);
+}
+
 void serial_test_kprobe_multi_bench_attach(void)
 {
        if (test__start_subtest("kernel"))
@@ -480,4 +515,6 @@ void test_kprobe_multi_test(void)
                test_attach_api_syms();
        if (test__start_subtest("attach_api_fails"))
                test_attach_api_fails();
+       if (test__start_subtest("attach_override"))
+               test_attach_override();
 }
index 064cc5e..dda7060 100644 (file)
@@ -475,6 +475,55 @@ out:
                test_sockmap_drop_prog__destroy(drop);
 }
 
+static void test_sockmap_skb_verdict_peek(void)
+{
+       int err, map, verdict, s, c1, p1, zero = 0, sent, recvd, avail;
+       struct test_sockmap_pass_prog *pass;
+       char snd[256] = "0123456789";
+       char rcv[256] = "0";
+
+       pass = test_sockmap_pass_prog__open_and_load();
+       if (!ASSERT_OK_PTR(pass, "open_and_load"))
+               return;
+       verdict = bpf_program__fd(pass->progs.prog_skb_verdict);
+       map = bpf_map__fd(pass->maps.sock_map_rx);
+
+       err = bpf_prog_attach(verdict, map, BPF_SK_SKB_STREAM_VERDICT, 0);
+       if (!ASSERT_OK(err, "bpf_prog_attach"))
+               goto out;
+
+       s = socket_loopback(AF_INET, SOCK_STREAM);
+       if (!ASSERT_GT(s, -1, "socket_loopback(s)"))
+               goto out;
+
+       err = create_pair(s, AF_INET, SOCK_STREAM, &c1, &p1);
+       if (!ASSERT_OK(err, "create_pairs(s)"))
+               goto out;
+
+       err = bpf_map_update_elem(map, &zero, &c1, BPF_NOEXIST);
+       if (!ASSERT_OK(err, "bpf_map_update_elem(c1)"))
+               goto out_close;
+
+       sent = xsend(p1, snd, sizeof(snd), 0);
+       ASSERT_EQ(sent, sizeof(snd), "xsend(p1)");
+       recvd = recv(c1, rcv, sizeof(rcv), MSG_PEEK);
+       ASSERT_EQ(recvd, sizeof(rcv), "recv(c1)");
+       err = ioctl(c1, FIONREAD, &avail);
+       ASSERT_OK(err, "ioctl(FIONREAD) error");
+       ASSERT_EQ(avail, sizeof(snd), "after peek ioctl(FIONREAD)");
+       recvd = recv(c1, rcv, sizeof(rcv), 0);
+       ASSERT_EQ(recvd, sizeof(rcv), "recv(p0)");
+       err = ioctl(c1, FIONREAD, &avail);
+       ASSERT_OK(err, "ioctl(FIONREAD) error");
+       ASSERT_EQ(avail, 0, "after read ioctl(FIONREAD)");
+
+out_close:
+       close(c1);
+       close(p1);
+out:
+       test_sockmap_pass_prog__destroy(pass);
+}
+
 void test_sockmap_basic(void)
 {
        if (test__start_subtest("sockmap create_update_free"))
@@ -515,4 +564,6 @@ void test_sockmap_basic(void)
                test_sockmap_skb_verdict_fionread(true);
        if (test__start_subtest("sockmap skb_verdict fionread on drop"))
                test_sockmap_skb_verdict_fionread(false);
+       if (test__start_subtest("sockmap skb_verdict msg_f_peek"))
+               test_sockmap_skb_verdict_peek();
 }
index 7a2ecd4..99af79e 100644 (file)
@@ -2378,3 +2378,87 @@ void serial_test_tc_opts_chain_mixed(void)
        test_tc_chain_mixed(BPF_TCX_INGRESS);
        test_tc_chain_mixed(BPF_TCX_EGRESS);
 }
+
+static int generate_dummy_prog(void)
+{
+       const struct bpf_insn prog_insns[] = {
+               BPF_MOV64_IMM(BPF_REG_0, 0),
+               BPF_EXIT_INSN(),
+       };
+       const size_t prog_insn_cnt = sizeof(prog_insns) / sizeof(struct bpf_insn);
+       LIBBPF_OPTS(bpf_prog_load_opts, opts);
+       const size_t log_buf_sz = 256;
+       char *log_buf;
+       int fd = -1;
+
+       log_buf = malloc(log_buf_sz);
+       if (!ASSERT_OK_PTR(log_buf, "log_buf_alloc"))
+               return fd;
+       opts.log_buf = log_buf;
+       opts.log_size = log_buf_sz;
+
+       log_buf[0] = '\0';
+       opts.log_level = 0;
+       fd = bpf_prog_load(BPF_PROG_TYPE_SCHED_CLS, "tcx_prog", "GPL",
+                          prog_insns, prog_insn_cnt, &opts);
+       ASSERT_STREQ(log_buf, "", "log_0");
+       ASSERT_GE(fd, 0, "prog_fd");
+       free(log_buf);
+       return fd;
+}
+
+static void test_tc_opts_max_target(int target, int flags, bool relative)
+{
+       int err, ifindex, i, prog_fd, last_fd = -1;
+       LIBBPF_OPTS(bpf_prog_attach_opts, opta);
+       const int max_progs = 63;
+
+       ASSERT_OK(system("ip link add dev tcx_opts1 type veth peer name tcx_opts2"), "add veth");
+       ifindex = if_nametoindex("tcx_opts1");
+       ASSERT_NEQ(ifindex, 0, "non_zero_ifindex");
+
+       assert_mprog_count_ifindex(ifindex, target, 0);
+
+       for (i = 0; i < max_progs; i++) {
+               prog_fd = generate_dummy_prog();
+               if (!ASSERT_GE(prog_fd, 0, "dummy_prog"))
+                       goto cleanup;
+               err = bpf_prog_attach_opts(prog_fd, ifindex, target, &opta);
+               if (!ASSERT_EQ(err, 0, "prog_attach"))
+                       goto cleanup;
+               assert_mprog_count_ifindex(ifindex, target, i + 1);
+               if (i == max_progs - 1 && relative)
+                       last_fd = prog_fd;
+               else
+                       close(prog_fd);
+       }
+
+       prog_fd = generate_dummy_prog();
+       if (!ASSERT_GE(prog_fd, 0, "dummy_prog"))
+               goto cleanup;
+       opta.flags = flags;
+       if (last_fd > 0)
+               opta.relative_fd = last_fd;
+       err = bpf_prog_attach_opts(prog_fd, ifindex, target, &opta);
+       ASSERT_EQ(err, -ERANGE, "prog_64_attach");
+       assert_mprog_count_ifindex(ifindex, target, max_progs);
+       close(prog_fd);
+cleanup:
+       if (last_fd > 0)
+               close(last_fd);
+       ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth");
+       ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed");
+       ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed");
+}
+
+void serial_test_tc_opts_max(void)
+{
+       test_tc_opts_max_target(BPF_TCX_INGRESS, 0, false);
+       test_tc_opts_max_target(BPF_TCX_EGRESS, 0, false);
+
+       test_tc_opts_max_target(BPF_TCX_INGRESS, BPF_F_BEFORE, false);
+       test_tc_opts_max_target(BPF_TCX_EGRESS, BPF_F_BEFORE, true);
+
+       test_tc_opts_max_target(BPF_TCX_INGRESS, BPF_F_AFTER, true);
+       test_tc_opts_max_target(BPF_TCX_EGRESS, BPF_F_AFTER, false);
+}
diff --git a/tools/testing/selftests/bpf/prog_tests/test_bpf_ma.c b/tools/testing/selftests/bpf/prog_tests/test_bpf_ma.c
new file mode 100644 (file)
index 0000000..0cca4e8
--- /dev/null
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2023. Huawei Technologies Co., Ltd */
+#define _GNU_SOURCE
+#include <sched.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <bpf/btf.h>
+#include <test_progs.h>
+
+#include "test_bpf_ma.skel.h"
+
+void test_test_bpf_ma(void)
+{
+       struct test_bpf_ma *skel;
+       struct btf *btf;
+       int i, err;
+
+       skel = test_bpf_ma__open();
+       if (!ASSERT_OK_PTR(skel, "open"))
+               return;
+
+       btf = bpf_object__btf(skel->obj);
+       if (!ASSERT_OK_PTR(btf, "btf"))
+               goto out;
+
+       for (i = 0; i < ARRAY_SIZE(skel->rodata->data_sizes); i++) {
+               char name[32];
+               int id;
+
+               snprintf(name, sizeof(name), "bin_data_%u", skel->rodata->data_sizes[i]);
+               id = btf__find_by_name_kind(btf, name, BTF_KIND_STRUCT);
+               if (!ASSERT_GT(id, 0, "bin_data"))
+                       goto out;
+               skel->rodata->data_btf_ids[i] = id;
+       }
+
+       err = test_bpf_ma__load(skel);
+       if (!ASSERT_OK(err, "load"))
+               goto out;
+
+       err = test_bpf_ma__attach(skel);
+       if (!ASSERT_OK(err, "attach"))
+               goto out;
+
+       skel->bss->pid = getpid();
+       usleep(1);
+       ASSERT_OK(skel->bss->err, "test error");
+out:
+       test_bpf_ma__destroy(skel);
+}
diff --git a/tools/testing/selftests/bpf/prog_tests/xdp_dev_bound_only.c b/tools/testing/selftests/bpf/prog_tests/xdp_dev_bound_only.c
new file mode 100644 (file)
index 0000000..7dd18c6
--- /dev/null
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <net/if.h>
+#include <test_progs.h>
+#include <network_helpers.h>
+
+#define LOCAL_NETNS "xdp_dev_bound_only_netns"
+
+static int load_dummy_prog(char *name, __u32 ifindex, __u32 flags)
+{
+       struct bpf_insn insns[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN() };
+       LIBBPF_OPTS(bpf_prog_load_opts, opts);
+
+       opts.prog_flags = flags;
+       opts.prog_ifindex = ifindex;
+       return bpf_prog_load(BPF_PROG_TYPE_XDP, name, "GPL", insns, ARRAY_SIZE(insns), &opts);
+}
+
+/* A test case for bpf_offload_netdev->offload handling bug:
+ * - create a veth device (does not support offload);
+ * - create a device bound XDP program with BPF_F_XDP_DEV_BOUND_ONLY flag
+ *   (such programs are not offloaded);
+ * - create a device bound XDP program without flags (such programs are offloaded).
+ * This might lead to 'BUG: kernel NULL pointer dereference'.
+ */
+void test_xdp_dev_bound_only_offdev(void)
+{
+       struct nstoken *tok = NULL;
+       __u32 ifindex;
+       int fd1 = -1;
+       int fd2 = -1;
+
+       SYS(out, "ip netns add " LOCAL_NETNS);
+       tok = open_netns(LOCAL_NETNS);
+       if (!ASSERT_OK_PTR(tok, "open_netns"))
+               goto out;
+       SYS(out, "ip link add eth42 type veth");
+       ifindex = if_nametoindex("eth42");
+       if (!ASSERT_NEQ(ifindex, 0, "if_nametoindex")) {
+               perror("if_nametoindex");
+               goto out;
+       }
+       fd1 = load_dummy_prog("dummy1", ifindex, BPF_F_XDP_DEV_BOUND_ONLY);
+       if (!ASSERT_GE(fd1, 0, "load_dummy_prog #1")) {
+               perror("load_dummy_prog #1");
+               goto out;
+       }
+       /* Program with ifindex is considered offloaded, however veth
+        * does not support offload => error should be reported.
+        */
+       fd2 = load_dummy_prog("dummy2", ifindex, 0);
+       ASSERT_EQ(fd2, -EINVAL, "load_dummy_prog #2 (offloaded)");
+
+out:
+       close(fd1);
+       close(fd2);
+       close_netns(tok);
+       /* eth42 was added inside netns, removing the netns will
+        * also remove eth42 veth pair.
+        */
+       SYS_NOFAIL("ip netns del " LOCAL_NETNS);
+}
index d9660e7..c997e3e 100644 (file)
@@ -490,6 +490,8 @@ static __always_inline void hystart_update(struct sock *sk, __u32 delay)
        }
 }
 
+int bpf_cubic_acked_called = 0;
+
 void BPF_STRUCT_OPS(bpf_cubic_acked, struct sock *sk,
                    const struct ack_sample *sample)
 {
@@ -497,6 +499,7 @@ void BPF_STRUCT_OPS(bpf_cubic_acked, struct sock *sk,
        struct bictcp *ca = inet_csk_ca(sk);
        __u32 delay;
 
+       bpf_cubic_acked_called = 1;
        /* Some calls are for duplicates without timetamps */
        if (sample->rtt_us < 0)
                return;
diff --git a/tools/testing/selftests/bpf/progs/kprobe_multi_override.c b/tools/testing/selftests/bpf/progs/kprobe_multi_override.c
new file mode 100644 (file)
index 0000000..28f8487
--- /dev/null
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/bpf.h>
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_tracing.h>
+
+char _license[] SEC("license") = "GPL";
+
+SEC("kprobe.multi")
+int test_override(struct pt_regs *ctx)
+{
+       bpf_override_return(ctx, 123);
+       return 0;
+}
diff --git a/tools/testing/selftests/bpf/progs/test_bpf_ma.c b/tools/testing/selftests/bpf/progs/test_bpf_ma.c
new file mode 100644 (file)
index 0000000..ecde41a
--- /dev/null
@@ -0,0 +1,123 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2023. Huawei Technologies Co., Ltd */
+#include <vmlinux.h>
+#include <bpf/bpf_tracing.h>
+#include <bpf/bpf_helpers.h>
+
+#include "bpf_experimental.h"
+#include "bpf_misc.h"
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#endif
+
+struct generic_map_value {
+       void *data;
+};
+
+char _license[] SEC("license") = "GPL";
+
+const unsigned int data_sizes[] = {8, 16, 32, 64, 96, 128, 192, 256, 512, 1024, 2048, 4096};
+const volatile unsigned int data_btf_ids[ARRAY_SIZE(data_sizes)] = {};
+
+int err = 0;
+int pid = 0;
+
+#define DEFINE_ARRAY_WITH_KPTR(_size) \
+       struct bin_data_##_size { \
+               char data[_size - sizeof(void *)]; \
+       }; \
+       struct map_value_##_size { \
+               struct bin_data_##_size __kptr * data; \
+               /* To emit BTF info for bin_data_xx */ \
+               struct bin_data_##_size not_used; \
+       }; \
+       struct { \
+               __uint(type, BPF_MAP_TYPE_ARRAY); \
+               __type(key, int); \
+               __type(value, struct map_value_##_size); \
+               __uint(max_entries, 128); \
+       } array_##_size SEC(".maps");
+
+static __always_inline void batch_alloc_free(struct bpf_map *map, unsigned int batch,
+                                            unsigned int idx)
+{
+       struct generic_map_value *value;
+       unsigned int i, key;
+       void *old, *new;
+
+       for (i = 0; i < batch; i++) {
+               key = i;
+               value = bpf_map_lookup_elem(map, &key);
+               if (!value) {
+                       err = 1;
+                       return;
+               }
+               new = bpf_obj_new_impl(data_btf_ids[idx], NULL);
+               if (!new) {
+                       err = 2;
+                       return;
+               }
+               old = bpf_kptr_xchg(&value->data, new);
+               if (old) {
+                       bpf_obj_drop(old);
+                       err = 3;
+                       return;
+               }
+       }
+       for (i = 0; i < batch; i++) {
+               key = i;
+               value = bpf_map_lookup_elem(map, &key);
+               if (!value) {
+                       err = 4;
+                       return;
+               }
+               old = bpf_kptr_xchg(&value->data, NULL);
+               if (!old) {
+                       err = 5;
+                       return;
+               }
+               bpf_obj_drop(old);
+       }
+}
+
+#define CALL_BATCH_ALLOC_FREE(size, batch, idx) \
+       batch_alloc_free((struct bpf_map *)(&array_##size), batch, idx)
+
+DEFINE_ARRAY_WITH_KPTR(8);
+DEFINE_ARRAY_WITH_KPTR(16);
+DEFINE_ARRAY_WITH_KPTR(32);
+DEFINE_ARRAY_WITH_KPTR(64);
+DEFINE_ARRAY_WITH_KPTR(96);
+DEFINE_ARRAY_WITH_KPTR(128);
+DEFINE_ARRAY_WITH_KPTR(192);
+DEFINE_ARRAY_WITH_KPTR(256);
+DEFINE_ARRAY_WITH_KPTR(512);
+DEFINE_ARRAY_WITH_KPTR(1024);
+DEFINE_ARRAY_WITH_KPTR(2048);
+DEFINE_ARRAY_WITH_KPTR(4096);
+
+SEC("fentry/" SYS_PREFIX "sys_nanosleep")
+int test_bpf_mem_alloc_free(void *ctx)
+{
+       if ((u32)bpf_get_current_pid_tgid() != pid)
+               return 0;
+
+       /* Alloc 128 8-bytes objects in batch to trigger refilling,
+        * then free 128 8-bytes objects in batch to trigger freeing.
+        */
+       CALL_BATCH_ALLOC_FREE(8, 128, 0);
+       CALL_BATCH_ALLOC_FREE(16, 128, 1);
+       CALL_BATCH_ALLOC_FREE(32, 128, 2);
+       CALL_BATCH_ALLOC_FREE(64, 128, 3);
+       CALL_BATCH_ALLOC_FREE(96, 128, 4);
+       CALL_BATCH_ALLOC_FREE(128, 128, 5);
+       CALL_BATCH_ALLOC_FREE(192, 128, 6);
+       CALL_BATCH_ALLOC_FREE(256, 128, 7);
+       CALL_BATCH_ALLOC_FREE(512, 64, 8);
+       CALL_BATCH_ALLOC_FREE(1024, 32, 9);
+       CALL_BATCH_ALLOC_FREE(2048, 16, 10);
+       CALL_BATCH_ALLOC_FREE(4096, 8, 11);
+
+       return 0;
+}
index 31f1c93..98107e0 100644 (file)
@@ -1880,7 +1880,7 @@ int main(int argc, char **argv)
                }
        }
 
-       get_unpriv_disabled();
+       unpriv_disabled = get_unpriv_disabled();
        if (unpriv && unpriv_disabled) {
                printf("Cannot run as unprivileged user with sysctl %s.\n",
                       UNPRIV_SYSCTL);
index 20839f8..71ec34b 100644 (file)
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-or-later
 
-CFLAGS += -Wall -O2 -g -fsanitize=address -fsanitize=undefined $(KHDR_INCLUDES)
+CFLAGS += -Wall -O2 -g -fsanitize=address -fsanitize=undefined -static-libasan $(KHDR_INCLUDES)
 TEST_GEN_PROGS := fchmodat2_test
 
 include ../lib.mk
index 4fd0421..25bc61d 100644 (file)
@@ -68,6 +68,12 @@ struct xstate {
 #define XFEATURE_MASK_OPMASK           BIT_ULL(5)
 #define XFEATURE_MASK_ZMM_Hi256                BIT_ULL(6)
 #define XFEATURE_MASK_Hi16_ZMM         BIT_ULL(7)
+#define XFEATURE_MASK_PT               BIT_ULL(8)
+#define XFEATURE_MASK_PKRU             BIT_ULL(9)
+#define XFEATURE_MASK_PASID            BIT_ULL(10)
+#define XFEATURE_MASK_CET_USER         BIT_ULL(11)
+#define XFEATURE_MASK_CET_KERNEL       BIT_ULL(12)
+#define XFEATURE_MASK_LBR              BIT_ULL(15)
 #define XFEATURE_MASK_XTILE_CFG                BIT_ULL(17)
 #define XFEATURE_MASK_XTILE_DATA       BIT_ULL(18)
 
@@ -147,6 +153,7 @@ struct kvm_x86_cpu_feature {
 #define        X86_FEATURE_CLWB                KVM_X86_CPU_FEATURE(0x7, 0, EBX, 24)
 #define        X86_FEATURE_UMIP                KVM_X86_CPU_FEATURE(0x7, 0, ECX, 2)
 #define        X86_FEATURE_PKU                 KVM_X86_CPU_FEATURE(0x7, 0, ECX, 3)
+#define        X86_FEATURE_OSPKE               KVM_X86_CPU_FEATURE(0x7, 0, ECX, 4)
 #define        X86_FEATURE_LA57                KVM_X86_CPU_FEATURE(0x7, 0, ECX, 16)
 #define        X86_FEATURE_RDPID               KVM_X86_CPU_FEATURE(0x7, 0, ECX, 22)
 #define        X86_FEATURE_SGX_LC              KVM_X86_CPU_FEATURE(0x7, 0, ECX, 30)
@@ -553,6 +560,13 @@ static inline void xsetbv(u32 index, u64 value)
        __asm__ __volatile__("xsetbv" :: "a" (eax), "d" (edx), "c" (index));
 }
 
+static inline void wrpkru(u32 pkru)
+{
+       /* Note, ECX and EDX are architecturally required to be '0'. */
+       asm volatile(".byte 0x0f,0x01,0xef\n\t"
+                    : : "a" (pkru), "c"(0), "d"(0));
+}
+
 static inline struct desc_ptr get_gdt(void)
 {
        struct desc_ptr gdt;
@@ -908,6 +922,15 @@ static inline bool kvm_pmu_has(struct kvm_x86_pmu_feature feature)
               !kvm_cpu_has(feature.anti_feature);
 }
 
+static __always_inline uint64_t kvm_cpu_supported_xcr0(void)
+{
+       if (!kvm_cpu_has_p(X86_PROPERTY_SUPPORTED_XCR0_LO))
+               return 0;
+
+       return kvm_cpu_property(X86_PROPERTY_SUPPORTED_XCR0_LO) |
+              ((uint64_t)kvm_cpu_property(X86_PROPERTY_SUPPORTED_XCR0_HI) << 32);
+}
+
 static inline size_t kvm_cpuid2_size(int nr_entries)
 {
        return sizeof(struct kvm_cpuid2) +
index 4c4925a..88b58aa 100644 (file)
@@ -139,6 +139,83 @@ static void vmx_l1_guest_code(struct vmx_pages *vmx_pages)
 static void __attribute__((__flatten__)) guest_code(void *arg)
 {
        GUEST_SYNC(1);
+
+       if (this_cpu_has(X86_FEATURE_XSAVE)) {
+               uint64_t supported_xcr0 = this_cpu_supported_xcr0();
+               uint8_t buffer[4096];
+
+               memset(buffer, 0xcc, sizeof(buffer));
+
+               set_cr4(get_cr4() | X86_CR4_OSXSAVE);
+               GUEST_ASSERT(this_cpu_has(X86_FEATURE_OSXSAVE));
+
+               xsetbv(0, xgetbv(0) | supported_xcr0);
+
+               /*
+                * Modify state for all supported xfeatures to take them out of
+                * their "init" state, i.e. to make them show up in XSTATE_BV.
+                *
+                * Note off-by-default features, e.g. AMX, are out of scope for
+                * this particular testcase as they have a different ABI.
+                */
+               GUEST_ASSERT(supported_xcr0 & XFEATURE_MASK_FP);
+               asm volatile ("fincstp");
+
+               GUEST_ASSERT(supported_xcr0 & XFEATURE_MASK_SSE);
+               asm volatile ("vmovdqu %0, %%xmm0" :: "m" (buffer));
+
+               if (supported_xcr0 & XFEATURE_MASK_YMM)
+                       asm volatile ("vmovdqu %0, %%ymm0" :: "m" (buffer));
+
+               if (supported_xcr0 & XFEATURE_MASK_AVX512) {
+                       asm volatile ("kmovq %0, %%k1" :: "r" (-1ull));
+                       asm volatile ("vmovupd %0, %%zmm0" :: "m" (buffer));
+                       asm volatile ("vmovupd %0, %%zmm16" :: "m" (buffer));
+               }
+
+               if (this_cpu_has(X86_FEATURE_MPX)) {
+                       uint64_t bounds[2] = { 10, 0xffffffffull };
+                       uint64_t output[2] = { };
+
+                       GUEST_ASSERT(supported_xcr0 & XFEATURE_MASK_BNDREGS);
+                       GUEST_ASSERT(supported_xcr0 & XFEATURE_MASK_BNDCSR);
+
+                       /*
+                        * Don't bother trying to get BNDCSR into the INUSE
+                        * state.  MSR_IA32_BNDCFGS doesn't count as it isn't
+                        * managed via XSAVE/XRSTOR, and BNDCFGU can only be
+                        * modified by XRSTOR.  Stuffing XSTATE_BV in the host
+                        * is simpler than doing XRSTOR here in the guest.
+                        *
+                        * However, temporarily enable MPX in BNDCFGS so that
+                        * BNDMOV actually loads BND1.  If MPX isn't *fully*
+                        * enabled, all MPX instructions are treated as NOPs.
+                        *
+                        * Hand encode "bndmov (%rax),%bnd1" as support for MPX
+                        * mnemonics/registers has been removed from gcc and
+                        * clang (and was never fully supported by clang).
+                        */
+                       wrmsr(MSR_IA32_BNDCFGS, BIT_ULL(0));
+                       asm volatile (".byte 0x66,0x0f,0x1a,0x08" :: "a" (bounds));
+                       /*
+                        * Hand encode "bndmov %bnd1, (%rax)" to sanity check
+                        * that BND1 actually got loaded.
+                        */
+                       asm volatile (".byte 0x66,0x0f,0x1b,0x08" :: "a" (output));
+                       wrmsr(MSR_IA32_BNDCFGS, 0);
+
+                       GUEST_ASSERT_EQ(bounds[0], output[0]);
+                       GUEST_ASSERT_EQ(bounds[1], output[1]);
+               }
+               if (this_cpu_has(X86_FEATURE_PKU)) {
+                       GUEST_ASSERT(supported_xcr0 & XFEATURE_MASK_PKRU);
+                       set_cr4(get_cr4() | X86_CR4_PKE);
+                       GUEST_ASSERT(this_cpu_has(X86_FEATURE_OSPKE));
+
+                       wrpkru(-1u);
+               }
+       }
+
        GUEST_SYNC(2);
 
        if (arg) {
@@ -153,10 +230,11 @@ static void __attribute__((__flatten__)) guest_code(void *arg)
 
 int main(int argc, char *argv[])
 {
+       uint64_t *xstate_bv, saved_xstate_bv;
        vm_vaddr_t nested_gva = 0;
-
+       struct kvm_cpuid2 empty_cpuid = {};
        struct kvm_regs regs1, regs2;
-       struct kvm_vcpu *vcpu;
+       struct kvm_vcpu *vcpu, *vcpuN;
        struct kvm_vm *vm;
        struct kvm_x86_state *state;
        struct ucall uc;
@@ -209,6 +287,34 @@ int main(int argc, char *argv[])
                /* Restore state in a new VM.  */
                vcpu = vm_recreate_with_one_vcpu(vm);
                vcpu_load_state(vcpu, state);
+
+               /*
+                * Restore XSAVE state in a dummy vCPU, first without doing
+                * KVM_SET_CPUID2, and then with an empty guest CPUID.  Except
+                * for off-by-default xfeatures, e.g. AMX, KVM is supposed to
+                * allow KVM_SET_XSAVE regardless of guest CPUID.  Manually
+                * load only XSAVE state, MSRs in particular have a much more
+                * convoluted ABI.
+                *
+                * Load two versions of XSAVE state: one with the actual guest
+                * XSAVE state, and one with all supported features forced "on"
+                * in xstate_bv, e.g. to ensure that KVM allows loading all
+                * supported features, even if something goes awry in saving
+                * the original snapshot.
+                */
+               xstate_bv = (void *)&((uint8_t *)state->xsave->region)[512];
+               saved_xstate_bv = *xstate_bv;
+
+               vcpuN = __vm_vcpu_add(vm, vcpu->id + 1);
+               vcpu_xsave_set(vcpuN, state->xsave);
+               *xstate_bv = kvm_cpu_supported_xcr0();
+               vcpu_xsave_set(vcpuN, state->xsave);
+
+               vcpu_init_cpuid(vcpuN, &empty_cpuid);
+               vcpu_xsave_set(vcpuN, state->xsave);
+               *xstate_bv = saved_xstate_bv;
+               vcpu_xsave_set(vcpuN, state->xsave);
+
                kvm_x86_state_cleanup(state);
 
                memset(&regs2, 0, sizeof(regs2));
index a5cb4b0..0899019 100755 (executable)
@@ -25,7 +25,7 @@ if [[ "$1" == "-cgroup-v2" ]]; then
 fi
 
 if [[ $cgroup2 ]]; then
-  cgroup_path=$(mount -t cgroup2 | head -1 | awk -e '{print $3}')
+  cgroup_path=$(mount -t cgroup2 | head -1 | awk '{print $3}')
   if [[ -z "$cgroup_path" ]]; then
     cgroup_path=/dev/cgroup/memory
     mount -t cgroup2 none $cgroup_path
@@ -33,7 +33,7 @@ if [[ $cgroup2 ]]; then
   fi
   echo "+hugetlb" >$cgroup_path/cgroup.subtree_control
 else
-  cgroup_path=$(mount -t cgroup | grep ",hugetlb" | awk -e '{print $3}')
+  cgroup_path=$(mount -t cgroup | grep ",hugetlb" | awk '{print $3}')
   if [[ -z "$cgroup_path" ]]; then
     cgroup_path=/dev/cgroup/memory
     mount -t cgroup memory,hugetlb $cgroup_path
index bf2d2a6..14d2607 100755 (executable)
@@ -20,7 +20,7 @@ fi
 
 
 if [[ $cgroup2 ]]; then
-  CGROUP_ROOT=$(mount -t cgroup2 | head -1 | awk -e '{print $3}')
+  CGROUP_ROOT=$(mount -t cgroup2 | head -1 | awk '{print $3}')
   if [[ -z "$CGROUP_ROOT" ]]; then
     CGROUP_ROOT=/dev/cgroup/memory
     mount -t cgroup2 none $CGROUP_ROOT
@@ -28,7 +28,7 @@ if [[ $cgroup2 ]]; then
   fi
   echo "+hugetlb +memory" >$CGROUP_ROOT/cgroup.subtree_control
 else
-  CGROUP_ROOT=$(mount -t cgroup | grep ",hugetlb" | awk -e '{print $3}')
+  CGROUP_ROOT=$(mount -t cgroup | grep ",hugetlb" | awk '{print $3}')
   if [[ -z "$CGROUP_ROOT" ]]; then
     CGROUP_ROOT=/dev/cgroup/memory
     mount -t cgroup memory,hugetlb $CGROUP_ROOT
index df91435..1c6457e 100755 (executable)
@@ -41,61 +41,6 @@ cleanup()
        done
 }
 
-ip -Version > /dev/null 2>&1
-if [ $? -ne 0 ];then
-       echo "SKIP: Could not run test without ip tool"
-       exit $ksft_skip
-fi
-
-trap cleanup EXIT
-
-for i in "$ns1" "$ns2" "$ns3" ;do
-       ip netns add $i || exit $ksft_skip
-       ip -net $i link set lo up
-done
-
-echo "INFO: preparing interfaces."
-# Three HSR nodes. Each node has one link to each of its neighbour, two links in total.
-#
-#    ns1eth1 ----- ns2eth1
-#      hsr1         hsr2
-#    ns1eth2       ns2eth2
-#       |            |
-#    ns3eth1      ns3eth2
-#           \    /
-#            hsr3
-#
-# Interfaces
-ip link add ns1eth1 netns "$ns1" type veth peer name ns2eth1 netns "$ns2"
-ip link add ns1eth2 netns "$ns1" type veth peer name ns3eth1 netns "$ns3"
-ip link add ns3eth2 netns "$ns3" type veth peer name ns2eth2 netns "$ns2"
-
-# HSRv0.
-ip -net "$ns1" link add name hsr1 type hsr slave1 ns1eth1 slave2 ns1eth2 supervision 45 version 0 proto 0
-ip -net "$ns2" link add name hsr2 type hsr slave1 ns2eth1 slave2 ns2eth2 supervision 45 version 0 proto 0
-ip -net "$ns3" link add name hsr3 type hsr slave1 ns3eth1 slave2 ns3eth2 supervision 45 version 0 proto 0
-
-# IP for HSR
-ip -net "$ns1" addr add 100.64.0.1/24 dev hsr1
-ip -net "$ns1" addr add dead:beef:1::1/64 dev hsr1 nodad
-ip -net "$ns2" addr add 100.64.0.2/24 dev hsr2
-ip -net "$ns2" addr add dead:beef:1::2/64 dev hsr2 nodad
-ip -net "$ns3" addr add 100.64.0.3/24 dev hsr3
-ip -net "$ns3" addr add dead:beef:1::3/64 dev hsr3 nodad
-
-# All Links up
-ip -net "$ns1" link set ns1eth1 up
-ip -net "$ns1" link set ns1eth2 up
-ip -net "$ns1" link set hsr1 up
-
-ip -net "$ns2" link set ns2eth1 up
-ip -net "$ns2" link set ns2eth2 up
-ip -net "$ns2" link set hsr2 up
-
-ip -net "$ns3" link set ns3eth1 up
-ip -net "$ns3" link set ns3eth2 up
-ip -net "$ns3" link set hsr3 up
-
 # $1: IP address
 is_v6()
 {
@@ -164,93 +109,168 @@ stop_if_error()
        fi
 }
 
-
-echo "INFO: Initial validation ping."
-# Each node has to be able each one.
-do_ping "$ns1" 100.64.0.2
-do_ping "$ns2" 100.64.0.1
-do_ping "$ns3" 100.64.0.1
-stop_if_error "Initial validation failed."
-
-do_ping "$ns1" 100.64.0.3
-do_ping "$ns2" 100.64.0.3
-do_ping "$ns3" 100.64.0.2
-
-do_ping "$ns1" dead:beef:1::2
-do_ping "$ns1" dead:beef:1::3
-do_ping "$ns2" dead:beef:1::1
-do_ping "$ns2" dead:beef:1::2
-do_ping "$ns3" dead:beef:1::1
-do_ping "$ns3" dead:beef:1::2
-
-stop_if_error "Initial validation failed."
+do_complete_ping_test()
+{
+       echo "INFO: Initial validation ping."
+       # Each node has to be able each one.
+       do_ping "$ns1" 100.64.0.2
+       do_ping "$ns2" 100.64.0.1
+       do_ping "$ns3" 100.64.0.1
+       stop_if_error "Initial validation failed."
+
+       do_ping "$ns1" 100.64.0.3
+       do_ping "$ns2" 100.64.0.3
+       do_ping "$ns3" 100.64.0.2
+
+       do_ping "$ns1" dead:beef:1::2
+       do_ping "$ns1" dead:beef:1::3
+       do_ping "$ns2" dead:beef:1::1
+       do_ping "$ns2" dead:beef:1::2
+       do_ping "$ns3" dead:beef:1::1
+       do_ping "$ns3" dead:beef:1::2
+
+       stop_if_error "Initial validation failed."
 
 # Wait until supervisor all supervision frames have been processed and the node
 # entries have been merged. Otherwise duplicate frames will be observed which is
 # valid at this stage.
-WAIT=5
-while [ ${WAIT} -gt 0 ]
-do
-       grep 00:00:00:00:00:00 /sys/kernel/debug/hsr/hsr*/node_table
-       if [ $? -ne 0 ]
-       then
-               break
-       fi
-       sleep 1
-       let WAIT = WAIT - 1
-done
+       WAIT=5
+       while [ ${WAIT} -gt 0 ]
+       do
+               grep 00:00:00:00:00:00 /sys/kernel/debug/hsr/hsr*/node_table
+               if [ $? -ne 0 ]
+               then
+                       break
+               fi
+               sleep 1
+               let "WAIT = WAIT - 1"
+       done
 
 # Just a safety delay in case the above check didn't handle it.
-sleep 1
+       sleep 1
+
+       echo "INFO: Longer ping test."
+       do_ping_long "$ns1" 100.64.0.2
+       do_ping_long "$ns1" dead:beef:1::2
+       do_ping_long "$ns1" 100.64.0.3
+       do_ping_long "$ns1" dead:beef:1::3
 
-echo "INFO: Longer ping test."
-do_ping_long "$ns1" 100.64.0.2
-do_ping_long "$ns1" dead:beef:1::2
-do_ping_long "$ns1" 100.64.0.3
-do_ping_long "$ns1" dead:beef:1::3
+       stop_if_error "Longer ping test failed."
 
-stop_if_error "Longer ping test failed."
+       do_ping_long "$ns2" 100.64.0.1
+       do_ping_long "$ns2" dead:beef:1::1
+       do_ping_long "$ns2" 100.64.0.3
+       do_ping_long "$ns2" dead:beef:1::2
+       stop_if_error "Longer ping test failed."
 
-do_ping_long "$ns2" 100.64.0.1
-do_ping_long "$ns2" dead:beef:1::1
-do_ping_long "$ns2" 100.64.0.3
-do_ping_long "$ns2" dead:beef:1::2
-stop_if_error "Longer ping test failed."
+       do_ping_long "$ns3" 100.64.0.1
+       do_ping_long "$ns3" dead:beef:1::1
+       do_ping_long "$ns3" 100.64.0.2
+       do_ping_long "$ns3" dead:beef:1::2
+       stop_if_error "Longer ping test failed."
 
-do_ping_long "$ns3" 100.64.0.1
-do_ping_long "$ns3" dead:beef:1::1
-do_ping_long "$ns3" 100.64.0.2
-do_ping_long "$ns3" dead:beef:1::2
-stop_if_error "Longer ping test failed."
+       echo "INFO: Cutting one link."
+       do_ping_long "$ns1" 100.64.0.3 &
 
-echo "INFO: Cutting one link."
-do_ping_long "$ns1" 100.64.0.3 &
+       sleep 3
+       ip -net "$ns3" link set ns3eth1 down
+       wait
 
-sleep 3
-ip -net "$ns3" link set ns3eth1 down
-wait
+       ip -net "$ns3" link set ns3eth1 up
 
-ip -net "$ns3" link set ns3eth1 up
+       stop_if_error "Failed with one link down."
 
-stop_if_error "Failed with one link down."
+       echo "INFO: Delay the link and drop a few packages."
+       tc -net "$ns3" qdisc add dev ns3eth1 root netem delay 50ms
+       tc -net "$ns2" qdisc add dev ns2eth1 root netem delay 5ms loss 25%
 
-echo "INFO: Delay the link and drop a few packages."
-tc -net "$ns3" qdisc add dev ns3eth1 root netem delay 50ms
-tc -net "$ns2" qdisc add dev ns2eth1 root netem delay 5ms loss 25%
+       do_ping_long "$ns1" 100.64.0.2
+       do_ping_long "$ns1" 100.64.0.3
 
-do_ping_long "$ns1" 100.64.0.2
-do_ping_long "$ns1" 100.64.0.3
+       stop_if_error "Failed with delay and packetloss."
 
-stop_if_error "Failed with delay and packetloss."
+       do_ping_long "$ns2" 100.64.0.1
+       do_ping_long "$ns2" 100.64.0.3
 
-do_ping_long "$ns2" 100.64.0.1
-do_ping_long "$ns2" 100.64.0.3
+       stop_if_error "Failed with delay and packetloss."
 
-stop_if_error "Failed with delay and packetloss."
+       do_ping_long "$ns3" 100.64.0.1
+       do_ping_long "$ns3" 100.64.0.2
+       stop_if_error "Failed with delay and packetloss."
+
+       echo "INFO: All good."
+}
+
+setup_hsr_interfaces()
+{
+       local HSRv="$1"
+
+       echo "INFO: preparing interfaces for HSRv${HSRv}."
+# Three HSR nodes. Each node has one link to each of its neighbour, two links in total.
+#
+#    ns1eth1 ----- ns2eth1
+#      hsr1         hsr2
+#    ns1eth2       ns2eth2
+#       |            |
+#    ns3eth1      ns3eth2
+#           \    /
+#            hsr3
+#
+       # Interfaces
+       ip link add ns1eth1 netns "$ns1" type veth peer name ns2eth1 netns "$ns2"
+       ip link add ns1eth2 netns "$ns1" type veth peer name ns3eth1 netns "$ns3"
+       ip link add ns3eth2 netns "$ns3" type veth peer name ns2eth2 netns "$ns2"
+
+       # HSRv0/1
+       ip -net "$ns1" link add name hsr1 type hsr slave1 ns1eth1 slave2 ns1eth2 supervision 45 version $HSRv proto 0
+       ip -net "$ns2" link add name hsr2 type hsr slave1 ns2eth1 slave2 ns2eth2 supervision 45 version $HSRv proto 0
+       ip -net "$ns3" link add name hsr3 type hsr slave1 ns3eth1 slave2 ns3eth2 supervision 45 version $HSRv proto 0
+
+       # IP for HSR
+       ip -net "$ns1" addr add 100.64.0.1/24 dev hsr1
+       ip -net "$ns1" addr add dead:beef:1::1/64 dev hsr1 nodad
+       ip -net "$ns2" addr add 100.64.0.2/24 dev hsr2
+       ip -net "$ns2" addr add dead:beef:1::2/64 dev hsr2 nodad
+       ip -net "$ns3" addr add 100.64.0.3/24 dev hsr3
+       ip -net "$ns3" addr add dead:beef:1::3/64 dev hsr3 nodad
+
+       # All Links up
+       ip -net "$ns1" link set ns1eth1 up
+       ip -net "$ns1" link set ns1eth2 up
+       ip -net "$ns1" link set hsr1 up
+
+       ip -net "$ns2" link set ns2eth1 up
+       ip -net "$ns2" link set ns2eth2 up
+       ip -net "$ns2" link set hsr2 up
+
+       ip -net "$ns3" link set ns3eth1 up
+       ip -net "$ns3" link set ns3eth2 up
+       ip -net "$ns3" link set hsr3 up
+}
+
+ip -Version > /dev/null 2>&1
+if [ $? -ne 0 ];then
+       echo "SKIP: Could not run test without ip tool"
+       exit $ksft_skip
+fi
+
+trap cleanup EXIT
+
+for i in "$ns1" "$ns2" "$ns3" ;do
+       ip netns add $i || exit $ksft_skip
+       ip -net $i link set lo up
+done
+
+setup_hsr_interfaces 0
+do_complete_ping_test
+cleanup
+
+for i in "$ns1" "$ns2" "$ns3" ;do
+       ip netns add $i || exit $ksft_skip
+       ip -net $i link set lo up
+done
 
-do_ping_long "$ns3" 100.64.0.1
-do_ping_long "$ns3" 100.64.0.2
-stop_if_error "Failed with delay and packetloss."
+setup_hsr_interfaces 1
+do_complete_ping_test
 
-echo "INFO: All good."
 exit $ret
index 297d972..464853a 100644 (file)
@@ -613,11 +613,11 @@ TEST_F(tls, sendmsg_large)
 
                msg.msg_iov = &vec;
                msg.msg_iovlen = 1;
-               EXPECT_EQ(sendmsg(self->cfd, &msg, 0), send_len);
+               EXPECT_EQ(sendmsg(self->fd, &msg, 0), send_len);
        }
 
        while (recvs++ < sends) {
-               EXPECT_NE(recv(self->fd, mem, send_len, 0), -1);
+               EXPECT_NE(recv(self->cfd, mem, send_len, 0), -1);
        }
 
        free(mem);
@@ -646,9 +646,9 @@ TEST_F(tls, sendmsg_multiple)
        msg.msg_iov = vec;
        msg.msg_iovlen = iov_len;
 
-       EXPECT_EQ(sendmsg(self->cfd, &msg, 0), total_len);
+       EXPECT_EQ(sendmsg(self->fd, &msg, 0), total_len);
        buf = malloc(total_len);
-       EXPECT_NE(recv(self->fd, buf, total_len, 0), -1);
+       EXPECT_NE(recv(self->cfd, buf, total_len, 0), -1);
        for (i = 0; i < iov_len; i++) {
                EXPECT_EQ(memcmp(test_strs[i], buf + len_cmp,
                                 strlen(test_strs[i])),
index 4cb887b..4b2928e 100644 (file)
@@ -1,3 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0-only
 nf-queue
 connect_close
+audit_logread
index 3686bfa..ef90aca 100644 (file)
@@ -6,13 +6,14 @@ TEST_PROGS := nft_trans_stress.sh nft_fib.sh nft_nat.sh bridge_brouter.sh \
        nft_concat_range.sh nft_conntrack_helper.sh \
        nft_queue.sh nft_meta.sh nf_nat_edemux.sh \
        ipip-conntrack-mtu.sh conntrack_tcp_unreplied.sh \
-       conntrack_vrf.sh nft_synproxy.sh rpath.sh
+       conntrack_vrf.sh nft_synproxy.sh rpath.sh nft_audit.sh \
+       conntrack_sctp_collision.sh
 
 HOSTPKG_CONFIG := pkg-config
 
 CFLAGS += $(shell $(HOSTPKG_CONFIG) --cflags libmnl 2>/dev/null)
 LDLIBS += $(shell $(HOSTPKG_CONFIG) --libs libmnl 2>/dev/null || echo -lmnl)
 
-TEST_GEN_FILES =  nf-queue connect_close
+TEST_GEN_FILES =  nf-queue connect_close audit_logread sctp_collision
 
 include ../lib.mk
diff --git a/tools/testing/selftests/netfilter/audit_logread.c b/tools/testing/selftests/netfilter/audit_logread.c
new file mode 100644 (file)
index 0000000..a0a880f
--- /dev/null
@@ -0,0 +1,165 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#define _GNU_SOURCE
+#include <errno.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <linux/audit.h>
+#include <linux/netlink.h>
+
+static int fd;
+
+#define MAX_AUDIT_MESSAGE_LENGTH       8970
+struct audit_message {
+       struct nlmsghdr nlh;
+       union {
+               struct audit_status s;
+               char data[MAX_AUDIT_MESSAGE_LENGTH];
+       } u;
+};
+
+int audit_recv(int fd, struct audit_message *rep)
+{
+       struct sockaddr_nl addr;
+       socklen_t addrlen = sizeof(addr);
+       int ret;
+
+       do {
+               ret = recvfrom(fd, rep, sizeof(*rep), 0,
+                              (struct sockaddr *)&addr, &addrlen);
+       } while (ret < 0 && errno == EINTR);
+
+       if (ret < 0 ||
+           addrlen != sizeof(addr) ||
+           addr.nl_pid != 0 ||
+           rep->nlh.nlmsg_type == NLMSG_ERROR) /* short-cut for now */
+               return -1;
+
+       return ret;
+}
+
+int audit_send(int fd, uint16_t type, uint32_t key, uint32_t val)
+{
+       static int seq = 0;
+       struct audit_message msg = {
+               .nlh = {
+                       .nlmsg_len   = NLMSG_SPACE(sizeof(msg.u.s)),
+                       .nlmsg_type  = type,
+                       .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
+                       .nlmsg_seq   = ++seq,
+               },
+               .u.s = {
+                       .mask    = key,
+                       .enabled = key == AUDIT_STATUS_ENABLED ? val : 0,
+                       .pid     = key == AUDIT_STATUS_PID ? val : 0,
+               }
+       };
+       struct sockaddr_nl addr = {
+               .nl_family = AF_NETLINK,
+       };
+       int ret;
+
+       do {
+               ret = sendto(fd, &msg, msg.nlh.nlmsg_len, 0,
+                            (struct sockaddr *)&addr, sizeof(addr));
+       } while (ret < 0 && errno == EINTR);
+
+       if (ret != (int)msg.nlh.nlmsg_len)
+               return -1;
+       return 0;
+}
+
+int audit_set(int fd, uint32_t key, uint32_t val)
+{
+       struct audit_message rep = { 0 };
+       int ret;
+
+       ret = audit_send(fd, AUDIT_SET, key, val);
+       if (ret)
+               return ret;
+
+       ret = audit_recv(fd, &rep);
+       if (ret < 0)
+               return ret;
+       return 0;
+}
+
+int readlog(int fd)
+{
+       struct audit_message rep = { 0 };
+       int ret = audit_recv(fd, &rep);
+       const char *sep = "";
+       char *k, *v;
+
+       if (ret < 0)
+               return ret;
+
+       if (rep.nlh.nlmsg_type != AUDIT_NETFILTER_CFG)
+               return 0;
+
+       /* skip the initial "audit(...): " part */
+       strtok(rep.u.data, " ");
+
+       while ((k = strtok(NULL, "="))) {
+               v = strtok(NULL, " ");
+
+               /* these vary and/or are uninteresting, ignore */
+               if (!strcmp(k, "pid") ||
+                   !strcmp(k, "comm") ||
+                   !strcmp(k, "subj"))
+                       continue;
+
+               /* strip the varying sequence number */
+               if (!strcmp(k, "table"))
+                       *strchrnul(v, ':') = '\0';
+
+               printf("%s%s=%s", sep, k, v);
+               sep = " ";
+       }
+       if (*sep) {
+               printf("\n");
+               fflush(stdout);
+       }
+       return 0;
+}
+
+void cleanup(int sig)
+{
+       audit_set(fd, AUDIT_STATUS_ENABLED, 0);
+       close(fd);
+       if (sig)
+               exit(0);
+}
+
+int main(int argc, char **argv)
+{
+       struct sigaction act = {
+               .sa_handler = cleanup,
+       };
+
+       fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_AUDIT);
+       if (fd < 0) {
+               perror("Can't open netlink socket");
+               return -1;
+       }
+
+       if (sigaction(SIGTERM, &act, NULL) < 0 ||
+           sigaction(SIGINT, &act, NULL) < 0) {
+               perror("Can't set signal handler");
+               close(fd);
+               return -1;
+       }
+
+       audit_set(fd, AUDIT_STATUS_ENABLED, 1);
+       audit_set(fd, AUDIT_STATUS_PID, getpid());
+
+       while (1)
+               readlog(fd);
+}
index 4faf2ce..7c42b1b 100644 (file)
@@ -6,3 +6,4 @@ CONFIG_NFT_REDIR=m
 CONFIG_NFT_MASQ=m
 CONFIG_NFT_FLOW_OFFLOAD=m
 CONFIG_NF_CT_NETLINK=m
+CONFIG_AUDIT=y
diff --git a/tools/testing/selftests/netfilter/conntrack_sctp_collision.sh b/tools/testing/selftests/netfilter/conntrack_sctp_collision.sh
new file mode 100755 (executable)
index 0000000..a924e59
--- /dev/null
@@ -0,0 +1,89 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# Testing For SCTP COLLISION SCENARIO as Below:
+#
+#   14:35:47.655279 IP CLIENT_IP.PORT > SERVER_IP.PORT: sctp (1) [INIT] [init tag: 2017837359]
+#   14:35:48.353250 IP SERVER_IP.PORT > CLIENT_IP.PORT: sctp (1) [INIT] [init tag: 1187206187]
+#   14:35:48.353275 IP CLIENT_IP.PORT > SERVER_IP.PORT: sctp (1) [INIT ACK] [init tag: 2017837359]
+#   14:35:48.353283 IP SERVER_IP.PORT > CLIENT_IP.PORT: sctp (1) [COOKIE ECHO]
+#   14:35:48.353977 IP CLIENT_IP.PORT > SERVER_IP.PORT: sctp (1) [COOKIE ACK]
+#   14:35:48.855335 IP SERVER_IP.PORT > CLIENT_IP.PORT: sctp (1) [INIT ACK] [init tag: 164579970]
+#
+# TOPO: SERVER_NS (link0)<--->(link1) ROUTER_NS (link2)<--->(link3) CLIENT_NS
+
+CLIENT_NS=$(mktemp -u client-XXXXXXXX)
+CLIENT_IP="198.51.200.1"
+CLIENT_PORT=1234
+
+SERVER_NS=$(mktemp -u server-XXXXXXXX)
+SERVER_IP="198.51.100.1"
+SERVER_PORT=1234
+
+ROUTER_NS=$(mktemp -u router-XXXXXXXX)
+CLIENT_GW="198.51.200.2"
+SERVER_GW="198.51.100.2"
+
+# setup the topo
+setup() {
+       ip net add $CLIENT_NS
+       ip net add $SERVER_NS
+       ip net add $ROUTER_NS
+       ip -n $SERVER_NS link add link0 type veth peer name link1 netns $ROUTER_NS
+       ip -n $CLIENT_NS link add link3 type veth peer name link2 netns $ROUTER_NS
+
+       ip -n $SERVER_NS link set link0 up
+       ip -n $SERVER_NS addr add $SERVER_IP/24 dev link0
+       ip -n $SERVER_NS route add $CLIENT_IP dev link0 via $SERVER_GW
+
+       ip -n $ROUTER_NS link set link1 up
+       ip -n $ROUTER_NS link set link2 up
+       ip -n $ROUTER_NS addr add $SERVER_GW/24 dev link1
+       ip -n $ROUTER_NS addr add $CLIENT_GW/24 dev link2
+       ip net exec $ROUTER_NS sysctl -wq net.ipv4.ip_forward=1
+
+       ip -n $CLIENT_NS link set link3 up
+       ip -n $CLIENT_NS addr add $CLIENT_IP/24 dev link3
+       ip -n $CLIENT_NS route add $SERVER_IP dev link3 via $CLIENT_GW
+
+       # simulate the delay on OVS upcall by setting up a delay for INIT_ACK with
+       # tc on $SERVER_NS side
+       tc -n $SERVER_NS qdisc add dev link0 root handle 1: htb
+       tc -n $SERVER_NS class add dev link0 parent 1: classid 1:1 htb rate 100mbit
+       tc -n $SERVER_NS filter add dev link0 parent 1: protocol ip u32 match ip protocol 132 \
+               0xff match u8 2 0xff at 32 flowid 1:1
+       tc -n $SERVER_NS qdisc add dev link0 parent 1:1 handle 10: netem delay 1200ms
+
+       # simulate the ctstate check on OVS nf_conntrack
+       ip net exec $ROUTER_NS iptables -A FORWARD -m state --state INVALID,UNTRACKED -j DROP
+       ip net exec $ROUTER_NS iptables -A INPUT -p sctp -j DROP
+
+       # use a smaller number for assoc's max_retrans to reproduce the issue
+       modprobe sctp
+       ip net exec $CLIENT_NS sysctl -wq net.sctp.association_max_retrans=3
+}
+
+cleanup() {
+       ip net exec $CLIENT_NS pkill sctp_collision 2>&1 >/dev/null
+       ip net exec $SERVER_NS pkill sctp_collision 2>&1 >/dev/null
+       ip net del "$CLIENT_NS"
+       ip net del "$SERVER_NS"
+       ip net del "$ROUTER_NS"
+}
+
+do_test() {
+       ip net exec $SERVER_NS ./sctp_collision server \
+               $SERVER_IP $SERVER_PORT $CLIENT_IP $CLIENT_PORT &
+       ip net exec $CLIENT_NS ./sctp_collision client \
+               $CLIENT_IP $CLIENT_PORT $SERVER_IP $SERVER_PORT
+}
+
+# NOTE: one way to work around the issue is set a smaller hb_interval
+# ip net exec $CLIENT_NS sysctl -wq net.sctp.hb_interval=3500
+
+# run the test case
+trap cleanup EXIT
+setup && \
+echo "Test for SCTP Collision in nf_conntrack:" && \
+do_test && echo "PASS!"
+exit $?
diff --git a/tools/testing/selftests/netfilter/nft_audit.sh b/tools/testing/selftests/netfilter/nft_audit.sh
new file mode 100755 (executable)
index 0000000..bb34329
--- /dev/null
@@ -0,0 +1,193 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# Check that audit logs generated for nft commands are as expected.
+
+SKIP_RC=4
+RC=0
+
+nft --version >/dev/null 2>&1 || {
+       echo "SKIP: missing nft tool"
+       exit $SKIP_RC
+}
+
+logfile=$(mktemp)
+rulefile=$(mktemp)
+echo "logging into $logfile"
+./audit_logread >"$logfile" &
+logread_pid=$!
+trap 'kill $logread_pid; rm -f $logfile $rulefile' EXIT
+exec 3<"$logfile"
+
+do_test() { # (cmd, log)
+       echo -n "testing for cmd: $1 ... "
+       cat <&3 >/dev/null
+       $1 >/dev/null || exit 1
+       sleep 0.1
+       res=$(diff -a -u <(echo "$2") - <&3)
+       [ $? -eq 0 ] && { echo "OK"; return; }
+       echo "FAIL"
+       grep -v '^\(---\|+++\|@@\)' <<< "$res"
+       ((RC--))
+}
+
+nft flush ruleset
+
+# adding tables, chains and rules
+
+for table in t1 t2; do
+       do_test "nft add table $table" \
+       "table=$table family=2 entries=1 op=nft_register_table"
+
+       do_test "nft add chain $table c1" \
+       "table=$table family=2 entries=1 op=nft_register_chain"
+
+       do_test "nft add chain $table c2; add chain $table c3" \
+       "table=$table family=2 entries=2 op=nft_register_chain"
+
+       cmd="add rule $table c1 counter"
+
+       do_test "nft $cmd" \
+       "table=$table family=2 entries=1 op=nft_register_rule"
+
+       do_test "nft $cmd; $cmd" \
+       "table=$table family=2 entries=2 op=nft_register_rule"
+
+       cmd=""
+       sep=""
+       for chain in c2 c3; do
+               for i in {1..3}; do
+                       cmd+="$sep add rule $table $chain counter"
+                       sep=";"
+               done
+       done
+       do_test "nft $cmd" \
+       "table=$table family=2 entries=6 op=nft_register_rule"
+done
+
+for ((i = 0; i < 500; i++)); do
+       echo "add rule t2 c3 counter accept comment \"rule $i\""
+done >$rulefile
+do_test "nft -f $rulefile" \
+'table=t2 family=2 entries=500 op=nft_register_rule'
+
+# adding sets and elements
+
+settype='type inet_service; counter'
+setelem='{ 22, 80, 443 }'
+setblock="{ $settype; elements = $setelem; }"
+do_test "nft add set t1 s $setblock" \
+"table=t1 family=2 entries=4 op=nft_register_set"
+
+do_test "nft add set t1 s2 $setblock; add set t1 s3 { $settype; }" \
+"table=t1 family=2 entries=5 op=nft_register_set"
+
+do_test "nft add element t1 s3 $setelem" \
+"table=t1 family=2 entries=3 op=nft_register_setelem"
+
+# adding counters
+
+do_test 'nft add counter t1 c1' \
+'table=t1 family=2 entries=1 op=nft_register_obj'
+
+do_test 'nft add counter t2 c1; add counter t2 c2' \
+'table=t2 family=2 entries=2 op=nft_register_obj'
+
+# adding/updating quotas
+
+do_test 'nft add quota t1 q1 { 10 bytes }' \
+'table=t1 family=2 entries=1 op=nft_register_obj'
+
+do_test 'nft add quota t2 q1 { 10 bytes }; add quota t2 q2 { 10 bytes }' \
+'table=t2 family=2 entries=2 op=nft_register_obj'
+
+# changing the quota value triggers obj update path
+do_test 'nft add quota t1 q1 { 20 bytes }' \
+'table=t1 family=2 entries=1 op=nft_register_obj'
+
+# resetting rules
+
+do_test 'nft reset rules t1 c2' \
+'table=t1 family=2 entries=3 op=nft_reset_rule'
+
+do_test 'nft reset rules table t1' \
+'table=t1 family=2 entries=3 op=nft_reset_rule
+table=t1 family=2 entries=3 op=nft_reset_rule
+table=t1 family=2 entries=3 op=nft_reset_rule'
+
+do_test 'nft reset rules t2 c3' \
+'table=t2 family=2 entries=189 op=nft_reset_rule
+table=t2 family=2 entries=188 op=nft_reset_rule
+table=t2 family=2 entries=126 op=nft_reset_rule'
+
+do_test 'nft reset rules t2' \
+'table=t2 family=2 entries=3 op=nft_reset_rule
+table=t2 family=2 entries=3 op=nft_reset_rule
+table=t2 family=2 entries=186 op=nft_reset_rule
+table=t2 family=2 entries=188 op=nft_reset_rule
+table=t2 family=2 entries=129 op=nft_reset_rule'
+
+do_test 'nft reset rules' \
+'table=t1 family=2 entries=3 op=nft_reset_rule
+table=t1 family=2 entries=3 op=nft_reset_rule
+table=t1 family=2 entries=3 op=nft_reset_rule
+table=t2 family=2 entries=3 op=nft_reset_rule
+table=t2 family=2 entries=3 op=nft_reset_rule
+table=t2 family=2 entries=180 op=nft_reset_rule
+table=t2 family=2 entries=188 op=nft_reset_rule
+table=t2 family=2 entries=135 op=nft_reset_rule'
+
+# resetting sets and elements
+
+elem=(22 ,80 ,443)
+relem=""
+for i in {1..3}; do
+       relem+="${elem[((i - 1))]}"
+       do_test "nft reset element t1 s { $relem }" \
+       "table=t1 family=2 entries=$i op=nft_reset_setelem"
+done
+
+do_test 'nft reset set t1 s' \
+'table=t1 family=2 entries=3 op=nft_reset_setelem'
+
+# deleting rules
+
+readarray -t handles < <(nft -a list chain t1 c1 | \
+                        sed -n 's/.*counter.* handle \(.*\)$/\1/p')
+
+do_test "nft delete rule t1 c1 handle ${handles[0]}" \
+'table=t1 family=2 entries=1 op=nft_unregister_rule'
+
+cmd='delete rule t1 c1 handle'
+do_test "nft $cmd ${handles[1]}; $cmd ${handles[2]}" \
+'table=t1 family=2 entries=2 op=nft_unregister_rule'
+
+do_test 'nft flush chain t1 c2' \
+'table=t1 family=2 entries=3 op=nft_unregister_rule'
+
+do_test 'nft flush table t2' \
+'table=t2 family=2 entries=509 op=nft_unregister_rule'
+
+# deleting chains
+
+do_test 'nft delete chain t2 c2' \
+'table=t2 family=2 entries=1 op=nft_unregister_chain'
+
+# deleting sets and elements
+
+do_test 'nft delete element t1 s { 22 }' \
+'table=t1 family=2 entries=1 op=nft_unregister_setelem'
+
+do_test 'nft delete element t1 s { 80, 443 }' \
+'table=t1 family=2 entries=2 op=nft_unregister_setelem'
+
+do_test 'nft flush set t1 s2' \
+'table=t1 family=2 entries=3 op=nft_unregister_setelem'
+
+do_test 'nft delete set t1 s2' \
+'table=t1 family=2 entries=1 op=nft_unregister_set'
+
+do_test 'nft delete set t1 s3' \
+'table=t1 family=2 entries=1 op=nft_unregister_set'
+
+exit $RC
diff --git a/tools/testing/selftests/netfilter/sctp_collision.c b/tools/testing/selftests/netfilter/sctp_collision.c
new file mode 100644 (file)
index 0000000..21bb1cf
--- /dev/null
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+
+int main(int argc, char *argv[])
+{
+       struct sockaddr_in saddr = {}, daddr = {};
+       int sd, ret, len = sizeof(daddr);
+       struct timeval tv = {25, 0};
+       char buf[] = "hello";
+
+       if (argc != 6 || (strcmp(argv[1], "server") && strcmp(argv[1], "client"))) {
+               printf("%s <server|client> <LOCAL_IP> <LOCAL_PORT> <REMOTE_IP> <REMOTE_PORT>\n",
+                      argv[0]);
+               return -1;
+       }
+
+       sd = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
+       if (sd < 0) {
+               printf("Failed to create sd\n");
+               return -1;
+       }
+
+       saddr.sin_family = AF_INET;
+       saddr.sin_addr.s_addr = inet_addr(argv[2]);
+       saddr.sin_port = htons(atoi(argv[3]));
+
+       ret = bind(sd, (struct sockaddr *)&saddr, sizeof(saddr));
+       if (ret < 0) {
+               printf("Failed to bind to address\n");
+               goto out;
+       }
+
+       ret = listen(sd, 5);
+       if (ret < 0) {
+               printf("Failed to listen on port\n");
+               goto out;
+       }
+
+       daddr.sin_family = AF_INET;
+       daddr.sin_addr.s_addr = inet_addr(argv[4]);
+       daddr.sin_port = htons(atoi(argv[5]));
+
+       /* make test shorter than 25s */
+       ret = setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
+       if (ret < 0) {
+               printf("Failed to setsockopt SO_RCVTIMEO\n");
+               goto out;
+       }
+
+       if (!strcmp(argv[1], "server")) {
+               sleep(1); /* wait a bit for client's INIT */
+               ret = connect(sd, (struct sockaddr *)&daddr, len);
+               if (ret < 0) {
+                       printf("Failed to connect to peer\n");
+                       goto out;
+               }
+               ret = recvfrom(sd, buf, sizeof(buf), 0, (struct sockaddr *)&daddr, &len);
+               if (ret < 0) {
+                       printf("Failed to recv msg %d\n", ret);
+                       goto out;
+               }
+               ret = sendto(sd, buf, strlen(buf) + 1, 0, (struct sockaddr *)&daddr, len);
+               if (ret < 0) {
+                       printf("Failed to send msg %d\n", ret);
+                       goto out;
+               }
+               printf("Server: sent! %d\n", ret);
+       }
+
+       if (!strcmp(argv[1], "client")) {
+               usleep(300000); /* wait a bit for server's listening */
+               ret = connect(sd, (struct sockaddr *)&daddr, len);
+               if (ret < 0) {
+                       printf("Failed to connect to peer\n");
+                       goto out;
+               }
+               sleep(1); /* wait a bit for server's delayed INIT_ACK to reproduce the issue */
+               ret = sendto(sd, buf, strlen(buf) + 1, 0, (struct sockaddr *)&daddr, len);
+               if (ret < 0) {
+                       printf("Failed to send msg %d\n", ret);
+                       goto out;
+               }
+               ret = recvfrom(sd, buf, sizeof(buf), 0, (struct sockaddr *)&daddr, &len);
+               if (ret < 0) {
+                       printf("Failed to recv msg %d\n", ret);
+                       goto out;
+               }
+               printf("Client: rcvd! %d\n", ret);
+       }
+       ret = 0;
+out:
+       close(sd);
+       return ret;
+}
index 843ba56..254d676 100644 (file)
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-or-later
 
-CFLAGS += -Wall -O2 -g -fsanitize=address -fsanitize=undefined
+CFLAGS += -Wall -O2 -g -fsanitize=address -fsanitize=undefined -static-libasan
 TEST_GEN_PROGS := openat2_test resolve_test rename_attack_test
 
 include ../lib.mk
index 49f2ad1..7ea42fa 100644 (file)
@@ -59,12 +59,11 @@ override define INSTALL_RULE
        done;
 endef
 
-override define EMIT_TESTS
+emit_tests:
        +@for TARGET in $(SUB_DIRS); do \
                BUILD_TARGET=$(OUTPUT)/$$TARGET;        \
-               $(MAKE) OUTPUT=$$BUILD_TARGET -s -C $$TARGET emit_tests;\
+               $(MAKE) OUTPUT=$$BUILD_TARGET -s -C $$TARGET $@;\
        done;
-endef
 
 override define CLEAN
        +@for TARGET in $(SUB_DIRS); do \
@@ -77,4 +76,4 @@ endef
 tags:
        find . -name '*.c' -o -name '*.h' | xargs ctags
 
-.PHONY: tags $(SUB_DIRS)
+.PHONY: tags $(SUB_DIRS) emit_tests
index 2b95e44..a284fa8 100644 (file)
@@ -30,13 +30,14 @@ override define RUN_TESTS
        +TARGET=event_code_tests; BUILD_TARGET=$$OUTPUT/$$TARGET; $(MAKE) OUTPUT=$$BUILD_TARGET -C $$TARGET run_tests
 endef
 
-DEFAULT_EMIT_TESTS := $(EMIT_TESTS)
-override define EMIT_TESTS
-       $(DEFAULT_EMIT_TESTS)
+emit_tests:
+       for TEST in $(TEST_GEN_PROGS); do \
+               BASENAME_TEST=`basename $$TEST`;        \
+               echo "$(COLLECTION):$$BASENAME_TEST";   \
+       done
        +TARGET=ebb; BUILD_TARGET=$$OUTPUT/$$TARGET; $(MAKE) OUTPUT=$$BUILD_TARGET -s -C $$TARGET emit_tests
        +TARGET=sampling_tests; BUILD_TARGET=$$OUTPUT/$$TARGET; $(MAKE) OUTPUT=$$BUILD_TARGET -s -C $$TARGET emit_tests
        +TARGET=event_code_tests; BUILD_TARGET=$$OUTPUT/$$TARGET; $(MAKE) OUTPUT=$$BUILD_TARGET -s -C $$TARGET emit_tests
-endef
 
 DEFAULT_INSTALL_RULE := $(INSTALL_RULE)
 override define INSTALL_RULE
@@ -64,4 +65,4 @@ sampling_tests:
 event_code_tests:
        TARGET=$@; BUILD_TARGET=$$OUTPUT/$$TARGET; mkdir -p $$BUILD_TARGET; $(MAKE) OUTPUT=$$BUILD_TARGET -k -C $$TARGET all
 
-.PHONY: all run_tests ebb sampling_tests event_code_tests
+.PHONY: all run_tests ebb sampling_tests event_code_tests emit_tests
index b16c136..ee71ce5 100644 (file)
@@ -267,6 +267,7 @@ static const char g_smaps_rollup[] =
 "Private_Dirty:         0 kB\n"
 "Referenced:            0 kB\n"
 "Anonymous:             0 kB\n"
+"KSM:                   0 kB\n"
 "LazyFree:              0 kB\n"
 "AnonHugePages:         0 kB\n"
 "ShmemPmdMapped:        0 kB\n"
index 22374d2..8202f13 100644 (file)
@@ -91,16 +91,18 @@ static int reg_disable(long *enable, int bit)
 
 FIXTURE(user) {
        long check;
+       bool umount;
 };
 
 FIXTURE_SETUP(user) {
-       USER_EVENT_FIXTURE_SETUP(return);
+       USER_EVENT_FIXTURE_SETUP(return, self->umount);
 
        change_event(false);
        self->check = 0;
 }
 
 FIXTURE_TEARDOWN(user) {
+       USER_EVENT_FIXTURE_TEARDOWN(self->umount);
 }
 
 TEST_F(user, enablement) {
index 32c827a..a859801 100644 (file)
@@ -144,13 +144,16 @@ do { \
 
 FIXTURE(user) {
        int check;
+       bool umount;
 };
 
 FIXTURE_SETUP(user) {
-       USER_EVENT_FIXTURE_SETUP(return);
+       USER_EVENT_FIXTURE_SETUP(return, self->umount);
 }
 
 FIXTURE_TEARDOWN(user) {
+       USER_EVENT_FIXTURE_TEARDOWN(self->umount);
+
        wait_for_delete();
 }
 
index 6a260ca..dcd7509 100644 (file)
@@ -204,10 +204,11 @@ FIXTURE(user) {
        int data_fd;
        int enable_fd;
        int check;
+       bool umount;
 };
 
 FIXTURE_SETUP(user) {
-       USER_EVENT_FIXTURE_SETUP(return);
+       USER_EVENT_FIXTURE_SETUP(return, self->umount);
 
        self->status_fd = open(status_file, O_RDONLY);
        ASSERT_NE(-1, self->status_fd);
@@ -219,6 +220,8 @@ FIXTURE_SETUP(user) {
 }
 
 FIXTURE_TEARDOWN(user) {
+       USER_EVENT_FIXTURE_TEARDOWN(self->umount);
+
        close(self->status_fd);
        close(self->data_fd);
 
index f893398..5288e76 100644 (file)
@@ -111,16 +111,19 @@ static int clear(int *check)
 FIXTURE(user) {
        int data_fd;
        int check;
+       bool umount;
 };
 
 FIXTURE_SETUP(user) {
-       USER_EVENT_FIXTURE_SETUP(return);
+       USER_EVENT_FIXTURE_SETUP(return, self->umount);
 
        self->data_fd = open(data_file, O_RDWR);
        ASSERT_NE(-1, self->data_fd);
 }
 
 FIXTURE_TEARDOWN(user) {
+       USER_EVENT_FIXTURE_TEARDOWN(self->umount);
+
        close(self->data_fd);
 
        if (clear(&self->check) != 0)
index 6903789..e1c3c06 100644 (file)
 
 #include "../kselftest.h"
 
-static inline bool tracefs_enabled(char **message, bool *fail)
+static inline void tracefs_unmount(void)
+{
+       umount("/sys/kernel/tracing");
+}
+
+static inline bool tracefs_enabled(char **message, bool *fail, bool *umount)
 {
        struct stat buf;
        int ret;
 
        *message = "";
        *fail = false;
+       *umount = false;
 
        /* Ensure tracefs is installed */
        ret = stat("/sys/kernel/tracing", &buf);
@@ -37,6 +43,8 @@ static inline bool tracefs_enabled(char **message, bool *fail)
                        return false;
                }
 
+               *umount = true;
+
                ret = stat("/sys/kernel/tracing/README", &buf);
        }
 
@@ -49,13 +57,14 @@ static inline bool tracefs_enabled(char **message, bool *fail)
        return true;
 }
 
-static inline bool user_events_enabled(char **message, bool *fail)
+static inline bool user_events_enabled(char **message, bool *fail, bool *umount)
 {
        struct stat buf;
        int ret;
 
        *message = "";
        *fail = false;
+       *umount = false;
 
        if (getuid() != 0) {
                *message = "Must be run as root";
@@ -63,7 +72,7 @@ static inline bool user_events_enabled(char **message, bool *fail)
                return false;
        }
 
-       if (!tracefs_enabled(message, fail))
+       if (!tracefs_enabled(message, fail, umount))
                return false;
 
        /* Ensure user_events is installed */
@@ -85,10 +94,10 @@ static inline bool user_events_enabled(char **message, bool *fail)
        return true;
 }
 
-#define USER_EVENT_FIXTURE_SETUP(statement) do { \
+#define USER_EVENT_FIXTURE_SETUP(statement, umount) do { \
        char *message; \
        bool fail; \
-       if (!user_events_enabled(&message, &fail)) { \
+       if (!user_events_enabled(&message, &fail, &(umount))) { \
                if (fail) { \
                        TH_LOG("Setup failed due to: %s", message); \
                        ASSERT_FALSE(fail); \
@@ -97,4 +106,9 @@ static inline bool user_events_enabled(char **message, bool *fail)
        } \
 } while (0)
 
+#define USER_EVENT_FIXTURE_TEARDOWN(umount) do { \
+       if ((umount))  \
+               tracefs_unmount(); \
+} while (0)
+
 #endif /* _USER_EVENTS_SELFTESTS_H */
index e0ffe69..7093fd5 100644 (file)
@@ -159,6 +159,7 @@ static int timerlat_aa_irq_latency(struct timerlat_aa_data *taa_data,
        taa_data->thread_nmi_sum = 0;
        taa_data->thread_irq_sum = 0;
        taa_data->thread_softirq_sum = 0;
+       taa_data->thread_thread_sum = 0;
        taa_data->thread_blocking_duration = 0;
        taa_data->timer_irq_start_time = 0;
        taa_data->timer_irq_duration = 0;
@@ -337,7 +338,23 @@ static int timerlat_aa_irq_handler(struct trace_seq *s, struct tep_record *recor
                taa_data->timer_irq_start_time = start;
                taa_data->timer_irq_duration = duration;
 
-               taa_data->timer_irq_start_delay = taa_data->timer_irq_start_time - expected_start;
+               /*
+                * We are dealing with two different clock sources: the
+                * external clock source that timerlat uses as a reference
+                * and the clock used by the tracer. There are also two
+                * moments: the time reading the clock and the timer in
+                * which the event is placed in the buffer (the trace
+                * event timestamp). If the processor is slow or there
+                * is some hardware noise, the difference between the
+                * timestamp and the external clock read can be longer
+                * than the IRQ handler delay, resulting in a negative
+                * time. If so, set IRQ start delay as 0. In the end,
+                * it is less relevant than the noise.
+                */
+               if (expected_start < taa_data->timer_irq_start_time)
+                       taa_data->timer_irq_start_delay = taa_data->timer_irq_start_time - expected_start;
+               else
+                       taa_data->timer_irq_start_delay = 0;
 
                /*
                 * not exit from idle.
@@ -528,7 +545,7 @@ static int timerlat_aa_kworker_start_handler(struct trace_seq *s, struct tep_rec
 static void timerlat_thread_analysis(struct timerlat_aa_data *taa_data, int cpu,
                                     int irq_thresh, int thread_thresh)
 {
-       unsigned long long exp_irq_ts;
+       long long exp_irq_ts;
        int total;
        int irq;
 
@@ -545,12 +562,15 @@ static void timerlat_thread_analysis(struct timerlat_aa_data *taa_data, int cpu,
 
        /*
         * Expected IRQ arrival time using the trace clock as the base.
+        *
+        * TODO: Add a list of previous IRQ, and then run the list backwards.
         */
        exp_irq_ts = taa_data->timer_irq_start_time - taa_data->timer_irq_start_delay;
-
-       if (exp_irq_ts < taa_data->prev_irq_timstamp + taa_data->prev_irq_duration)
-               printf("  Previous IRQ interference:    \t\t up to  %9.2f us\n",
-                       ns_to_usf(taa_data->prev_irq_duration));
+       if (exp_irq_ts < taa_data->prev_irq_timstamp + taa_data->prev_irq_duration) {
+               if (taa_data->prev_irq_timstamp < taa_data->timer_irq_start_time)
+                       printf("  Previous IRQ interference:    \t\t up to  %9.2f us\n",
+                               ns_to_usf(taa_data->prev_irq_duration));
+       }
 
        /*
         * The delay that the IRQ suffered before starting.
index 05e3106..01dbf9a 100644 (file)
@@ -45,7 +45,7 @@ static int timerlat_u_main(int cpu, struct timerlat_u_params *params)
 
        retval = sched_setaffinity(gettid(), sizeof(set), &set);
        if (retval == -1) {
-               err_msg("Error setting user thread affinity\n");
+               debug_msg("Error setting user thread affinity %d, is the CPU online?\n", cpu);
                exit(1);
        }
 
@@ -193,7 +193,9 @@ void *timerlat_u_dispatcher(void *data)
                                        procs_count--;
                                }
                        }
-                       break;
+
+                       if (!procs_count)
+                               break;
                }
 
                sleep(1);