]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
Merge tag 'kvm-x86-mmu-6.7' of https://github.com/kvm-x86/linux into HEAD
authorPaolo Bonzini <pbonzini@redhat.com>
Tue, 31 Oct 2023 14:17:43 +0000 (10:17 -0400)
committerPaolo Bonzini <pbonzini@redhat.com>
Tue, 31 Oct 2023 14:17:43 +0000 (10:17 -0400)
KVM x86 MMU changes for 6.7:

 - Clean up code that deals with honoring guest MTRRs when the VM has
   non-coherent DMA and host MTRRs are ignored, i.e. EPT is enabled.

 - Zap EPT entries when non-coherent DMA assignment stops/start to prevent
   using stale entries with the wrong memtype.

 - Don't ignore guest PAT for CR0.CD=1 && KVM_X86_QUIRK_CD_NW_CLEARED=y, as
   there's zero reason to ignore guest PAT if the effective MTRR memtype is WB.
   This will also allow for future optimizations of handling guest MTRR updates
   for VMs with non-coherent DMA and the quirk enabled.

 - Harden the fast page fault path to guard against encountering an invalid
   root when walking SPTEs.

1550 files changed:
.mailmap
Documentation/ABI/testing/sysfs-class-firmware
Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-sec-update
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/core-api/workqueue.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/dma/xilinx/xlnx,zynqmp-dma-1.0.yaml
Documentation/devicetree/bindings/i2c/i2c-mxs.yaml
Documentation/devicetree/bindings/iio/adc/adi,ad7292.yaml
Documentation/devicetree/bindings/iio/addac/adi,ad74115.yaml
Documentation/devicetree/bindings/iio/dac/adi,ad5758.yaml
Documentation/devicetree/bindings/iio/health/ti,afe4403.yaml
Documentation/devicetree/bindings/iio/health/ti,afe4404.yaml
Documentation/devicetree/bindings/iio/light/rohm,bu27010.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/mmc/sdhci-msm.yaml
Documentation/devicetree/bindings/pci/brcm,iproc-pcie.yaml
Documentation/devicetree/bindings/phy/qcom,ipq8074-qmp-pcie-phy.yaml
Documentation/devicetree/bindings/riscv/cpus.yaml
Documentation/devicetree/bindings/riscv/extensions.yaml
Documentation/devicetree/bindings/soc/loongson/loongson,ls2k-pmc.yaml
Documentation/devicetree/bindings/sound/cirrus,cs42l43.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/overlayfs.rst
Documentation/filesystems/porting.rst
Documentation/kbuild/kconfig-language.rst
Documentation/netlink/specs/devlink.yaml
Documentation/networking/ax25.rst
Documentation/networking/representors.rst
Documentation/process/embargoed-hardware-issues.rst
Documentation/rust/general-information.rst
Documentation/sound/designs/midi-2.0.rst
Documentation/tools/rtla/rtla-timerlat-hist.rst
Documentation/trace/fprobe.rst
Documentation/translations/zh_CN/arch/loongarch/introduction.rst
Documentation/translations/zh_CN/core-api/workqueue.rst
Documentation/virt/kvm/api.rst
Documentation/virt/kvm/x86/mmu.rst
MAINTAINERS
Makefile
arch/arm/boot/dts/rockchip/rk3128.dtsi
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/omap4-l4-abe.dtsi
arch/arm/boot/dts/ti/omap/omap4-l4.dtsi
arch/arm/boot/dts/ti/omap/omap443x.dtsi
arch/arm/boot/dts/ti/omap/omap4460.dtsi
arch/arm/boot/dts/ti/omap/omap5-l4-abe.dtsi
arch/arm/include/asm/hardware/locomo.h
arch/arm/mach-omap1/board-ams-delta.c
arch/arm/mach-omap1/timer32k.c
arch/arm/mach-omap2/omap_hwmod.c
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/freescale/imx93.dtsi
arch/arm64/boot/dts/mediatek/mt7622.dtsi
arch/arm64/boot/dts/mediatek/mt7986a.dtsi
arch/arm64/boot/dts/mediatek/mt8195-demo.dts
arch/arm64/boot/dts/mediatek/mt8195.dtsi
arch/arm64/boot/dts/qcom/apq8096-db820c.dts
arch/arm64/boot/dts/qcom/msm8996-xiaomi-common.dtsi
arch/arm64/boot/dts/qcom/msm8996-xiaomi-gemini.dts
arch/arm64/boot/dts/qcom/sa8775p-pmics.dtsi
arch/arm64/boot/dts/qcom/sm8150.dtsi
arch/arm64/boot/dts/rockchip/px30-ringneck-haikou.dts
arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dtsi
arch/arm64/boot/dts/rockchip/rk3399.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/include/asm/cpu.h
arch/ia64/kernel/acpi.c
arch/ia64/kernel/topology.c
arch/loongarch/Kbuild
arch/loongarch/Kconfig
arch/loongarch/configs/loongson3_defconfig
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/inst.h
arch/loongarch/include/asm/io.h
arch/loongarch/include/asm/kasan.h
arch/loongarch/include/asm/kvm_csr.h [new file with mode: 0644]
arch/loongarch/include/asm/kvm_host.h [new file with mode: 0644]
arch/loongarch/include/asm/kvm_mmu.h [new file with mode: 0644]
arch/loongarch/include/asm/kvm_types.h [new file with mode: 0644]
arch/loongarch/include/asm/kvm_vcpu.h [new file with mode: 0644]
arch/loongarch/include/asm/linkage.h
arch/loongarch/include/asm/loongarch.h
arch/loongarch/include/asm/pgtable-bits.h
arch/loongarch/include/asm/smp.h
arch/loongarch/include/uapi/asm/kvm.h [new file with mode: 0644]
arch/loongarch/kernel/Makefile
arch/loongarch/kernel/acpi.c
arch/loongarch/kernel/asm-offsets.c
arch/loongarch/kernel/entry.S
arch/loongarch/kernel/genex.S
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/setup.c
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/kvm/Kconfig [new file with mode: 0644]
arch/loongarch/kvm/Makefile [new file with mode: 0644]
arch/loongarch/kvm/exit.c [new file with mode: 0644]
arch/loongarch/kvm/interrupt.c [new file with mode: 0644]
arch/loongarch/kvm/main.c [new file with mode: 0644]
arch/loongarch/kvm/mmu.c [new file with mode: 0644]
arch/loongarch/kvm/switch.S [new file with mode: 0644]
arch/loongarch/kvm/timer.c [new file with mode: 0644]
arch/loongarch/kvm/tlb.c [new file with mode: 0644]
arch/loongarch/kvm/trace.h [new file with mode: 0644]
arch/loongarch/kvm/vcpu.c [new file with mode: 0644]
arch/loongarch/kvm/vm.c [new file with mode: 0644]
arch/loongarch/mm/fault.c
arch/loongarch/mm/hugetlbpage.c
arch/loongarch/mm/init.c
arch/loongarch/mm/ioremap.c
arch/loongarch/mm/kasan_init.c
arch/loongarch/mm/tlb.c
arch/loongarch/mm/tlbex.S
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/include/asm/nohash/32/pte-8xx.h
arch/powerpc/include/asm/nohash/64/pgtable.h
arch/powerpc/include/asm/nohash/pgtable.h
arch/powerpc/kernel/entry_32.S
arch/powerpc/kernel/head_85xx.S
arch/powerpc/kernel/hw_breakpoint.c
arch/powerpc/kernel/hw_breakpoint_constraints.c
arch/powerpc/kernel/setup-common.c
arch/powerpc/kernel/stacktrace.c
arch/powerpc/kernel/traps.c
arch/powerpc/lib/qspinlock.c
arch/powerpc/mm/book3s64/hugetlbpage.c
arch/powerpc/mm/book3s64/radix_hugetlbpage.c
arch/powerpc/mm/book3s64/radix_tlb.c
arch/powerpc/mm/mem.c
arch/powerpc/mm/nohash/8xx.c
arch/powerpc/mm/pgtable.c
arch/powerpc/perf/hv-24x7.c
arch/powerpc/platforms/82xx/Kconfig
arch/powerpc/platforms/pseries/hvCall.S
arch/riscv/Kconfig
arch/riscv/Kconfig.errata
arch/riscv/Makefile
arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
arch/riscv/boot/dts/thead/th1520.dtsi
arch/riscv/errata/andes/Makefile
arch/riscv/include/asm/csr.h
arch/riscv/include/asm/ftrace.h
arch/riscv/include/asm/hugetlb.h
arch/riscv/include/asm/hwcap.h
arch/riscv/include/asm/kprobes.h
arch/riscv/include/asm/kvm_host.h
arch/riscv/include/asm/kvm_vcpu_sbi.h
arch/riscv/include/asm/sbi.h
arch/riscv/include/asm/uprobes.h
arch/riscv/include/uapi/asm/kvm.h
arch/riscv/kernel/cpufeature.c
arch/riscv/kernel/irq.c
arch/riscv/kernel/setup.c
arch/riscv/kernel/signal.c
arch/riscv/kernel/traps.c
arch/riscv/kvm/vcpu.c
arch/riscv/kvm/vcpu_onereg.c
arch/riscv/kvm/vcpu_sbi.c
arch/riscv/kvm/vcpu_sbi_replace.c
arch/riscv/mm/fault.c
arch/riscv/mm/hugetlbpage.c
arch/riscv/net/bpf_jit_comp64.c
arch/s390/boot/vmem.c
arch/s390/configs/debug_defconfig
arch/s390/configs/defconfig
arch/s390/configs/zfcpdump_defconfig
arch/s390/include/asm/hugetlb.h
arch/s390/include/asm/kvm_host.h
arch/s390/kernel/cert_store.c
arch/s390/kvm/gaccess.c
arch/s390/kvm/interrupt.c
arch/s390/kvm/kvm-s390.c
arch/s390/kvm/trace-s390.h
arch/s390/kvm/vsie.c
arch/s390/mm/hugetlbpage.c
arch/s390/net/bpf_jit_comp.c
arch/s390/pci/pci_dma.c
arch/sh/mm/ioremap.c
arch/sparc/include/asm/hugetlb.h
arch/sparc/lib/checksum_32.S
arch/sparc/mm/hugetlbpage.c
arch/x86/boot/compressed/sev.c
arch/x86/entry/common.c
arch/x86/events/amd/core.c
arch/x86/events/utils.c
arch/x86/hyperv/hv_init.c
arch/x86/hyperv/hv_vtl.c
arch/x86/include/asm/cpu.h
arch/x86/include/asm/cpufeatures.h
arch/x86/include/asm/fpu/api.h
arch/x86/include/asm/i8259.h
arch/x86/include/asm/intel-family.h
arch/x86/include/asm/kvm-x86-ops.h
arch/x86/include/asm/kvm_host.h
arch/x86/include/asm/linkage.h
arch/x86/include/asm/mmu_context.h
arch/x86/include/asm/mshyperv.h
arch/x86/include/asm/msr-index.h
arch/x86/include/asm/paravirt_types.h
arch/x86/include/asm/pgtable.h
arch/x86/include/asm/processor.h
arch/x86/include/asm/smp.h
arch/x86/include/asm/svm.h
arch/x86/include/asm/xen/hypervisor.h
arch/x86/kernel/acpi/boot.c
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/resctrl/monitor.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/i8259.c
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/kernel/smp.c
arch/x86/kernel/smpboot.c
arch/x86/kernel/topology.c
arch/x86/kernel/tsc_sync.c
arch/x86/kvm/Kconfig
arch/x86/kvm/cpuid.c
arch/x86/kvm/cpuid.h
arch/x86/kvm/hyperv.c
arch/x86/kvm/lapic.c
arch/x86/kvm/pmu.c
arch/x86/kvm/pmu.h
arch/x86/kvm/smm.c
arch/x86/kvm/svm/avic.c
arch/x86/kvm/svm/nested.c
arch/x86/kvm/svm/pmu.c
arch/x86/kvm/svm/svm.c
arch/x86/kvm/vmx/pmu_intel.c
arch/x86/kvm/vmx/vmx.c
arch/x86/kvm/x86.c
arch/x86/kvm/x86.h
arch/x86/kvm/xen.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/blk-throttle.c
block/disk-events.c
block/fops.c
block/sed-opal.c
crypto/asymmetric_keys/public_key.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_hw.h
drivers/accel/ivpu/ivpu_hw_37xx.c
drivers/accel/ivpu/ivpu_hw_40xx.c
drivers/accel/ivpu/ivpu_hw_40xx_reg.h
drivers/accel/ivpu/ivpu_ipc.c
drivers/accel/ivpu/ivpu_mmu_context.c
drivers/accel/ivpu/ivpu_pm.c
drivers/acpi/acpi_processor.c
drivers/acpi/acpi_video.c
drivers/acpi/bus.c
drivers/acpi/ec.c
drivers/acpi/irq.c
drivers/acpi/nfit/core.c
drivers/acpi/processor_idle.c
drivers/acpi/processor_pdc.c
drivers/acpi/resource.c
drivers/android/binder.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/base/regmap/regmap.c
drivers/block/nbd.c
drivers/block/rbd.c
drivers/bluetooth/btrtl.c
drivers/bluetooth/btusb.c
drivers/bluetooth/hci_vhci.c
drivers/bus/ti-sysc.c
drivers/cache/Kconfig
drivers/clk/clk-si521xx.c
drivers/clk/clk-versaclock3.c
drivers/clk/clk.c
drivers/clk/socfpga/clk-gate.c
drivers/clk/sprd/ums512-clk.c
drivers/clk/stm32/clk-stm32-core.c
drivers/clk/tegra/clk-bpmp.c
drivers/clk/ti/clk-44xx.c
drivers/clk/ti/clk-54xx.c
drivers/connector/cn_proc.c
drivers/counter/counter-chrdev.c
drivers/counter/microchip-tcb-capture.c
drivers/crypto/virtio/virtio_crypto_common.h
drivers/crypto/virtio/virtio_crypto_core.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-buf/dma-fence-unwrap.c
drivers/dma-buf/sync_file.c
drivers/dma/fsl-edma-common.c
drivers/dma/fsl-edma-common.h
drivers/dma/fsl-edma-main.c
drivers/dma/idxd/device.c
drivers/dma/mediatek/mtk-uart-apdma.c
drivers/dma/ste_dma40.c
drivers/dma/stm32-dma.c
drivers/dma/stm32-mdma.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/efi/libstub/x86-stub.c
drivers/firmware/efi/libstub/x86-stub.h
drivers/firmware/efi/unaccepted_memory.c
drivers/firmware/imx/imx-dsp.c
drivers/fpga/tests/Kconfig
drivers/fpga/tests/fpga-region-test.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/gpio/gpio-vf610.c
drivers/gpio/gpiolib-acpi.c
drivers/gpu/drm/Kconfig
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c
drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
drivers/gpu/drm/amd/amdgpu/amdgpu_doorbell_mgr.c
drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c
drivers/gpu/drm/amd/amdgpu/amdgpu_object.h
drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
drivers/gpu/drm/amd/amdgpu/vi.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/core/dc.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/bridge/ti-sn65dsi86.c
drivers/gpu/drm/display/drm_dp_mst_topology.c
drivers/gpu/drm/drm_atomic_helper.c
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/drm_gem.c
drivers/gpu/drm/drm_panel_orientation_quirks.c
drivers/gpu/drm/i915/display/intel_cx0_phy.c
drivers/gpu/drm/i915/gem/i915_gem_mman.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_gt_mcr.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/i915/i915_perf.c
drivers/gpu/drm/i915/i915_pmu.c
drivers/gpu/drm/logicvc/Kconfig
drivers/gpu/drm/mediatek/mtk_drm_gem.c
drivers/gpu/drm/meson/meson_encoder_hdmi.c
drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
drivers/gpu/drm/msm/dp/dp_ctrl.c
drivers/gpu/drm/msm/dp/dp_link.c
drivers/gpu/drm/msm/dsi/dsi_host.c
drivers/gpu/drm/msm/msm_mdss.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/nouveau/nvkm/engine/disp/uconn.c
drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c
drivers/gpu/drm/panel/panel-edp.c
drivers/gpu/drm/panel/panel-simple.c
drivers/gpu/drm/scheduler/sched_main.c
drivers/gpu/drm/tests/drm_kunit_helpers.c
drivers/gpu/drm/tests/drm_mm_test.c
drivers/gpu/drm/tiny/simpledrm.c
drivers/gpu/drm/ttm/ttm_device.c
drivers/gpu/drm/virtio/virtgpu_submit.c
drivers/gpu/drm/vmwgfx/vmwgfx_bo.c
drivers/gpu/drm/vmwgfx/vmwgfx_bo.h
drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
drivers/gpu/drm/vmwgfx/vmwgfx_gem.c
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c
drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
drivers/gpu/drm/vmwgfx/vmwgfx_shader.c
drivers/gpu/drm/vmwgfx/vmwgfx_surface.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/hwtracing/coresight/coresight-tmc-etr.c
drivers/i2c/busses/i2c-aspeed.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-stm32f7.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/i2c/muxes/i2c-mux-gpmux.c
drivers/i2c/muxes/i2c-mux-pinctrl.c
drivers/iio/adc/ad7192.c
drivers/iio/adc/exynos_adc.c
drivers/iio/adc/imx8qxp-adc.c
drivers/iio/adc/xilinx-xadc-core.c
drivers/iio/adc/xilinx-xadc.h
drivers/iio/addac/Kconfig
drivers/iio/afe/iio-rescale.c
drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c
drivers/iio/dac/ad3552r.c
drivers/iio/frequency/admv1013.c
drivers/iio/imu/bno055/Kconfig
drivers/iio/light/vcnl4000.c
drivers/iio/pressure/bmp280-core.c
drivers/iio/pressure/dps310.c
drivers/iio/pressure/ms5611_core.c
drivers/iio/proximity/irsd200.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/input/joystick/xpad.c
drivers/input/misc/powermate.c
drivers/input/mouse/elantech.c
drivers/input/mouse/psmouse-smbus.c
drivers/input/mouse/synaptics.c
drivers/input/rmi4/rmi_smbus.c
drivers/input/serio/i8042-acpipnpio.h
drivers/input/touchscreen/goodix.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/iommu.c
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/isdn/hardware/mISDN/hfcsusb.c
drivers/leds/led-core.c
drivers/mcb/mcb-core.c
drivers/mcb/mcb-parse.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/ov8858.c
drivers/media/i2c/rdacm21.c
drivers/media/pci/bt8xx/bttv-risc.c
drivers/media/pci/intel/Kconfig
drivers/media/pci/intel/ipu-bridge.c
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/platform/xilinx/xilinx-vipp.c
drivers/media/usb/em28xx/Kconfig
drivers/media/usb/go7007/Kconfig
drivers/media/usb/uvc/uvc_ctrl.c
drivers/media/v4l2-core/v4l2-subdev.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/misc/fastrpc.c
drivers/mmc/core/block.c
drivers/mmc/core/mmc.c
drivers/mmc/core/sdio.c
drivers/mmc/host/mtk-sd.c
drivers/mmc/host/sdhci-pci-gli.c
drivers/mmc/host/sdhci-sprd.c
drivers/mtd/maps/physmap-core.c
drivers/mtd/nand/raw/arasan-nand-controller.c
drivers/mtd/nand/raw/marvell_nand.c
drivers/mtd/nand/raw/nand_base.c
drivers/mtd/nand/raw/nand_jedec.c
drivers/mtd/nand/raw/nand_onfi.c
drivers/mtd/nand/raw/pl35x-nand-controller.c
drivers/mtd/nand/raw/qcom_nandc.c
drivers/mtd/nand/spi/micron.c
drivers/mtd/ubi/build.c
drivers/net/bonding/bond_main.c
drivers/net/can/Kconfig
drivers/net/can/flexcan/flexcan-core.c
drivers/net/can/flexcan/flexcan.h
drivers/net/can/m_can/tcan4x5x-core.c
drivers/net/can/sja1000/sja1000.c
drivers/net/dsa/bcm_sf2.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/dsa/qca/qca8k-8xxx.c
drivers/net/ethernet/adi/adin1110.c
drivers/net/ethernet/amazon/ena/ena_netdev.c
drivers/net/ethernet/apm/xgene/xgene_enet_main.c
drivers/net/ethernet/broadcom/bnxt/bnxt.c
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_io.c
drivers/net/ethernet/engleder/tsnep_ethtool.c
drivers/net/ethernet/engleder/tsnep_main.c
drivers/net/ethernet/google/gve/gve_rx.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.h
drivers/net/ethernet/intel/i40e/i40e_common.c
drivers/net/ethernet/intel/i40e/i40e_txrx.c
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
drivers/net/ethernet/intel/i40e/i40e_xsk.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_lag.c
drivers/net/ethernet/intel/ice/ice_lag.h
drivers/net/ethernet/intel/ice/ice_lib.c
drivers/net/ethernet/intel/ice/ice_main.c
drivers/net/ethernet/intel/ice/ice_virtchnl.c
drivers/net/ethernet/intel/igb/igb_ethtool.c
drivers/net/ethernet/intel/igc/igc_ethtool.c
drivers/net/ethernet/intel/igc/igc_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.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/cn10k_macsec.c
drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c
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/mellanox/mlx5/core/cmd.c
drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c
drivers/net/ethernet/mellanox/mlx5/core/en/rep/bridge.c
drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c
drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c
drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c
drivers/net/ethernet/mellanox/mlx5/core/en_main.c
drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
drivers/net/ethernet/mellanox/mlx5/core/en_stats.h
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.c
drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.h
drivers/net/ethernet/mellanox/mlx5/core/esw/bridge_priv.h
drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_nve_vxlan.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/netronome/nfp/flower/cmsg.c
drivers/net/ethernet/netronome/nfp/flower/conntrack.c
drivers/net/ethernet/netronome/nfp/flower/main.h
drivers/net/ethernet/netronome/nfp/flower/metadata.c
drivers/net/ethernet/netronome/nfp/flower/offload.c
drivers/net/ethernet/netronome/nfp/flower/qos_conf.c
drivers/net/ethernet/pensando/ionic/ionic_dev.h
drivers/net/ethernet/pensando/ionic/ionic_txrx.c
drivers/net/ethernet/qlogic/qed/qed_ll2.c
drivers/net/ethernet/qlogic/qed/qed_ll2.h
drivers/net/ethernet/realtek/r8169_main.c
drivers/net/ethernet/renesas/ravb_main.c
drivers/net/ethernet/renesas/rswitch.c
drivers/net/ethernet/renesas/rswitch.h
drivers/net/ethernet/sfc/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/Makefile
drivers/net/ethernet/ti/am65-cpsw-nuss.c
drivers/net/ethernet/ti/icssg/icssg_config.c
drivers/net/ethernet/ti/icssg/icssg_prueth.c
drivers/net/ethernet/ti/icssg/icssg_stats.c
drivers/net/ethernet/ti/k3-cppi-desc-pool.c
drivers/net/ethernet/toshiba/ps3_gelic_wireless.c
drivers/net/gtp.c
drivers/net/ieee802154/adf7242.c
drivers/net/ieee802154/ca8210.c
drivers/net/macsec.c
drivers/net/mdio/mdio-mux.c
drivers/net/phy/bcm7xxx.c
drivers/net/phy/mscc/mscc_macsec.c
drivers/net/team/team.c
drivers/net/thunderbolt/main.c
drivers/net/tun.c
drivers/net/usb/dm9601.c
drivers/net/usb/r8152.c
drivers/net/usb/smsc75xx.c
drivers/net/usb/smsc95xx.c
drivers/net/virtio_net.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/net/wwan/iosm/iosm_ipc_imem.c
drivers/net/wwan/iosm/iosm_ipc_imem.h
drivers/net/wwan/iosm/iosm_ipc_pcie.c
drivers/net/wwan/iosm/iosm_ipc_port.c
drivers/net/wwan/iosm/iosm_ipc_trace.c
drivers/net/wwan/iosm/iosm_ipc_wwan.c
drivers/net/xen-netback/interface.c
drivers/nvme/host/auth.c
drivers/nvme/host/ioctl.c
drivers/nvme/host/pci.c
drivers/nvme/host/rdma.c
drivers/nvme/target/fabrics-cmd-auth.c
drivers/nvme/target/tcp.c
drivers/nvmem/imx-ocotp.c
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/perf/riscv_pmu.c
drivers/perf/riscv_pmu_sbi.c
drivers/phy/freescale/phy-fsl-lynx-28g.c
drivers/phy/motorola/phy-mapphone-mdm6600.c
drivers/phy/qualcomm/phy-qcom-apq8064-sata.c
drivers/phy/qualcomm/phy-qcom-m31.c
drivers/phy/qualcomm/phy-qcom-qmp-combo.c
drivers/phy/qualcomm/phy-qcom-qmp-pcs-usb-v6.h
drivers/phy/qualcomm/phy-qcom-qmp-usb.c
drivers/phy/realtek/Kconfig
drivers/phy/realtek/phy-rtk-usb2.c
drivers/phy/realtek/phy-rtk-usb3.c
drivers/pinctrl/nuvoton/pinctrl-wpcm450.c
drivers/pinctrl/pinctrl-lantiq.h
drivers/pinctrl/qcom/pinctrl-lpass-lpi.c
drivers/pinctrl/renesas/Kconfig
drivers/pinctrl/starfive/pinctrl-starfive-jh7110-aon.c
drivers/pinctrl/starfive/pinctrl-starfive-jh7110-sys.c
drivers/pinctrl/starfive/pinctrl-starfive-jh7110.c
drivers/pinctrl/starfive/pinctrl-starfive-jh7110.h
drivers/pinctrl/tegra/pinctrl-tegra.c
drivers/pinctrl/tegra/pinctrl-tegra.h
drivers/platform/mellanox/mlxbf-tmfifo.c
drivers/platform/surface/surface_platform_profile.c
drivers/platform/x86/amd/pmc/pmc-quirks.c
drivers/platform/x86/apple-gmux.c
drivers/platform/x86/asus-nb-wmi.c
drivers/platform/x86/asus-wmi.c
drivers/platform/x86/asus-wmi.h
drivers/platform/x86/hp/hp-bioscfg/bioscfg.c
drivers/platform/x86/hp/hp-wmi.c
drivers/platform/x86/intel/ifs/runtest.c
drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c
drivers/platform/x86/intel_scu_ipc.c
drivers/platform/x86/mlx-platform.c
drivers/platform/x86/msi-ec.c
drivers/platform/x86/think-lmi.c
drivers/platform/x86/thinkpad_acpi.c
drivers/platform/x86/touchscreen_dmi.c
drivers/pmdomain/imx/scu-pd.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/qcom_battmgr.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/cio/css.c
drivers/s390/net/Kconfig
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/mpt3sas/mpt3sas_scsih.c
drivers/scsi/qla2xxx/qla_os.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/soc/renesas/Kconfig
drivers/soundwire/Makefile
drivers/soundwire/bus.c
drivers/soundwire/bus_type.c
drivers/soundwire/irq.c [new file with mode: 0644]
drivers/soundwire/irq.h [new file with mode: 0644]
drivers/spi/spi-cs42l43.c
drivers/spi/spi-gxp.c
drivers/spi/spi-imx.c
drivers/spi/spi-intel-pci.c
drivers/spi/spi-npcm-fiu.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/amdtee/core.c
drivers/tee/optee/optee_private.h
drivers/tee/tee_private.h
drivers/thermal/thermal_sysfs.c
drivers/thunderbolt/icm.c
drivers/thunderbolt/switch.c
drivers/thunderbolt/tb.c
drivers/thunderbolt/tmu.c
drivers/thunderbolt/xdomain.c
drivers/tty/n_gsm.c
drivers/tty/serial/8250/8250_omap.c
drivers/tty/serial/8250/8250_port.c
drivers/tty/serial/serial_core.c
drivers/ufs/core/ufshcd.c
drivers/usb/cdns3/cdnsp-gadget.c
drivers/usb/cdns3/core.h
drivers/usb/core/hub.c
drivers/usb/core/hub.h
drivers/usb/dwc3/core.c
drivers/usb/gadget/function/f_ncm.c
drivers/usb/gadget/udc/udc-xilinx.c
drivers/usb/host/xhci-hub.c
drivers/usb/host/xhci-mem.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.h
drivers/usb/misc/onboard_usb_hub.c
drivers/usb/misc/onboard_usb_hub.h
drivers/usb/musb/musb_debugfs.c
drivers/usb/musb/musb_host.c
drivers/usb/serial/option.c
drivers/usb/typec/altmodes/displayport.c
drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy.c
drivers/usb/typec/ucsi/psy.c
drivers/usb/typec/ucsi/ucsi.c
drivers/vdpa/mlx5/net/debug.c
drivers/vdpa/mlx5/net/mlx5_vnet.c
drivers/vdpa/mlx5/net/mlx5_vnet.h
drivers/vdpa/vdpa_sim/vdpa_sim_blk.c
drivers/vfio/mdev/mdev_sysfs.c
drivers/vfio/pci/pds/Kconfig
drivers/vfio/pci/pds/vfio_dev.c
drivers/vhost/vhost.c
drivers/vhost/vringh.c
drivers/video/console/Kconfig
drivers/video/fbdev/Kconfig
drivers/video/fbdev/aty/atyfb_base.c
drivers/video/fbdev/core/Kconfig
drivers/video/fbdev/core/cfbcopyarea.c
drivers/video/fbdev/core/syscopyarea.c
drivers/video/fbdev/mmp/hw/mmp_ctrl.h
drivers/video/fbdev/omap/omapfb_main.c
drivers/video/fbdev/sa1100fb.c
drivers/video/fbdev/uvesafb.c
drivers/virtio/virtio_balloon.c
drivers/virtio/virtio_mmio.c
drivers/virtio/virtio_pci_modern_dev.c
drivers/xen/events/events_base.c
drivers/xen/platform-pci.c
fs/aio.c
fs/binfmt_elf_fdpic.c
fs/btrfs/backref.c
fs/btrfs/backref.h
fs/btrfs/ctree.c
fs/btrfs/ctree.h
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/relocation.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/ceph/file.c
fs/ceph/inode.c
fs/ceph/mds_client.c
fs/erofs/decompressor_lzma.c
fs/erofs/super.c
fs/ext4/super.c
fs/fs-writeback.c
fs/fs_context.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/namei.c
fs/netfs/buffered_read.c
fs/nfs/direct.c
fs/nfs/flexfilelayout/flexfilelayout.c
fs/nfs/nfs42proc.c
fs/nfs/nfs4client.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c
fs/nfs/pnfs.c
fs/nfs/write.c
fs/nfsd/nfs4xdr.c
fs/nfsd/vfs.c
fs/nilfs2/gcinode.c
fs/notify/fanotify/fanotify_user.c
fs/ntfs3/attrib.c
fs/ntfs3/attrlist.c
fs/ntfs3/bitmap.c
fs/ntfs3/dir.c
fs/ntfs3/file.c
fs/ntfs3/frecord.c
fs/ntfs3/fslog.c
fs/ntfs3/fsntfs.c
fs/ntfs3/index.c
fs/ntfs3/inode.c
fs/ntfs3/namei.c
fs/ntfs3/ntfs.h
fs/ntfs3/ntfs_fs.h
fs/ntfs3/record.c
fs/ntfs3/super.c
fs/ntfs3/xattr.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/cached_dir.h
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_ag.c
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/scrub/xfile.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_notify_failure.c
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/acpi/processor.h
include/asm-generic/hugetlb.h
include/asm-generic/mshyperv.h
include/asm-generic/vmlinux.lds.h
include/drm/gpu_scheduler.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/cgroup-defs.h
include/linux/cpu.h
include/linux/cpuhotplug.h
include/linux/dma-fence.h
include/linux/fs.h
include/linux/fs_context.h
include/linux/hugetlb.h
include/linux/ieee80211.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/mcb.h
include/linux/memcontrol.h
include/linux/mtd/jedec.h
include/linux/mtd/onfi.h
include/linux/mtd/rawnand.h
include/linux/netfilter/nf_conntrack_sctp.h
include/linux/nfs_fs_sb.h
include/linux/nfs_page.h
include/linux/perf_event.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/skbuff.h
include/linux/sunrpc/xdr.h
include/linux/swiotlb.h
include/linux/virtio_net.h
include/net/bluetooth/hci_core.h
include/net/bluetooth/hci_mon.h
include/net/cfg80211.h
include/net/ip_fib.h
include/net/macsec.h
include/net/mana/mana.h
include/net/neighbour.h
include/net/netfilter/nf_flow_table.h
include/net/netfilter/nf_tables.h
include/net/netns/xfrm.h
include/net/page_pool/helpers.h
include/net/sock.h
include/net/tcp.h
include/scsi/scsi.h
include/scsi/scsi_device.h
include/scsi/scsi_host.h
include/sound/soc-dapm.h
include/sound/soc.h
include/trace/events/neigh.h
include/trace/events/xen.h
include/uapi/drm/nouveau_drm.h
include/uapi/linux/bpf.h
include/uapi/linux/gtp.h
include/uapi/linux/if_packet.h
include/uapi/linux/kvm.h
include/uapi/linux/stddef.h
include/video/mmp_disp.h
include/video/uvesafb.h
include/xen/arm/hypervisor.h
include/xen/events.h
io_uring/fdinfo.c
io_uring/fs.c
io_uring/io-wq.c
io_uring/io_uring.c
io_uring/io_uring.h
io_uring/kbuf.c
io_uring/rw.c
kernel/auditsc.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/syscall.c
kernel/bpf/tcx.c
kernel/bpf/verifier.c
kernel/cgroup/cgroup-v1.c
kernel/crash_core.c
kernel/dma/swiotlb.c
kernel/events/core.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/fprobe.c
kernel/trace/ring_buffer.c
kernel/trace/trace_events.c
kernel/trace/trace_events_user.c
kernel/trace/trace_kprobe.c
kernel/trace/trace_probe.h
kernel/workqueue.c
lib/argv_split.c
lib/maple_tree.c
lib/scatterlist.c
lib/test_maple_tree.c
mm/damon/sysfs.c
mm/damon/vaddr-test.h
mm/damon/vaddr.c
mm/filemap.c
mm/hugetlb.c
mm/kasan/kasan.h
mm/kasan/report.c
mm/memcontrol.c
mm/memory.c
mm/mempolicy.c
mm/migrate.c
mm/mmap.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_sock.c
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/can/isotp.c
net/ceph/messenger.c
net/core/dev.c
net/core/dev.h
net/core/flow_dissector.c
net/core/neighbour.c
net/core/pktgen.c
net/core/rtnetlink.c
net/core/sock_map.c
net/core/stream.c
net/dccp/ipv4.c
net/dccp/ipv6.c
net/devlink/health.c
net/ethtool/plca.c
net/handshake/handshake-test.c
net/handshake/netlink.c
net/hsr/hsr_framereg.c
net/hsr/hsr_main.h
net/ipv4/af_inet.c
net/ipv4/esp4.c
net/ipv4/fib_semantics.c
net/ipv4/fib_trie.c
net/ipv4/inet_connection_sock.c
net/ipv4/inet_hashtables.c
net/ipv4/route.c
net/ipv4/tcp.c
net/ipv4/tcp_bpf.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_output.c
net/ipv4/tcp_recovery.c
net/ipv6/esp6.c
net/ipv6/tcp_ipv6.c
net/ipv6/xfrm6_policy.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/rx.c
net/mac80211/tx.c
net/mac80211/vht.c
net/mctp/route.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_flow_table_core.c
net/netfilter/nf_tables_api.c
net/netfilter/nfnetlink_log.c
net/netfilter/nft_inner.c
net/netfilter/nft_payload.c
net/netfilter/nft_set_hash.c
net/netfilter/nft_set_pipapo.c
net/netfilter/nft_set_pipapo.h
net/netfilter/nft_set_rbtree.c
net/netlink/af_netlink.c
net/nfc/llcp_core.c
net/nfc/nci/core.c
net/nfc/nci/spi.c
net/packet/af_packet.c
net/rds/rdma_transport.c
net/rds/tcp_connect.c
net/rds/tcp_listen.c
net/rfkill/core.c
net/rfkill/rfkill-gpio.c
net/sched/act_ct.c
net/sched/cls_u32.c
net/sched/sch_hfsc.c
net/sctp/associola.c
net/sctp/socket.c
net/smc/Kconfig
net/smc/af_smc.c
net/smc/smc_ib.c
net/smc/smc_ib.h
net/smc/smc_stats.h
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/tls/tls_main.c
net/tls/tls_sw.c
net/vmw_vsock/virtio_transport.c
net/wireless/core.c
net/wireless/core.h
net/wireless/mlme.c
net/wireless/nl80211.c
net/wireless/scan.c
net/xdp/xsk_queue.c
net/xfrm/xfrm_interface_core.c
net/xfrm/xfrm_policy.c
rust/Makefile
rust/kernel/error.rs
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-jack.c
sound/soc/codecs/cs42l43.c
sound/soc/codecs/da7219-aad.c
sound/soc/codecs/hdmi-codec.c
sound/soc/codecs/lpass-wsa-macro.c
sound/soc/codecs/rt5640.c
sound/soc/codecs/rt5645.c
sound/soc/codecs/rt5682-i2c.c
sound/soc/codecs/tas2780.c
sound/soc/codecs/tlv320adc3xxx.c
sound/soc/codecs/wcd938x-sdw.c
sound/soc/codecs/wcd938x.c
sound/soc/codecs/wm8960.c
sound/soc/codecs/wm_adsp.c
sound/soc/dwc/dwc-i2s.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/pxa/pxa-ssp.c
sound/soc/sh/rcar/core.c
sound/soc/soc-component.c
sound/soc/soc-core.c
sound/soc/soc-dapm.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/soc/ti/ams-delta.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/arch/x86/include/uapi/asm/unistd_32.h
tools/build/feature/test-llvm.cpp [new file with mode: 0644]
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/rwsem.h [new file with mode: 0644]
tools/include/linux/seq_file.h
tools/include/nolibc/arch-i386.h
tools/include/nolibc/crt.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/net/ynl/generated/devlink-user.c
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/dlfilters/dlfilter-test-api-v0.c
tools/perf/dlfilters/dlfilter-test-api-v2.c
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/dlfilter.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_helpers.h
tools/testing/selftests/bpf/prog_tests/tc_links.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/timer.c
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/progs/timer_failure.c [new file with mode: 0644]
tools/testing/selftests/bpf/test_verifier.c
tools/testing/selftests/fchmodat2/Makefile
tools/testing/selftests/ftrace/test.d/kprobe/kprobe_non_uniq_symbol.tc [new file with mode: 0644]
tools/testing/selftests/kvm/Makefile
tools/testing/selftests/kvm/include/ucall_common.h
tools/testing/selftests/kvm/include/x86_64/processor.h
tools/testing/selftests/kvm/lib/guest_sprintf.c
tools/testing/selftests/kvm/lib/x86_64/apic.c
tools/testing/selftests/kvm/memslot_perf_test.c
tools/testing/selftests/kvm/riscv/get-reg-list.c
tools/testing/selftests/kvm/x86_64/hwcr_msr_test.c [new file with mode: 0644]
tools/testing/selftests/kvm/x86_64/hyperv_svm_test.c
tools/testing/selftests/kvm/x86_64/nx_huge_pages_test.c
tools/testing/selftests/kvm/x86_64/nx_huge_pages_test.sh
tools/testing/selftests/kvm/x86_64/state_test.c
tools/testing/selftests/kvm/x86_64/tsc_scaling_sync.c
tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c
tools/testing/selftests/mm/charge_reserved_hugetlb.sh
tools/testing/selftests/mm/hugetlb_reparenting_test.sh
tools/testing/selftests/mm/mremap_dontunmap.c
tools/testing/selftests/net/Makefile
tools/testing/selftests/net/fib_tests.sh
tools/testing/selftests/net/hsr/hsr_ping.sh
tools/testing/selftests/net/mptcp/mptcp_join.sh
tools/testing/selftests/net/netns-name.sh [new file with mode: 0755]
tools/testing/selftests/net/openvswitch/openvswitch.sh
tools/testing/selftests/net/openvswitch/ovs-dpctl.py
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/riscv/mm/Makefile
tools/testing/selftests/riscv/mm/mmap_bottomup.c [moved from tools/testing/selftests/riscv/mm/testcases/mmap_bottomup.c with 97% similarity]
tools/testing/selftests/riscv/mm/mmap_default.c [moved from tools/testing/selftests/riscv/mm/testcases/mmap_default.c with 97% similarity]
tools/testing/selftests/riscv/mm/mmap_test.h [moved from tools/testing/selftests/riscv/mm/testcases/mmap_test.h with 100% similarity]
tools/testing/selftests/riscv/mm/run_mmap.sh [moved from tools/testing/selftests/riscv/mm/testcases/run_mmap.sh with 100% similarity]
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
tools/virtio/linux/dma-mapping.h

index a0a6efe871869348ae181c58c846e3ebc01d90a5..2643b7203a745283d7f0e655f22966939e5ba3a4 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -87,6 +87,7 @@ Baolin Wang <baolin.wang@linux.alibaba.com> <baolin.wang@unisoc.com>
 Baolin Wang <baolin.wang@linux.alibaba.com> <baolin.wang7@gmail.com>
 Bart Van Assche <bvanassche@acm.org> <bart.vanassche@sandisk.com>
 Bart Van Assche <bvanassche@acm.org> <bart.vanassche@wdc.com>
+Bartosz Golaszewski <brgl@bgdev.pl> <bgolaszewski@baylibre.com>
 Ben Dooks <ben-linux@fluff.org> <ben.dooks@simtec.co.uk>
 Ben Dooks <ben-linux@fluff.org> <ben.dooks@sifive.com>
 Ben Gardner <bgardner@wabtec.com>
@@ -377,6 +378,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>
@@ -449,9 +451,10 @@ Oleksandr Natalenko <oleksandr@natalenko.name> <oleksandr@redhat.com>
 Oleksij Rempel <linux@rempel-privat.de> <bug-track@fisher-privat.net>
 Oleksij Rempel <linux@rempel-privat.de> <external.Oleksij.Rempel@de.bosch.com>
 Oleksij Rempel <linux@rempel-privat.de> <fixed-term.Oleksij.Rempel@de.bosch.com>
-Oleksij Rempel <linux@rempel-privat.de> <o.rempel@pengutronix.de>
-Oleksij Rempel <linux@rempel-privat.de> <ore@pengutronix.de>
+Oleksij Rempel <o.rempel@pengutronix.de>
+Oleksij Rempel <o.rempel@pengutronix.de> <ore@pengutronix.de>
 Oliver Upton <oliver.upton@linux.dev> <oupton@google.com>
+Ondřej Jirman <megi@xff.cz> <megous@megous.com>
 Oza Pawandeep <quic_poza@quicinc.com> <poza@codeaurora.org>
 Pali Rohár <pali@kernel.org> <pali.rohar@gmail.com>
 Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
index 978d3d5004005dcb1444c2f98b574cbd2b319088..fba87a55f3cafd263fbbe809e29833b802c4b69e 100644 (file)
@@ -1,7 +1,7 @@
 What:          /sys/class/firmware/.../data
 Date:          July 2022
 KernelVersion: 5.19
-Contact:       Russ Weight <russell.h.weight@intel.com>
+Contact:       Russ Weight <russ.weight@linux.dev>
 Description:   The data sysfs file is used for firmware-fallback and for
                firmware uploads. Cat a firmware image to this sysfs file
                after you echo 1 to the loading sysfs file. When the firmware
@@ -13,7 +13,7 @@ Description:  The data sysfs file is used for firmware-fallback and for
 What:          /sys/class/firmware/.../cancel
 Date:          July 2022
 KernelVersion: 5.19
-Contact:       Russ Weight <russell.h.weight@intel.com>
+Contact:       Russ Weight <russ.weight@linux.dev>
 Description:   Write-only. For firmware uploads, write a "1" to this file to
                request that the transfer of firmware data to the lower-level
                device be canceled. This request will be rejected (EBUSY) if
@@ -23,7 +23,7 @@ Description:  Write-only. For firmware uploads, write a "1" to this file to
 What:          /sys/class/firmware/.../error
 Date:          July 2022
 KernelVersion: 5.19
-Contact:       Russ Weight <russell.h.weight@intel.com>
+Contact:       Russ Weight <russ.weight@linux.dev>
 Description:   Read-only. Returns a string describing a failed firmware
                upload. This string will be in the form of <STATUS>:<ERROR>,
                where <STATUS> will be one of the status strings described
@@ -37,7 +37,7 @@ Description:  Read-only. Returns a string describing a failed firmware
 What:          /sys/class/firmware/.../loading
 Date:          July 2022
 KernelVersion: 5.19
-Contact:       Russ Weight <russell.h.weight@intel.com>
+Contact:       Russ Weight <russ.weight@linux.dev>
 Description:   The loading sysfs file is used for both firmware-fallback and
                for firmware uploads. Echo 1 onto the loading file to indicate
                you are writing a firmware file to the data sysfs node. Echo
@@ -49,7 +49,7 @@ Description:  The loading sysfs file is used for both firmware-fallback and
 What:          /sys/class/firmware/.../remaining_size
 Date:          July 2022
 KernelVersion: 5.19
-Contact:       Russ Weight <russell.h.weight@intel.com>
+Contact:       Russ Weight <russ.weight@linux.dev>
 Description:   Read-only. For firmware upload, this file contains the size
                of the firmware data that remains to be transferred to the
                lower-level device driver. The size value is initialized to
@@ -62,7 +62,7 @@ Description:  Read-only. For firmware upload, this file contains the size
 What:          /sys/class/firmware/.../status
 Date:          July 2022
 KernelVersion: 5.19
-Contact:       Russ Weight <russell.h.weight@intel.com>
+Contact:       Russ Weight <russ.weight@linux.dev>
 Description:   Read-only. Returns a string describing the current status of
                a firmware upload. The string will be one of the following:
                idle, "receiving", "preparing", "transferring", "programming".
@@ -70,7 +70,7 @@ Description:  Read-only. Returns a string describing the current status of
 What:          /sys/class/firmware/.../timeout
 Date:          July 2022
 KernelVersion: 5.19
-Contact:       Russ Weight <russell.h.weight@intel.com>
+Contact:       Russ Weight <russ.weight@linux.dev>
 Description:   This file supports the timeout mechanism for firmware
                fallback.  This file has no affect on firmware uploads. For
                more information on timeouts please see the documentation
index 0a41afe0ab4cbe9c915fc8a16268738da0aad411..9051695d221170bd82c4e84aa9fda49bf80ad1bf 100644 (file)
@@ -1,7 +1,7 @@
 What:          /sys/bus/platform/drivers/intel-m10bmc-sec-update/.../security/sr_root_entry_hash
 Date:          Sep 2022
 KernelVersion: 5.20
-Contact:       Russ Weight <russell.h.weight@intel.com>
+Contact:       Peter Colberg <peter.colberg@intel.com>
 Description:   Read only. Returns the root entry hash for the static
                region if one is programmed, else it returns the
                string: "hash not programmed".  This file is only
@@ -11,7 +11,7 @@ Description:  Read only. Returns the root entry hash for the static
 What:          /sys/bus/platform/drivers/intel-m10bmc-sec-update/.../security/pr_root_entry_hash
 Date:          Sep 2022
 KernelVersion: 5.20
-Contact:       Russ Weight <russell.h.weight@intel.com>
+Contact:       Peter Colberg <peter.colberg@intel.com>
 Description:   Read only. Returns the root entry hash for the partial
                reconfiguration region if one is programmed, else it
                returns the string: "hash not programmed".  This file
@@ -21,7 +21,7 @@ Description:  Read only. Returns the root entry hash for the partial
 What:          /sys/bus/platform/drivers/intel-m10bmc-sec-update/.../security/bmc_root_entry_hash
 Date:          Sep 2022
 KernelVersion: 5.20
-Contact:       Russ Weight <russell.h.weight@intel.com>
+Contact:       Peter Colberg <peter.colberg@intel.com>
 Description:   Read only. Returns the root entry hash for the BMC image
                if one is programmed, else it returns the string:
                "hash not programmed".  This file is only visible if the
@@ -31,7 +31,7 @@ Description:  Read only. Returns the root entry hash for the BMC image
 What:          /sys/bus/platform/drivers/intel-m10bmc-sec-update/.../security/sr_canceled_csks
 Date:          Sep 2022
 KernelVersion: 5.20
-Contact:       Russ Weight <russell.h.weight@intel.com>
+Contact:       Peter Colberg <peter.colberg@intel.com>
 Description:   Read only. Returns a list of indices for canceled code
                signing keys for the static region. The standard bitmap
                list format is used (e.g. "1,2-6,9").
@@ -39,7 +39,7 @@ Description:  Read only. Returns a list of indices for canceled code
 What:          /sys/bus/platform/drivers/intel-m10bmc-sec-update/.../security/pr_canceled_csks
 Date:          Sep 2022
 KernelVersion: 5.20
-Contact:       Russ Weight <russell.h.weight@intel.com>
+Contact:       Peter Colberg <peter.colberg@intel.com>
 Description:   Read only. Returns a list of indices for canceled code
                signing keys for the partial reconfiguration region. The
                standard bitmap list format is used (e.g. "1,2-6,9").
@@ -47,7 +47,7 @@ Description:  Read only. Returns a list of indices for canceled code
 What:          /sys/bus/platform/drivers/intel-m10bmc-sec-update/.../security/bmc_canceled_csks
 Date:          Sep 2022
 KernelVersion: 5.20
-Contact:       Russ Weight <russell.h.weight@intel.com>
+Contact:       Peter Colberg <peter.colberg@intel.com>
 Description:   Read only. Returns a list of indices for canceled code
                signing keys for the BMC.  The standard bitmap list format
                is used (e.g. "1,2-6,9").
@@ -55,7 +55,7 @@ Description:  Read only. Returns a list of indices for canceled code
 What:          /sys/bus/platform/drivers/intel-m10bmc-sec-update/.../security/flash_count
 Date:          Sep 2022
 KernelVersion: 5.20
-Contact:       Russ Weight <russell.h.weight@intel.com>
+Contact:       Peter Colberg <peter.colberg@intel.com>
 Description:   Read only. Returns number of times the secure update
                staging area has been flashed.
                Format: "%u".
index 5f502bf68fbcd2622f1547fc23a2113e590eb976..ff456871bf4b8b74a7e74bea664e0e6fa5e3910b 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 4e4625f2455fe92552365fc1c088d497bdef5a55..de6d8a4790e2b6cd06f69fe5ebe72eb69c23cb3d 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 8c8addb4194c93446936e60af3b9e7c744e75575..76ff9d7398fda74afd576f6f6734688cb111eb20 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 e96f057ea2a07ed396301938ed0bdefbe6df21b5..f47f63bcf67c91b5b401ff25019aeb170e12a95f 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 49135d451ced9a0b9fa5c54a7d52d82880521b32..8c568cfc2107984092f4d82c2076a3bed0c05c4f 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 5d7b01aed1fe630e7a1b508ae40f3e02d8c687a4..0046af06531a6e6ed4ad98b66474a46706f5d1a7 100644 (file)
@@ -244,7 +244,7 @@ unbound worker-pools and only one work item could be active at any given
 time thus achieving the same ordering property as ST wq.
 
 In the current implementation the above configuration only guarantees
-ST behavior within a given NUMA node. Instead ``alloc_ordered_queue()`` should
+ST behavior within a given NUMA node. Instead ``alloc_ordered_workqueue()`` should
 be used to achieve system-wide ST behavior.
 
 
@@ -390,7 +390,7 @@ The default affinity scope can be changed with the module parameter
 scope can be changed using ``apply_workqueue_attrs()``.
 
 If ``WQ_SYSFS`` is set, the workqueue will have the following affinity scope
-related interface files under its ``/sys/devices/virtual/WQ_NAME/``
+related interface files under its ``/sys/devices/virtual/workqueue/WQ_NAME/``
 directory.
 
 ``affinity_scope``
index 337ddf1113c4d60c8f6b7b394cacf09d4667cd54..4e867dd4d402b2689da486e97eb9729268625ed4 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 b568d0ce438d2117e776c91061bd250647dcd6c3..7e1ffc551046535b8f4b4e11f2a1c4c121e35027 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 9ab5f0c435d4df1638d1819a5c6379fdf270dba9..d2cbe49f4e15fdc4791c70ae3eaf2589c43bcce7 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 839648e753d4fed700498e2d861d77757d97dd8d..42b6f80613f3cde11c298a2633dde856493fc866 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 af7fe9c4d1963b6cd3789236c4cfe1c2ef4b09ca..7979cf07f119978e903c6ea21674f92d85dfd502 100644 (file)
@@ -87,7 +87,7 @@ required:
   - interrupts
   - ports
 
-additionalProperties: false
+unevaluatedProperties: false
 
 examples:
   - |
index 23ada8f87526a7be1b424a2f0ae9aeac33ede692..769ce23aaac27518cfad1bc8eaed4da280580013 100644 (file)
@@ -13,6 +13,8 @@ description: |
 
 maintainers:
   - Michael Tretter <m.tretter@pengutronix.de>
+  - Harini Katakam <harini.katakam@amd.com>
+  - Radhey Shyam Pandey <radhey.shyam.pandey@amd.com>
 
 allOf:
   - $ref: ../dma-controller.yaml#
@@ -65,6 +67,7 @@ required:
   - interrupts
   - clocks
   - clock-names
+  - xlnx,bus-width
 
 additionalProperties: false
 
index 21ae7bce038ec2b212de6de5c0445aa0edb0120e..171a41407241908959f2ac647a28b4c2f45b4ce1 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 7cc4ddc4e9b714e56d51b1a86db5cc360cabca75..2aa1f4b063ebdf6a64e7080a0a8774f67c9d0860 100644 (file)
@@ -61,7 +61,7 @@ patternProperties:
     required:
       - reg
 
-    additionalProperties: true
+    additionalProperties: false
 
 allOf:
   - $ref: /schemas/spi/spi-peripheral-props.yaml#
index 2594fa192f93d0d298cc3a9e7171a584e78b756d..2a04906531fb0ea254a121ee0595130298f11a73 100644 (file)
@@ -32,7 +32,8 @@ properties:
 
   spi-cpol: true
 
-  reset-gpios: true
+  reset-gpios:
+    maxItems: 1
 
   interrupts:
     minItems: 1
index 4e508bfcc9d87e46e5c5fb3c561304fba2acba41..5121685337b5ed090d0a266ce8bc5154280f8ed3 100644 (file)
@@ -78,7 +78,8 @@ properties:
           - const: -1000
           - const: 22000
 
-  reset-gpios: true
+  reset-gpios:
+    maxItems: 1
 
   adi,dc-dc-ilim-microamp:
     enum: [150000, 200000, 250000, 300000, 350000, 400000]
index b9b5beac33b2e926f1610257a115f19870145cb6..5b6cde86b5a5cbda886b576e49e762d6be02e837 100644 (file)
@@ -23,7 +23,8 @@ properties:
     maxItems: 1
     description: Connected to ADC_RDY pin.
 
-  reset-gpios: true
+  reset-gpios:
+    maxItems: 1
 
 required:
   - compatible
index 2958c4ca75b4851c06d4521a9c6b166f2ded0c54..167d10bd60af973a73403925456736b223783670 100644 (file)
@@ -23,7 +23,8 @@ properties:
     maxItems: 1
     description: Connected to ADC_RDY pin.
 
-  reset-gpios: true
+  reset-gpios:
+    maxItems: 1
 
 additionalProperties: false
 
index 8376d64a641aa647b918fdcb1a54d2bc9e2d7dd2..bed42d5d0d94c9c7d6b3f331dda935cff8073131 100644 (file)
@@ -45,5 +45,6 @@ examples:
       light-sensor@38 {
         compatible = "rohm,bu27010";
         reg = <0x38>;
+        vdd-supply = <&vdd>;
       };
     };
index 2bc38479a41ed50c0357209b67b88d3a42a136f0..0f4a062c9d6fe32259d9349ec4fab4e08f77a5dd 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 95033cb514fbd8f63ead74c0db7a5eada84cd056..b417341fc8ae049b91dc715fcb7c619e407fd923 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 33b90e975e33cde70730611424f386ebce47fcf0..2ef3081eaaf36aa653cdf52fd0de9ab918a418c4 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 cf29ab10501cbcbc7da2022c302376d69c8756c8..b1b2cf81b42fc1cf2db849fabceb159e368c7ce5 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 ffccf5f3c9e34a7fca06b49d96ee4a9b13071d75..642f9b15d3597738e33fd7e5a51636e69d5fe8ae 100644 (file)
@@ -54,6 +54,7 @@ properties:
 
   port:
     $ref: /schemas/graph.yaml#/$defs/port-base
+    unevaluatedProperties: false
 
     properties:
       endpoint:
index c5cab549ee8eafb1c03203f70c2c3fb20f24e043..1c476b635b690865cff0882578d72b1db2dc7c50 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 358019e85d90781e5001170572727f3f9bba4655..326284e151f66e937420af948f58b04df081f1e5 100644 (file)
@@ -59,7 +59,6 @@ allOf:
         compatible:
           contains:
             enum:
-              - fsl,imx8mq-csi
               - fsl,imx8mm-csi
     then:
       required:
index 324703bfb1bded3ad28ded83202b8f5293935dbb..5539d0f8e74d2e827cd78ccf1860de2f770e9c51 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 79ff6d83a9fd684c41f5dcd1e758876942fd66d5..b3486c38a05b9ef7cbbcd485fed90f9fd0741670 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 9804d13de648ceed131f15076bcbc50a8792c719..6a6f222b868ffa06e606e2bd4062efa5d319a6ec 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 80141eb7fc6bed58e820303561512f8104d25984..10f34aa8ba8ae53c15f18a9633b2522235a8e6d2 100644 (file)
@@ -69,7 +69,7 @@ properties:
     maxItems: 4
 
   clocks:
-    minItems: 3
+    minItems: 2
     items:
       - description: Main peripheral bus clock, PCLK/HCLK - AHB Bus clock
       - description: SDC MMC clock, MCLK
index 0972868735fca7522ec629f5a0dbb6c6af55c664..0e07ab61a48d28954f278acb2ac05d430b492ff7 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 5073007267ad440a682fb1f32cf4f60a49d7abfd..634cec5d57ea85b89ba9cafe01ebba3dd5f7c584 100644 (file)
@@ -70,7 +70,7 @@ examples:
 
     phy@84000 {
         compatible = "qcom,ipq6018-qmp-pcie-phy";
-        reg = <0x0 0x00084000 0x0 0x1000>;
+        reg = <0x00084000 0x1000>;
 
         clocks = <&gcc GCC_PCIE0_AUX_CLK>,
                  <&gcc GCC_PCIE0_AHB_CLK>,
index 38c0b5213736a463626ab7b1ad69f69e218c0605..97e8441eda1c2bf63f4321115a28c7cfd57e1c71 100644 (file)
@@ -91,6 +91,7 @@ properties:
 
   interrupt-controller:
     type: object
+    additionalProperties: false
     description: Describes the CPU's local interrupt controller
 
     properties:
index cc1f546fdbdcbaf5103b485517725e68cd1032e3..c91ab0e46648204e906982dedf999f90cc72a58f 100644 (file)
@@ -128,6 +128,12 @@ properties:
             changes to interrupts as frozen at commit ccbddab ("Merge pull
             request #42 from riscv/jhauser-2023-RC4") of riscv-aia.
 
+        - const: smstateen
+          description: |
+            The standard Smstateen extension for controlling access to CSRs
+            added by other RISC-V extensions in H/S/VS/U/VU modes and as
+            ratified at commit a28bfae (Ratified (#7)) of riscv-state-enable.
+
         - const: ssaia
           description: |
             The standard Ssaia supervisor-level extension for the advanced
@@ -212,6 +218,12 @@ properties:
             ratified in the 20191213 version of the unprivileged ISA
             specification.
 
+        - const: zicond
+          description:
+            The standard Zicond extension for conditional arithmetic and
+            conditional-select/move operations as ratified in commit 95cf1f9
+            ("Add changes requested by Ved during signoff") of riscv-zicond.
+
         - const: zicsr
           description: |
             The standard Zicsr extension for control and status register
index da2dcfeebf12ebc8839e30b026774e2c99277ffb..510f6cb0f084f8c8c46a51440fb10126f56acc12 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 7a6de938b11d10c76feab94d14ec8fa69402c002..4118aa54bbd55384da10e9e6debef8ae5c86bd67 100644 (file)
@@ -82,7 +82,7 @@ properties:
     description:
       Current at which the headset micbias sense clamp will engage, 0 to
       disable.
-    enum: [ 0, 14, 23, 41, 50, 60, 68, 86, 95 ]
+    enum: [ 0, 14, 24, 43, 52, 61, 71, 90, 99 ]
     default: 0
 
   cirrus,bias-ramp-ms:
index 4b99a18c79a0762aa468b1ff8a78b6184f5c82ad..b7e60583563918001b8333b7e473a15a8ddca172 100644 (file)
@@ -56,6 +56,9 @@ properties:
       - const: clkext3
     minItems: 2
 
+  "#sound-dai-cells":
+    const: 0
+
 required:
   - compatible
   - reg
index 4f51b2fa82dbda32ea92c2c27492ce9ae56fca05..c3c989ef2a2c81eba73fae3d1ee4bfd18a8e5d29 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 2f593c7225e5aa8a76c3681771d11a9f10687477..14cac0e6e0a189e2133dd4a8b3247148da920617 100644 (file)
@@ -22,6 +22,13 @@ properties:
       - const: fsl,imx35-cspi
       - 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
index cd58179ae3379ee3f4dd6d3d6bd97d44c9f7de57..430a814f64a5678ed1e8ab4f7d01626cde69cc8a 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 4654ee57c1d5e4ef5d59d9b34cea5651434c5b34..f200d78744952825790e105f8903c44d1601e02e 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 cdefbe73d85c8a04261839a287badac3253b47cb..5b93268e400f4c78e3adf20210574cc840aa6b96 100644 (file)
@@ -339,6 +339,18 @@ The specified lower directories will be stacked beginning from the
 rightmost one and going left.  In the above example lower1 will be the
 top, lower2 the middle and lower3 the bottom layer.
 
+Note: directory names containing colons can be provided as lower layer by
+escaping the colons with a single backslash.  For example:
+
+  mount -t overlay overlay -olowerdir=/a\:lower\:\:dir /merged
+
+Since kernel version v6.5, directory names containing colons can also
+be provided as lower layer using the fsconfig syscall from new mount api:
+
+  fsconfig(fs_fd, FSCONFIG_SET_STRING, "lowerdir", "/a:lower::dir", 0);
+
+In the latter case, colons in lower layer directory names will be escaped
+as an octal characters (\072) when displayed in /proc/self/mountinfo.
 
 Metadata only copy up
 ---------------------
index deac4e973ddc12d326ee9e6874ed90456206f5db..4d05b9862451ea8237c583b5f276b1834ee4adb9 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 858ed5d80defeaf2dc2ec8afaeefa260321315ac..0135905c0aa352f2d83747cc407080d0973d9bd8 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 d1ebcd927149734cb60fec08c18ed18431271b96..065661acb878f94332478471b59c290842039ff4 100644 (file)
@@ -323,7 +323,7 @@ operations:
             - dev-name
             - sb-index
         reply: &sb-get-reply
-          value: 11
+          value: 13
           attributes: *sb-id-attrs
       dump:
         request:
@@ -350,7 +350,7 @@ operations:
             - sb-index
             - sb-pool-index
         reply: &sb-pool-get-reply
-          value: 15
+          value: 17
           attributes: *sb-pool-id-attrs
       dump:
         request:
@@ -378,7 +378,7 @@ operations:
             - sb-index
             - sb-pool-index
         reply: &sb-port-pool-get-reply
-          value: 19
+          value: 21
           attributes: *sb-port-pool-id-attrs
       dump:
         request:
@@ -407,7 +407,7 @@ operations:
             - sb-pool-type
             - sb-tc-index
         reply: &sb-tc-pool-bind-get-reply
-          value: 23
+          value: 25
           attributes: *sb-tc-pool-bind-id-attrs
       dump:
         request:
@@ -538,7 +538,7 @@ operations:
             - dev-name
             - trap-name
         reply: &trap-get-reply
-          value: 61
+          value: 63
           attributes: *trap-id-attrs
       dump:
         request:
@@ -564,7 +564,7 @@ operations:
             - dev-name
             - trap-group-name
         reply: &trap-group-get-reply
-          value: 65
+          value: 67
           attributes: *trap-group-id-attrs
       dump:
         request:
@@ -590,7 +590,7 @@ operations:
             - dev-name
             - trap-policer-id
         reply: &trap-policer-get-reply
-          value: 69
+          value: 71
           attributes: *trap-policer-id-attrs
       dump:
         request:
@@ -617,7 +617,7 @@ operations:
             - port-index
             - rate-node-name
         reply: &rate-get-reply
-          value: 74
+          value: 76
           attributes: *rate-id-attrs
       dump:
         request:
@@ -643,7 +643,7 @@ operations:
             - dev-name
             - linecard-index
         reply: &linecard-get-reply
-          value: 78
+          value: 80
           attributes: *linecard-id-attrs
       dump:
         request:
index f060cfb1445a38a6e0d81c68e5184815976b7fed..605e72c6c8771dbdd8085d89874b2a8bb1008005 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 ee1f5cd54496e93f933133a10bd01c766aee9ca6..decb39c19b9ed23c2af7b1b8457285e250a15d56 100644 (file)
@@ -162,9 +162,11 @@ How are representors identified?
 The representor netdevice should *not* directly refer to a PCIe device (e.g.
 through ``net_dev->dev.parent`` / ``SET_NETDEV_DEV()``), either of the
 representee or of the switchdev function.
-Instead, it should implement the ``ndo_get_devlink_port()`` netdevice op, which
-the kernel uses to provide the ``phys_switch_id`` and ``phys_port_name`` sysfs
-nodes.  (Some legacy drivers implement ``ndo_get_port_parent_id()`` and
+Instead, the driver should use the ``SET_NETDEV_DEVLINK_PORT`` macro to
+assign a devlink port instance to the netdevice before registering the
+netdevice; the kernel uses the devlink port to provide the ``phys_switch_id``
+and ``phys_port_name`` sysfs nodes.
+(Some legacy drivers implement ``ndo_get_port_parent_id()`` and
 ``ndo_get_phys_port_name()`` directly, but this is deprecated.)  See
 :ref:`Documentation/networking/devlink/devlink-port.rst <devlink_port>` for the
 details of this API.
index ac7c52f130c9b30978267fdd9d92994f01878260..31000f075707305aa7ea64eccecd51dada42e6ec 100644 (file)
@@ -25,15 +25,15 @@ Contact
 The Linux kernel hardware security team is separate from the regular Linux
 kernel security team.
 
-The team only handles the coordination of embargoed hardware security
-issues.  Reports of pure software security bugs in the Linux kernel are not
+The team only handles developing fixes for embargoed hardware security
+issues. Reports of pure software security bugs in the Linux kernel are not
 handled by this team and the reporter will be guided to contact the regular
 Linux kernel security team (:ref:`Documentation/admin-guide/
 <securitybugs>`) instead.
 
 The team can be contacted by email at <hardware-security@kernel.org>. This
-is a private list of security officers who will help you to coordinate an
-issue according to our documented process.
+is a private list of security officers who will help you to coordinate a
+fix according to our documented process.
 
 The list is encrypted and email to the list can be sent by either PGP or
 S/MIME encrypted and must be signed with the reporter's PGP key or S/MIME
@@ -132,11 +132,11 @@ other hardware could be affected.
 
 The hardware security team will provide an incident-specific encrypted
 mailing-list which will be used for initial discussion with the reporter,
-further disclosure and coordination.
+further disclosure, and coordination of fixes.
 
 The hardware security team will provide the disclosing party a list of
 developers (domain experts) who should be informed initially about the
-issue after confirming with the developers  that they will adhere to this
+issue after confirming with the developers that they will adhere to this
 Memorandum of Understanding and the documented process. These developers
 form the initial response team and will be responsible for handling the
 issue after initial contact. The hardware security team is supporting the
@@ -209,13 +209,18 @@ five work days this is taken as silent acknowledgement.
 After acknowledgement or resolution of an objection the expert is disclosed
 by the incident team and brought into the development process.
 
+List participants may not communicate about the issue outside of the
+private mailing list. List participants may not use any shared resources
+(e.g. employer build farms, CI systems, etc) when working on patches.
+
 
 Coordinated release
 """""""""""""""""""
 
 The involved parties will negotiate the date and time where the embargo
 ends. At that point the prepared mitigations are integrated into the
-relevant kernel trees and published.
+relevant kernel trees and published. There is no pre-notification process:
+fixes are published in public and available to everyone at the same time.
 
 While we understand that hardware security issues need coordinated embargo
 time, the embargo time should be constrained to the minimum time which is
index 49029ee82e559e543cf583021b4c3053d8852fcb..081397827a7eab66bb45648bf0e9e9f67497125e 100644 (file)
@@ -29,7 +29,7 @@ target with the same invocation used for compilation, e.g.::
 
 To read the docs locally in your web browser, run e.g.::
 
-       xdg-open rust/doc/kernel/index.html
+       xdg-open Documentation/output/rust/rustdoc/kernel/index.html
 
 To learn about how to write the documentation, please see coding-guidelines.rst.
 
index 45987f256b976312644e94522f5565fbf062e255..086487ca7ab11905a8374437d31f12c29f84a402 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 057db78d4095a1135a66968fdb6c7a2f18846848..03b7f3deb0698fa622121c2c6a2b6a8fec49d967 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 7a895514b53794415901c6452169d379bdded30d..196f52386aaa8f3334c85367d5ea400e9fbb511e 100644 (file)
@@ -91,9 +91,9 @@ The prototype of the entry/exit callback function are as follows:
 
 .. code-block:: c
 
- int entry_callback(struct fprobe *fp, unsigned long entry_ip, struct pt_regs *regs, void *entry_data);
+ int entry_callback(struct fprobe *fp, unsigned long entry_ip, unsigned long ret_ip, struct pt_regs *regs, void *entry_data);
 
- void exit_callback(struct fprobe *fp, unsigned long entry_ip, struct pt_regs *regs, void *entry_data);
+ void exit_callback(struct fprobe *fp, unsigned long entry_ip, unsigned long ret_ip, struct pt_regs *regs, void *entry_data);
 
 Note that the @entry_ip is saved at function entry and passed to exit handler.
 If the entry callback function returns !0, the corresponding exit callback will be cancelled.
@@ -108,6 +108,10 @@ If the entry callback function returns !0, the corresponding exit callback will
         Note that this may not be the actual entry address of the function but
         the address where the ftrace is instrumented.
 
+@ret_ip
+        This is the return address that the traced function will return to,
+        somewhere in the caller. This can be used at both entry and exit.
+
 @regs
         This is the `pt_regs` data structure at the entry and exit. Note that
         the instruction pointer of @regs may be different from the @entry_ip
index cba04befc9509f8942eb1e2b1aadc2f80fe17034..59d6bf33050cb831236321d91eab7bbf313655ea 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 6c1b5ec31d75e15cc42501e3ca7a127c922d81e1..7fac6f75d0782062f3f11c342068e9f13e90f2ad 100644 (file)
@@ -202,7 +202,7 @@ workqueue将自动创建与属性相匹配的后备工作者池。调节并发
 同的排序属性。
 
 在目前的实现中,上述配置只保证了特定NUMA节点内的ST行为。相反,
-``alloc_ordered_queue()`` 应该被用来实现全系统的ST行为。
+``alloc_ordered_workqueue()`` 应该被用来实现全系统的ST行为。
 
 
 执行场景示例
index 21a7578142a18b4ad537acbd654ba510dd16fc9f..e81ab4e171e4c3e4e848ae1788876f1b940fb926 100644 (file)
@@ -416,6 +416,13 @@ Reads the general purpose registers from the vcpu.
        __u64 pc;
   };
 
+  /* LoongArch */
+  struct kvm_regs {
+       /* out (KVM_GET_REGS) / in (KVM_SET_REGS) */
+       unsigned long gpr[32];
+       unsigned long pc;
+  };
+
 
 4.12 KVM_SET_REGS
 -----------------
@@ -506,7 +513,7 @@ translation mode.
 ------------------
 
 :Capability: basic
-:Architectures: x86, ppc, mips, riscv
+:Architectures: x86, ppc, mips, riscv, loongarch
 :Type: vcpu ioctl
 :Parameters: struct kvm_interrupt (in)
 :Returns: 0 on success, negative on failure.
@@ -540,7 +547,7 @@ ioctl is useful if the in-kernel PIC is not used.
 PPC:
 ^^^^
 
-Queues an external interrupt to be injected. This ioctl is overleaded
+Queues an external interrupt to be injected. This ioctl is overloaded
 with 3 different irq values:
 
 a) KVM_INTERRUPT_SET
@@ -592,6 +599,14 @@ b) KVM_INTERRUPT_UNSET
 
 This is an asynchronous vcpu ioctl and can be invoked from any thread.
 
+LOONGARCH:
+^^^^^^^^^^
+
+Queues an external interrupt to be injected into the virtual CPU. A negative
+interrupt number dequeues the interrupt.
+
+This is an asynchronous vcpu ioctl and can be invoked from any thread.
+
 
 4.17 KVM_DEBUG_GUEST
 --------------------
@@ -737,7 +752,7 @@ signal mask.
 ----------------
 
 :Capability: basic
-:Architectures: x86
+:Architectures: x86, loongarch
 :Type: vcpu ioctl
 :Parameters: struct kvm_fpu (out)
 :Returns: 0 on success, -1 on error
@@ -746,7 +761,7 @@ Reads the floating point state from the vcpu.
 
 ::
 
-  /* for KVM_GET_FPU and KVM_SET_FPU */
+  /* x86: for KVM_GET_FPU and KVM_SET_FPU */
   struct kvm_fpu {
        __u8  fpr[8][16];
        __u16 fcw;
@@ -761,12 +776,21 @@ Reads the floating point state from the vcpu.
        __u32 pad2;
   };
 
+  /* LoongArch: for KVM_GET_FPU and KVM_SET_FPU */
+  struct kvm_fpu {
+       __u32 fcsr;
+       __u64 fcc;
+       struct kvm_fpureg {
+               __u64 val64[4];
+       }fpr[32];
+  };
+
 
 4.23 KVM_SET_FPU
 ----------------
 
 :Capability: basic
-:Architectures: x86
+:Architectures: x86, loongarch
 :Type: vcpu ioctl
 :Parameters: struct kvm_fpu (in)
 :Returns: 0 on success, -1 on error
@@ -775,7 +799,7 @@ Writes the floating point state to the vcpu.
 
 ::
 
-  /* for KVM_GET_FPU and KVM_SET_FPU */
+  /* x86: for KVM_GET_FPU and KVM_SET_FPU */
   struct kvm_fpu {
        __u8  fpr[8][16];
        __u16 fcw;
@@ -790,6 +814,15 @@ Writes the floating point state to the vcpu.
        __u32 pad2;
   };
 
+  /* LoongArch: for KVM_GET_FPU and KVM_SET_FPU */
+  struct kvm_fpu {
+       __u32 fcsr;
+       __u64 fcc;
+       struct kvm_fpureg {
+               __u64 val64[4];
+       }fpr[32];
+  };
+
 
 4.24 KVM_CREATE_IRQCHIP
 -----------------------
@@ -965,7 +998,7 @@ be set in the flags field of this ioctl:
 The KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL flag requests KVM to generate
 the contents of the hypercall page automatically; hypercalls will be
 intercepted and passed to userspace through KVM_EXIT_XEN.  In this
-ase, all of the blob size and address fields must be zero.
+case, all of the blob size and address fields must be zero.
 
 The KVM_XEN_HVM_CONFIG_EVTCHN_SEND flag indicates to KVM that userspace
 will always use the KVM_XEN_HVM_EVTCHN_SEND ioctl to deliver event
@@ -1070,7 +1103,7 @@ Other flags returned by ``KVM_GET_CLOCK`` are accepted but ignored.
 :Extended by: KVM_CAP_INTR_SHADOW
 :Architectures: x86, arm64
 :Type: vcpu ioctl
-:Parameters: struct kvm_vcpu_event (out)
+:Parameters: struct kvm_vcpu_events (out)
 :Returns: 0 on success, -1 on error
 
 X86:
@@ -1193,7 +1226,7 @@ directly to the virtual CPU).
 :Extended by: KVM_CAP_INTR_SHADOW
 :Architectures: x86, arm64
 :Type: vcpu ioctl
-:Parameters: struct kvm_vcpu_event (in)
+:Parameters: struct kvm_vcpu_events (in)
 :Returns: 0 on success, -1 on error
 
 X86:
@@ -1387,7 +1420,7 @@ documentation when it pops into existence).
 -------------------
 
 :Capability: KVM_CAP_ENABLE_CAP
-:Architectures: mips, ppc, s390, x86
+:Architectures: mips, ppc, s390, x86, loongarch
 :Type: vcpu ioctl
 :Parameters: struct kvm_enable_cap (in)
 :Returns: 0 on success; -1 on error
@@ -1442,7 +1475,7 @@ for vm-wide capabilities.
 ---------------------
 
 :Capability: KVM_CAP_MP_STATE
-:Architectures: x86, s390, arm64, riscv
+:Architectures: x86, s390, arm64, riscv, loongarch
 :Type: vcpu ioctl
 :Parameters: struct kvm_mp_state (out)
 :Returns: 0 on success; -1 on error
@@ -1460,7 +1493,7 @@ Possible values are:
 
    ==========================    ===============================================
    KVM_MP_STATE_RUNNABLE         the vcpu is currently running
-                                 [x86,arm64,riscv]
+                                 [x86,arm64,riscv,loongarch]
    KVM_MP_STATE_UNINITIALIZED    the vcpu is an application processor (AP)
                                  which has not yet received an INIT signal [x86]
    KVM_MP_STATE_INIT_RECEIVED    the vcpu has received an INIT signal, and is
@@ -1516,11 +1549,14 @@ For riscv:
 The only states that are valid are KVM_MP_STATE_STOPPED and
 KVM_MP_STATE_RUNNABLE which reflect if the vcpu is paused or not.
 
+On LoongArch, only the KVM_MP_STATE_RUNNABLE state is used to reflect
+whether the vcpu is runnable.
+
 4.39 KVM_SET_MP_STATE
 ---------------------
 
 :Capability: KVM_CAP_MP_STATE
-:Architectures: x86, s390, arm64, riscv
+:Architectures: x86, s390, arm64, riscv, loongarch
 :Type: vcpu ioctl
 :Parameters: struct kvm_mp_state (in)
 :Returns: 0 on success; -1 on error
@@ -1538,6 +1574,9 @@ For arm64/riscv:
 The only states that are valid are KVM_MP_STATE_STOPPED and
 KVM_MP_STATE_RUNNABLE which reflect if the vcpu should be paused or not.
 
+On LoongArch, only the KVM_MP_STATE_RUNNABLE state is used to reflect
+whether the vcpu is runnable.
+
 4.40 KVM_SET_IDENTITY_MAP_ADDR
 ------------------------------
 
@@ -2841,6 +2880,19 @@ Following are the RISC-V D-extension registers:
   0x8020 0000 0600 0020 fcsr      Floating point control and status register
 ======================= ========= =============================================
 
+LoongArch registers are mapped using the lower 32 bits. The upper 16 bits of
+that is the register group type.
+
+LoongArch csr registers are used to control guest cpu or get status of guest
+cpu, and they have the following id bit patterns::
+
+  0x9030 0000 0001 00 <reg:5> <sel:3>   (64-bit)
+
+LoongArch KVM control registers are used to implement some new defined functions
+such as set vcpu counter or reset vcpu, and they have the following id bit patterns::
+
+  0x9030 0000 0002 <reg:16>
+
 
 4.69 KVM_GET_ONE_REG
 --------------------
@@ -3063,7 +3115,7 @@ as follow::
    };
 
 An entry with a "page_shift" of 0 is unused. Because the array is
-organized in increasing order, a lookup can stop when encoutering
+organized in increasing order, a lookup can stop when encountering
 such an entry.
 
 The "slb_enc" field provides the encoding to use in the SLB for the
@@ -3455,7 +3507,7 @@ Possible features:
              - KVM_RUN and KVM_GET_REG_LIST are not available;
 
              - KVM_GET_ONE_REG and KVM_SET_ONE_REG cannot be used to access
-               the scalable archietctural SVE registers
+               the scalable architectural SVE registers
                KVM_REG_ARM64_SVE_ZREG(), KVM_REG_ARM64_SVE_PREG() or
                KVM_REG_ARM64_SVE_FFR;
 
@@ -4401,7 +4453,7 @@ This will have undefined effects on the guest if it has not already
 placed itself in a quiescent state where no vcpu will make MMU enabled
 memory accesses.
 
-On succsful completion, the pending HPT will become the guest's active
+On successful completion, the pending HPT will become the guest's active
 HPT and the previous HPT will be discarded.
 
 On failure, the guest will still be operating on its previous HPT.
@@ -5016,7 +5068,7 @@ before the vcpu is fully usable.
 
 Between KVM_ARM_VCPU_INIT and KVM_ARM_VCPU_FINALIZE, the feature may be
 configured by use of ioctls such as KVM_SET_ONE_REG.  The exact configuration
-that should be performaned and how to do it are feature-dependent.
+that should be performed and how to do it are feature-dependent.
 
 Other calls that depend on a particular feature being finalized, such as
 KVM_RUN, KVM_GET_REG_LIST, KVM_GET_ONE_REG and KVM_SET_ONE_REG, will fail with
@@ -5124,6 +5176,24 @@ Valid values for 'action'::
   #define KVM_PMU_EVENT_ALLOW 0
   #define KVM_PMU_EVENT_DENY 1
 
+Via this API, KVM userspace can also control the behavior of the VM's fixed
+counters (if any) by configuring the "action" and "fixed_counter_bitmap" fields.
+
+Specifically, KVM follows the following pseudo-code when determining whether to
+allow the guest FixCtr[i] to count its pre-defined fixed event::
+
+  FixCtr[i]_is_allowed = (action == ALLOW) && (bitmap & BIT(i)) ||
+    (action == DENY) && !(bitmap & BIT(i));
+  FixCtr[i]_is_denied = !FixCtr[i]_is_allowed;
+
+KVM always consumes fixed_counter_bitmap, it's userspace's responsibility to
+ensure fixed_counter_bitmap is set correctly, e.g. if userspace wants to define
+a filter that only affects general purpose counters.
+
+Note, the "events" field also applies to fixed counters' hardcoded event_select
+and unit_mask values.  "fixed_counter_bitmap" has higher priority than "events"
+if there is a contradiction between the two.
+
 4.121 KVM_PPC_SVM_OFF
 ---------------------
 
@@ -5475,7 +5545,7 @@ KVM_XEN_ATTR_TYPE_EVTCHN
   from the guest. A given sending port number may be directed back to
   a specified vCPU (by APIC ID) / port / priority on the guest, or to
   trigger events on an eventfd. The vCPU and priority can be changed
-  by setting KVM_XEN_EVTCHN_UPDATE in a subsequent call, but but other
+  by setting KVM_XEN_EVTCHN_UPDATE in a subsequent call, but other
   fields cannot change for a given sending port. A port mapping is
   removed by using KVM_XEN_EVTCHN_DEASSIGN in the flags field. Passing
   KVM_XEN_EVTCHN_RESET in the flags field removes all interception of
index d47595b33fcf19fe366c88c61361527aa3dd6fe3..2b3b6d442302b756f397360eb445a6d1a0f9c76b 100644 (file)
@@ -202,10 +202,22 @@ Shadow pages contain the following information:
     Is 1 if the MMU instance cannot use A/D bits.  EPT did not have A/D
     bits before Haswell; shadow EPT page tables also cannot use A/D bits
     if the L1 hypervisor does not enable them.
+  role.guest_mode:
+    Indicates the shadow page is created for a nested guest.
   role.passthrough:
     The page is not backed by a guest page table, but its first entry
     points to one.  This is set if NPT uses 5-level page tables (host
     CR4.LA57=1) and is shadowing L1's 4-level NPT (L1 CR4.LA57=0).
+  mmu_valid_gen:
+    The MMU generation of this page, used to fast zap of all MMU pages within a
+    VM without blocking vCPUs too long. Specifically, KVM updates the per-VM
+    valid MMU generation which causes the mismatch of mmu_valid_gen for each mmu
+    page. This makes all existing MMU pages obsolete. Obsolete pages can't be
+    used. Therefore, vCPUs must load a new, valid root before re-entering the
+    guest. The MMU generation is only ever '0' or '1'. Note, the TDP MMU doesn't
+    use this field as non-root TDP MMU pages are reachable only from their
+    owning root. Thus it suffices for TDP MMU to use role.invalid in root pages
+    to invalidate all MMU pages.
   gfn:
     Either the guest page table containing the translations shadowed by this
     page, or the base page frame for linear translations.  See role.direct.
@@ -219,21 +231,30 @@ Shadow pages contain the following information:
     at __pa(sp2->spt).  sp2 will point back at sp1 through parent_pte.
     The spt array forms a DAG structure with the shadow page as a node, and
     guest pages as leaves.
-  gfns:
-    An array of 512 guest frame numbers, one for each present pte.  Used to
-    perform a reverse map from a pte to a gfn. When role.direct is set, any
-    element of this array can be calculated from the gfn field when used, in
-    this case, the array of gfns is not allocated. See role.direct and gfn.
-  root_count:
-    A counter keeping track of how many hardware registers (guest cr3 or
-    pdptrs) are now pointing at the page.  While this counter is nonzero, the
-    page cannot be destroyed.  See role.invalid.
+  shadowed_translation:
+    An array of 512 shadow translation entries, one for each present pte. Used
+    to perform a reverse map from a pte to a gfn as well as its access
+    permission. When role.direct is set, the shadow_translation array is not
+    allocated. This is because the gfn contained in any element of this array
+    can be calculated from the gfn field when used.  In addition, when
+    role.direct is set, KVM does not track access permission for each of the
+    gfn. See role.direct and gfn.
+  root_count / tdp_mmu_root_count:
+     root_count is a reference counter for root shadow pages in Shadow MMU.
+     vCPUs elevate the refcount when getting a shadow page that will be used as
+     a root page, i.e. page that will be loaded into hardware directly (CR3,
+     PDPTRs, nCR3 EPTP). Root pages cannot be destroyed while their refcount is
+     non-zero. See role.invalid. tdp_mmu_root_count is similar but exclusively
+     used in TDP MMU as an atomic refcount.
   parent_ptes:
     The reverse mapping for the pte/ptes pointing at this page's spt. If
     parent_ptes bit 0 is zero, only one spte points at this page and
     parent_ptes points at this single spte, otherwise, there exists multiple
     sptes pointing at this page and (parent_ptes & ~0x1) points at a data
     structure with a list of parent sptes.
+  ptep:
+    The kernel virtual address of the SPTE that points at this shadow page.
+    Used exclusively by the TDP MMU, this field is a union with parent_ptes.
   unsync:
     If true, then the translations in this page may not match the guest's
     translation.  This is equivalent to the state of the tlb when a pte is
@@ -261,6 +282,10 @@ Shadow pages contain the following information:
     since the last time the page table was actually used; if emulation
     is triggered too frequently on this page, KVM will unmap the page
     to avoid emulation in the future.
+  tdp_mmu_page:
+    Is 1 if the shadow page is a TDP MMU page. This variable is used to
+    bifurcate the control flows for KVM when walking any data structure that
+    may contain pages from both TDP MMU and shadow MMU.
 
 Reverse map
 ===========
index bf0f54c24f81714b64a6b5a4169c12fc62bd63a1..7038e6671212dc8ba4e9f88a12fe0d3a062ca317 100644 (file)
@@ -378,8 +378,9 @@ F:  drivers/acpi/viot.c
 F:     include/linux/acpi_viot.h
 
 ACPI WMI DRIVER
+M:     Armin Wolf <W_Armin@gmx.de>
 L:     platform-driver-x86@vger.kernel.org
-S:     Orphan
+S:     Maintained
 F:     Documentation/driver-api/wmi.rst
 F:     Documentation/wmi/
 F:     drivers/platform/x86/wmi.c
@@ -470,7 +471,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 +1585,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 +1673,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 +1974,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/
@@ -2211,21 +2222,28 @@ F:      arch/arm/boot/dts/ti/omap/omap3-igep*
 ARM/INTEL IXP4XX ARM ARCHITECTURE
 M:     Linus Walleij <linusw@kernel.org>
 M:     Imre Kaloz <kaloz@openwrt.org>
-M:     Krzysztof Halasa <khalasa@piap.pl>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 F:     Documentation/devicetree/bindings/arm/intel-ixp4xx.yaml
 F:     Documentation/devicetree/bindings/gpio/intel,ixp4xx-gpio.txt
 F:     Documentation/devicetree/bindings/interrupt-controller/intel,ixp4xx-interrupt.yaml
 F:     Documentation/devicetree/bindings/memory-controllers/intel,ixp4xx-expansion*
+F:     Documentation/devicetree/bindings/rng/intel,ixp46x-rng.yaml
 F:     Documentation/devicetree/bindings/timer/intel,ixp4xx-timer.yaml
 F:     arch/arm/boot/dts/intel/ixp/
 F:     arch/arm/mach-ixp4xx/
 F:     drivers/bus/intel-ixp4xx-eb.c
+F:     drivers/char/hw_random/ixp4xx-rng.c
 F:     drivers/clocksource/timer-ixp4xx.c
 F:     drivers/crypto/intel/ixp4xx/ixp4xx_crypto.c
 F:     drivers/gpio/gpio-ixp4xx.c
 F:     drivers/irqchip/irq-ixp4xx.c
+F:     drivers/net/ethernet/xscale/ixp4xx_eth.c
+F:     drivers/net/wan/ixp4xx_hss.c
+F:     drivers/soc/ixp4xx/ixp4xx-npe.c
+F:     drivers/soc/ixp4xx/ixp4xx-qmgr.c
+F:     include/linux/soc/ixp4xx/npe.h
+F:     include/linux/soc/ixp4xx/qmgr.h
 
 ARM/INTEL KEEMBAY ARCHITECTURE
 M:     Paul J. Murphy <paul.j.murphy@intel.com>
@@ -2327,7 +2345,7 @@ F:        drivers/rtc/rtc-mt7622.c
 
 ARM/Mediatek SoC support
 M:     Matthias Brugger <matthias.bgg@gmail.com>
-R:     AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+M:     AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
 L:     linux-kernel@vger.kernel.org
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 L:     linux-mediatek@lists.infradead.org (moderated for non-subscribers)
@@ -3058,7 +3076,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 +3093,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 +3362,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 +4100,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 +6003,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 +6663,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
@@ -6748,7 +6766,7 @@ F:        drivers/gpu/drm/panel/panel-sitronix-st7701.c
 DRM DRIVER FOR SITRONIX ST7703 PANELS
 M:     Guido Günther <agx@sigxcpu.org>
 R:     Purism Kernel Team <kernel@puri.sm>
-R:     Ondrej Jirman <megous@megous.com>
+R:     Ondrej Jirman <megi@xff.cz>
 S:     Maintained
 F:     Documentation/devicetree/bindings/display/panel/rocktech,jh057n00900.yaml
 F:     drivers/gpu/drm/panel/panel-sitronix-st7703.c
@@ -8093,7 +8111,7 @@ F:        include/linux/arm_ffa.h
 
 FIRMWARE LOADER (request_firmware)
 M:     Luis Chamberlain <mcgrof@kernel.org>
-M:     Russ Weight <russell.h.weight@intel.com>
+M:     Russ Weight <russ.weight@linux.dev>
 L:     linux-kernel@vger.kernel.org
 S:     Maintained
 F:     Documentation/firmware_class/
@@ -8874,7 +8892,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 +9549,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
@@ -10622,22 +10638,6 @@ L:     linux-crypto@vger.kernel.org
 S:     Maintained
 F:     drivers/crypto/intel/ixp4xx/ixp4xx_crypto.c
 
-INTEL IXP4XX QMGR, NPE, ETHERNET and HSS SUPPORT
-M:     Krzysztof Halasa <khalasa@piap.pl>
-S:     Maintained
-F:     drivers/net/ethernet/xscale/ixp4xx_eth.c
-F:     drivers/net/wan/ixp4xx_hss.c
-F:     drivers/soc/ixp4xx/ixp4xx-npe.c
-F:     drivers/soc/ixp4xx/ixp4xx-qmgr.c
-F:     include/linux/soc/ixp4xx/npe.h
-F:     include/linux/soc/ixp4xx/qmgr.h
-
-INTEL IXP4XX RANDOM NUMBER GENERATOR SUPPORT
-M:     Deepak Saxena <dsaxena@plexity.net>
-S:     Maintained
-F:     Documentation/devicetree/bindings/rng/intel,ixp46x-rng.yaml
-F:     drivers/char/hw_random/ixp4xx-rng.c
-
 INTEL KEEM BAY DRM DRIVER
 M:     Anitha Chrisanthus <anitha.chrisanthus@intel.com>
 M:     Edmund Dea <edmund.j.dea@intel.com>
@@ -10701,7 +10701,7 @@ F:      drivers/mfd/intel-m10-bmc*
 F:     include/linux/mfd/intel-m10-bmc.h
 
 INTEL MAX10 BMC SECURE UPDATES
-M:     Russ Weight <russell.h.weight@intel.com>
+M:     Peter Colberg <peter.colberg@intel.com>
 L:     linux-fpga@vger.kernel.org
 S:     Maintained
 F:     Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-sec-update
@@ -11063,7 +11063,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 +11082,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
@@ -11523,6 +11522,18 @@ F:     include/kvm/arm_*
 F:     tools/testing/selftests/kvm/*/aarch64/
 F:     tools/testing/selftests/kvm/aarch64/
 
+KERNEL VIRTUAL MACHINE FOR LOONGARCH (KVM/LoongArch)
+M:     Tianrui Zhao <zhaotianrui@loongson.cn>
+M:     Bibo Mao <maobibo@loongson.cn>
+M:     Huacai Chen <chenhuacai@kernel.org>
+L:     kvm@vger.kernel.org
+L:     loongarch@lists.linux.dev
+S:     Maintained
+T:     git git://git.kernel.org/pub/scm/virt/kvm/kvm.git
+F:     arch/loongarch/include/asm/kvm*
+F:     arch/loongarch/include/uapi/asm/kvm*
+F:     arch/loongarch/kvm/
+
 KERNEL VIRTUAL MACHINE FOR MIPS (KVM/mips)
 M:     Huacai Chen <chenhuacai@kernel.org>
 L:     linux-mips@vger.kernel.org
@@ -11559,6 +11570,7 @@ F:      arch/riscv/include/asm/kvm*
 F:     arch/riscv/include/uapi/asm/kvm*
 F:     arch/riscv/kvm/
 F:     tools/testing/selftests/kvm/*/riscv/
+F:     tools/testing/selftests/kvm/riscv/
 
 KERNEL VIRTUAL MACHINE for s390 (KVM/s390)
 M:     Christian Borntraeger <borntraeger@linux.ibm.com>
@@ -13616,6 +13628,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
@@ -13846,9 +13859,10 @@ F:     Documentation/devicetree/bindings/media/amlogic,gx-vdec.yaml
 F:     drivers/staging/media/meson/vdec/
 
 METHODE UDPU SUPPORT
-M:     Vladimir Vid <vladimir.vid@sartura.hr>
+M:     Robert Marko <robert.marko@sartura.hr>
 S:     Maintained
-F:     arch/arm64/boot/dts/marvell/armada-3720-uDPU.dts
+F:     arch/arm64/boot/dts/marvell/armada-3720-eDPU.dts
+F:     arch/arm64/boot/dts/marvell/armada-3720-uDPU.*
 
 MHI BUS
 M:     Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
@@ -14210,6 +14224,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 +14771,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 +14960,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
@@ -15130,7 +15145,7 @@ NOLIBC HEADER FILE
 M:     Willy Tarreau <w@1wt.eu>
 M:     Thomas Weißschuh <linux@weissschuh.net>
 S:     Maintained
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/wtarreau/nolibc.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/nolibc/linux-nolibc.git
 F:     tools/include/nolibc/
 F:     tools/testing/selftests/nolibc/
 
@@ -17600,6 +17615,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 +18146,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 +18621,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 +18673,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 +18680,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
@@ -20488,6 +20499,7 @@ F:      include/dt-bindings/clock/starfive?jh71*.h
 STARFIVE JH71X0 PINCTRL DRIVERS
 M:     Emil Renner Berthing <kernel@esmil.dk>
 M:     Jianlong Huang <jianlong.huang@starfivetech.com>
+M:     Hal Feng <hal.feng@starfivetech.com>
 L:     linux-gpio@vger.kernel.org
 S:     Maintained
 F:     Documentation/devicetree/bindings/pinctrl/starfive,jh71*.yaml
@@ -21656,7 +21668,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 +23434,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 57698d048e2caa0d5d9c437cb091156072093015..5c418efbe89b6ca12a9f6a916035a87dd64513ac 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
 VERSION = 6
 PATCHLEVEL = 6
 SUBLEVEL = 0
-EXTRAVERSION = -rc2
+EXTRAVERSION =
 NAME = Hurr durr I'ma ninja sloth
 
 # *DOCUMENTATION*
@@ -1474,7 +1474,7 @@ endif # CONFIG_MODULES
 # Directories & files removed with 'make clean'
 CLEAN_FILES += vmlinux.symvers modules-only.symvers \
               modules.builtin modules.builtin.modinfo modules.nsdeps \
-              compile_commands.json .thinlto-cache rust/test rust/doc \
+              compile_commands.json .thinlto-cache rust/test \
               rust-project.json .vmlinux.objs .vmlinux.export.c
 
 # Directories & files removed with 'make mrproper'
index b63bd4ad3143c5467e315e2830c109d535fc49ef..88a4b0d6d928d4c2e0636a2a026bfec645129338 100644 (file)
@@ -64,7 +64,8 @@
                compatible = "arm,armv7-timer";
                interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
                             <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
-                            <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
+                            <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
+                            <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
                arm,cpu-registers-not-fw-configured;
                clock-frequency = <24000000>;
        };
                compatible = "rockchip,rk3128-timer", "rockchip,rk3288-timer";
                reg = <0x20044000 0x20>;
                interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
-               clocks = <&cru PCLK_TIMER>, <&xin24m>;
+               clocks = <&cru PCLK_TIMER>, <&cru SCLK_TIMER0>;
                clock-names = "pclk", "timer";
        };
 
                compatible = "rockchip,rk3128-timer", "rockchip,rk3288-timer";
                reg = <0x20044020 0x20>;
                interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
-               clocks = <&cru PCLK_TIMER>, <&xin24m>;
+               clocks = <&cru PCLK_TIMER>, <&cru SCLK_TIMER1>;
                clock-names = "pclk", "timer";
        };
 
                compatible = "rockchip,rk3128-timer", "rockchip,rk3288-timer";
                reg = <0x20044040 0x20>;
                interrupts = <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>;
-               clocks = <&cru PCLK_TIMER>, <&xin24m>;
+               clocks = <&cru PCLK_TIMER>, <&cru SCLK_TIMER2>;
                clock-names = "pclk", "timer";
        };
 
                compatible = "rockchip,rk3128-timer", "rockchip,rk3288-timer";
                reg = <0x20044060 0x20>;
                interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
-               clocks = <&cru PCLK_TIMER>, <&xin24m>;
+               clocks = <&cru PCLK_TIMER>, <&cru SCLK_TIMER3>;
                clock-names = "pclk", "timer";
        };
 
                compatible = "rockchip,rk3128-timer", "rockchip,rk3288-timer";
                reg = <0x20044080 0x20>;
                interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>;
-               clocks = <&cru PCLK_TIMER>, <&xin24m>;
+               clocks = <&cru PCLK_TIMER>, <&cru SCLK_TIMER4>;
                clock-names = "pclk", "timer";
        };
 
                compatible = "rockchip,rk3128-timer", "rockchip,rk3288-timer";
                reg = <0x200440a0 0x20>;
                interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
-               clocks = <&cru PCLK_TIMER>, <&xin24m>;
+               clocks = <&cru PCLK_TIMER>, <&cru SCLK_TIMER5>;
                clock-names = "pclk", "timer";
        };
 
 
        i2c0: i2c@20072000 {
                compatible = "rockchip,rk3128-i2c", "rockchip,rk3288-i2c";
-               reg = <20072000 0x1000>;
+               reg = <0x20072000 0x1000>;
                interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
                clock-names = "i2c";
                clocks = <&cru PCLK_I2C0>;
                interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
                             <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>;
                arm,pl330-broken-no-flushp;
+               arm,pl330-periph-burst;
                clocks = <&cru ACLK_DMAC>;
                clock-names = "apb_pclk";
                #dma-cells = <1>;
index 091ba310053ebc6fb99424c136b7794efc4721b4..d2d516d113baa7a33b3dba06ccede72623369e80 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 0da759f8e2c2df351c44a7c3f4e87ef5a6a6fcf0..7dd2340bc5e4556a9c840209a1695ccc2279a024 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 801b4f10350c126c53baa248cd4699cdde6f7bcd..d484ec1e4fd86b7c8f28a0de47942fcb3bafe439 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 7ae8b620515c5418140f9e779df2e46031f9dace..59f546a278f87c013e8cbb74ba6dd8607e65ddcb 100644 (file)
                                reg = <0x0 0xff>, /* MPU private access */
                                      <0x49022000 0xff>; /* L3 Interconnect */
                                reg-names = "mpu", "dma";
+                               clocks = <&abe_clkctrl OMAP4_MCBSP1_CLKCTRL 24>;
+                               clock-names = "fck";
                                interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
                                interrupt-names = "common";
                                ti,buffer-size = <128>;
                                reg = <0x0 0xff>, /* MPU private access */
                                      <0x49024000 0xff>; /* L3 Interconnect */
                                reg-names = "mpu", "dma";
+                               clocks = <&abe_clkctrl OMAP4_MCBSP2_CLKCTRL 24>;
+                               clock-names = "fck";
                                interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
                                interrupt-names = "common";
                                ti,buffer-size = <128>;
                                reg = <0x0 0xff>, /* MPU private access */
                                      <0x49026000 0xff>; /* L3 Interconnect */
                                reg-names = "mpu", "dma";
+                               clocks = <&abe_clkctrl OMAP4_MCBSP3_CLKCTRL 24>;
+                               clock-names = "fck";
                                interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
                                interrupt-names = "common";
                                ti,buffer-size = <128>;
index 46b8f9efd41316bde4c2f74473e95e1af3183ffe..3fcef3080eaec8180f245eadc12b2560fc1b4976 100644 (file)
                                compatible = "ti,omap4-mcbsp";
                                reg = <0x0 0xff>; /* L4 Interconnect */
                                reg-names = "mpu";
+                               clocks = <&l4_per_clkctrl OMAP4_MCBSP4_CLKCTRL 24>;
+                               clock-names = "fck";
                                interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
                                interrupt-names = "common";
                                ti,buffer-size = <128>;
index 238aceb799f89584c5d527e869e090ed0e781f5d..2104170fe2cd7080b683c362f36693249bcefb43 100644 (file)
@@ -69,6 +69,7 @@
 };
 
 &cpu_thermal {
+       thermal-sensors = <&bandgap>;
        coefficients = <0 20000>;
 };
 
index 1b27a862ae810a5e7100e7632f66e324e6c3655e..a6764750d4476c0910a6eddf5c47268a0daebaba 100644 (file)
@@ -79,6 +79,7 @@
 };
 
 &cpu_thermal {
+       thermal-sensors = <&bandgap>;
        coefficients = <348 (-9301)>;
 };
 
index a03bca5a358441c5977f1f8ae3ef697aac1caea2..97b0c3b5f573f7a4ee45d1c18e43aa84a170525b 100644 (file)
                                reg = <0x0 0xff>, /* MPU private access */
                                      <0x49022000 0xff>; /* L3 Interconnect */
                                reg-names = "mpu", "dma";
+                               clocks = <&abe_clkctrl OMAP5_MCBSP1_CLKCTRL 24>;
+                               clock-names = "fck";
                                interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
                                interrupt-names = "common";
                                ti,buffer-size = <128>;
                                reg = <0x0 0xff>, /* MPU private access */
                                      <0x49024000 0xff>; /* L3 Interconnect */
                                reg-names = "mpu", "dma";
+                               clocks = <&abe_clkctrl OMAP5_MCBSP2_CLKCTRL 24>;
+                               clock-names = "fck";
                                interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
                                interrupt-names = "common";
                                ti,buffer-size = <128>;
                                reg = <0x0 0xff>, /* MPU private access */
                                      <0x49026000 0xff>; /* L3 Interconnect */
                                reg-names = "mpu", "dma";
+                               clocks = <&abe_clkctrl OMAP5_MCBSP3_CLKCTRL 24>;
+                               clock-names = "fck";
                                interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
                                interrupt-names = "common";
                                ti,buffer-size = <128>;
index 246a3de25931db6d65259933fee7d50169a81f2f..aaaedafef7cce6ce0caefc726cf229aa510e15c2 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 9808cd27e2cf9359108ee6df0c1d63052ce52dd9..67de96c7717db12ba3a119750d3f89528630bf79 100644 (file)
@@ -550,6 +550,7 @@ static struct platform_device *ams_delta_devices[] __initdata = {
        &ams_delta_nand_device,
        &ams_delta_lcd_device,
        &cx20442_codec_device,
+       &modem_nreset_device,
 };
 
 static struct gpiod_lookup_table *ams_delta_gpio_tables[] __initdata = {
@@ -782,26 +783,28 @@ static struct plat_serial8250_port ams_delta_modem_ports[] = {
        { },
 };
 
+static int ams_delta_modem_pm_activate(struct device *dev)
+{
+       modem_priv.regulator = regulator_get(dev, "RESET#");
+       if (IS_ERR(modem_priv.regulator))
+               return -EPROBE_DEFER;
+
+       return 0;
+}
+
+static struct dev_pm_domain ams_delta_modem_pm_domain = {
+       .activate       = ams_delta_modem_pm_activate,
+};
+
 static struct platform_device ams_delta_modem_device = {
        .name   = "serial8250",
        .id     = PLAT8250_DEV_PLATFORM1,
        .dev            = {
                .platform_data = ams_delta_modem_ports,
+               .pm_domain = &ams_delta_modem_pm_domain,
        },
 };
 
-static int __init modem_nreset_init(void)
-{
-       int err;
-
-       err = platform_device_register(&modem_nreset_device);
-       if (err)
-               pr_err("Couldn't register the modem regulator device\n");
-
-       return err;
-}
-
-
 /*
  * This function expects MODEM IRQ number already assigned to the port.
  * The MODEM device requires its RESET# pin kept high during probe.
@@ -833,37 +836,6 @@ static int __init ams_delta_modem_init(void)
 }
 arch_initcall_sync(ams_delta_modem_init);
 
-static int __init late_init(void)
-{
-       int err;
-
-       err = modem_nreset_init();
-       if (err)
-               return err;
-
-       /*
-        * Once the modem device is registered, the modem_nreset
-        * regulator can be requested on behalf of that device.
-        */
-       modem_priv.regulator = regulator_get(&ams_delta_modem_device.dev,
-                       "RESET#");
-       if (IS_ERR(modem_priv.regulator)) {
-               err = PTR_ERR(modem_priv.regulator);
-               goto unregister;
-       }
-       return 0;
-
-unregister:
-       platform_device_unregister(&ams_delta_modem_device);
-       return err;
-}
-
-static void __init ams_delta_init_late(void)
-{
-       omap1_init_late();
-       late_init();
-}
-
 static void __init ams_delta_map_io(void)
 {
        omap1_map_io();
@@ -877,7 +849,7 @@ MACHINE_START(AMS_DELTA, "Amstrad E3 (Delta)")
        .init_early     = omap1_init_early,
        .init_irq       = omap1_init_irq,
        .init_machine   = ams_delta_init,
-       .init_late      = ams_delta_init_late,
+       .init_late      = omap1_init_late,
        .init_time      = omap1_timer_init,
        .restart        = omap1_restart,
 MACHINE_END
index 410d17d1d4431e248dadd5143fab115969fef316..f618a6df29382bc0828b27a9ef83d7c19a9c151e 100644 (file)
@@ -176,17 +176,18 @@ static u64 notrace omap_32k_read_sched_clock(void)
        return sync32k_cnt_reg ? readl_relaxed(sync32k_cnt_reg) : 0;
 }
 
+static struct timespec64 persistent_ts;
+static cycles_t cycles;
+static unsigned int persistent_mult, persistent_shift;
+
 /**
  * omap_read_persistent_clock64 -  Return time from a persistent clock.
+ * @ts: &struct timespec64 for the returned time
  *
  * Reads the time from a source which isn't disabled during PM, the
  * 32k sync timer.  Convert the cycles elapsed since last read into
  * nsecs and adds to a monotonically increasing timespec64.
  */
-static struct timespec64 persistent_ts;
-static cycles_t cycles;
-static unsigned int persistent_mult, persistent_shift;
-
 static void omap_read_persistent_clock64(struct timespec64 *ts)
 {
        unsigned long long nsecs;
@@ -206,10 +207,9 @@ static void omap_read_persistent_clock64(struct timespec64 *ts)
 /**
  * omap_init_clocksource_32k - setup and register counter 32k as a
  * kernel clocksource
- * @pbase: base addr of counter_32k module
- * @size: size of counter_32k to map
+ * @vbase: base addr of counter_32k module
  *
- * Returns 0 upon success or negative error code upon failure.
+ * Returns: %0 upon success or negative error code upon failure.
  *
  */
 static int __init omap_init_clocksource_32k(void __iomem *vbase)
index 1e17b5f775889b9b06002ac06ea3eee4396065d1..ba71928c0fcb7b9d8b348a1c85fdfdcbf9325383 100644 (file)
@@ -2209,7 +2209,7 @@ int omap_hwmod_parse_module_range(struct omap_hwmod *oh,
                return err;
 
        pr_debug("omap_hwmod: %s %pOFn at %pR\n",
-                oh->name, np, &res);
+                oh->name, np, res);
 
        if (oh && oh->mpu_rt_idx) {
                omap_hwmod_fix_mpu_rt_idx(oh, np, res);
index f57802f3ee3adc62d234f91e0c6d771a8c0c6195..37b168119fe43e2e960a4e6aea7b50c4a4c2d25c 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 b7bc23ffd3c696284d0d75423e747d7e3879f771..c95273c9567bb944c153c39417dbcf624c97fa3b 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 ff288145850432984ba116cc39bf79b2a7e2cea7..84a2f17ff32d09dd282ad12e0d8be5fe01510d70 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 7d59765aef220b429afdf7a8d3a2a6ec0923c0b2..c392e18f1e43178fd00a177033baba203e25e931 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 b10515c0200b4044cf37a98cbf83b743664c1b65..78f20e6327120ea439ebad77de7611eea59cca8d 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 c6872b7e9471d1aec3e0794abfe854a78a4078a0..89aee6c925760d2839cd99c446131b120827678b 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 e31ab8b4f54f3f626463f126ecede8824c284e81..a882c86ec3132b88479a13720ee7cb92cca7aac1 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 06e91297fb163b8a8488f3f2c0bf419bcf90ba5d..acd265d8b58ed9c8399d63794caacc1f229732d1 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 6f2f50e1639c372e2355b41611b54a703355e380..83d907294fbc73ede28c54672ed05d96c9a8ff2d 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 1c71c08becde8a939b22c35d51a8212321569220..f6e422dc2663e99702e3a305d7213e6547aa79e5 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 6f85a05ee7e1a0d9b3f7ee3ecc0b1be9ff0c286b..dcf6e4846ac9def75627e3e428ae481c385818da 100644 (file)
                        #size-cells = <1>;
                        ranges;
 
-                       anomix_ns_gpr: syscon@44210000 {
+                       aonmix_ns_gpr: syscon@44210000 {
                                compatible = "fsl,imx93-aonmix-ns-syscfg", "syscon";
                                reg = <0x44210000 0x1000>;
                        };
                                assigned-clock-parents = <&clk IMX93_CLK_SYS_PLL_PFD1_DIV2>;
                                assigned-clock-rates = <40000000>;
                                fsl,clk-source = /bits/ 8 <0>;
+                               fsl,stop-mode = <&aonmix_ns_gpr 0x14 0>;
                                status = "disabled";
                        };
 
                                assigned-clock-parents = <&clk IMX93_CLK_SYS_PLL_PFD1_DIV2>;
                                assigned-clock-rates = <40000000>;
                                fsl,clk-source = /bits/ 8 <0>;
+                               fsl,stop-mode = <&wakeupmix_gpr 0x0c 2>;
                                status = "disabled";
                        };
 
index 36ef2dbe8add484ea9d3ba0fbb294376d77a9215..3ee9266fa8e985cedcd4177f04dfdff8a4b689f4 100644 (file)
                status = "disabled";
        };
 
-       sata_phy: t-phy@1a243000 {
+       sata_phy: t-phy {
                compatible = "mediatek,mt7622-tphy",
                             "mediatek,generic-tphy-v1";
                #address-cells = <2>;
index 68539ea788dfcce5e52cb996693de7766607e05e..24eda00e320d3a8873a702966f8b674b737425a3 100644 (file)
                        };
                };
 
-               pcie_phy: t-phy@11c00000 {
+               pcie_phy: t-phy {
                        compatible = "mediatek,mt7986-tphy",
                                     "mediatek,generic-tphy-v2";
                        #address-cells = <2>;
index b2485ddfd33bbdae83b1a37d2d0edd60a7570d18..5d635085fe3fd0cc6534dd0bd045bbf8642de59b 100644 (file)
@@ -48,7 +48,7 @@
 
        memory@40000000 {
                device_type = "memory";
-               reg = <0 0x40000000 0 0x80000000>;
+               reg = <0 0x40000000 0x2 0x00000000>;
        };
 
        reserved-memory {
                #size-cells = <2>;
                ranges;
 
-               /* 2 MiB reserved for ARM Trusted Firmware (BL31) */
-               bl31_secmon_reserved: secmon@54600000 {
-                       no-map;
-                       reg = <0 0x54600000 0x0 0x200000>;
-               };
-
-               /* 12 MiB reserved for OP-TEE (BL32)
+               /*
+                * 12 MiB reserved for OP-TEE (BL32)
                 * +-----------------------+ 0x43e0_0000
                 * |      SHMEM 2MiB       |
                 * +-----------------------+ 0x43c0_0000
                        no-map;
                        reg = <0 0x43200000 0 0x00c00000>;
                };
+
+               scp_mem: memory@50000000 {
+                       compatible = "shared-dma-pool";
+                       reg = <0 0x50000000 0 0x2900000>;
+                       no-map;
+               };
+
+               vpu_mem: memory@53000000 {
+                       compatible = "shared-dma-pool";
+                       reg = <0 0x53000000 0 0x1400000>; /* 20 MB */
+               };
+
+               /* 2 MiB reserved for ARM Trusted Firmware (BL31) */
+               bl31_secmon_mem: memory@54600000 {
+                       no-map;
+                       reg = <0 0x54600000 0x0 0x200000>;
+               };
+
+               snd_dma_mem: memory@60000000 {
+                       compatible = "shared-dma-pool";
+                       reg = <0 0x60000000 0 0x1100000>;
+                       no-map;
+               };
+
+               apu_mem: memory@62000000 {
+                       compatible = "shared-dma-pool";
+                       reg = <0 0x62000000 0 0x1400000>; /* 20 MB */
+               };
        };
 };
 
index 4dbbf8fdab75857d7a9f889c3222900331c81174..54c674c45b49a27c223b4240db452284f01f5f15 100644 (file)
                interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH 0>;
                cpus = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>,
                       <&cpu4>, <&cpu5>, <&cpu6>, <&cpu7>;
+               status = "fail";
        };
 
        dmic_codec: dmic-codec {
                        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 385b178314db9573eed3b6ea1f30838c853ebe3c..3067a4091a7afbd16bdfd764ff43f7e163308dd2 100644 (file)
                stdout-path = "serial0:115200n8";
        };
 
-       clocks {
-               divclk4: divclk4 {
-                       compatible = "fixed-clock";
-                       #clock-cells = <0>;
-                       clock-frequency = <32768>;
-                       clock-output-names = "divclk4";
+       div1_mclk: divclk1 {
+               compatible = "gpio-gate-clock";
+               pinctrl-0 = <&audio_mclk>;
+               pinctrl-names = "default";
+               clocks = <&rpmcc RPM_SMD_DIV_CLK1>;
+               #clock-cells = <0>;
+               enable-gpios = <&pm8994_gpios 15 0>;
+       };
 
-                       pinctrl-names = "default";
-                       pinctrl-0 = <&divclk4_pin_a>;
-               };
+       divclk4: divclk4 {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <32768>;
+               clock-output-names = "divclk4";
 
-               div1_mclk: divclk1 {
-                       compatible = "gpio-gate-clock";
-                       pinctrl-0 = <&audio_mclk>;
-                       pinctrl-names = "default";
-                       clocks = <&rpmcc RPM_SMD_DIV_CLK1>;
-                       #clock-cells = <0>;
-                       enable-gpios = <&pm8994_gpios 15 0>;
-               };
+               pinctrl-names = "default";
+               pinctrl-0 = <&divclk4_pin_a>;
        };
 
        gpio-keys {
index bcd2397eb373392188bbd5a6518d1a95953ee9d7..06f8ff624181fc1dde3fa825a86f15dee6249a9e 100644 (file)
 #include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
 
 / {
-       clocks {
-               divclk1_cdc: divclk1 {
-                       compatible = "gpio-gate-clock";
-                       clocks = <&rpmcc RPM_SMD_DIV_CLK1>;
-                       #clock-cells = <0>;
-                       enable-gpios = <&pm8994_gpios 15 GPIO_ACTIVE_HIGH>;
+       divclk1_cdc: divclk1 {
+               compatible = "gpio-gate-clock";
+               clocks = <&rpmcc RPM_SMD_DIV_CLK1>;
+               #clock-cells = <0>;
+               enable-gpios = <&pm8994_gpios 15 GPIO_ACTIVE_HIGH>;
 
-                       pinctrl-names = "default";
-                       pinctrl-0 = <&divclk1_default>;
-               };
+               pinctrl-names = "default";
+               pinctrl-0 = <&divclk1_default>;
+       };
 
-               divclk4: divclk4 {
-                       compatible = "fixed-clock";
-                       #clock-cells = <0>;
-                       clock-frequency = <32768>;
-                       clock-output-names = "divclk4";
+       divclk4: divclk4 {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <32768>;
+               clock-output-names = "divclk4";
 
-                       pinctrl-names = "default";
-                       pinctrl-0 = <&divclk4_pin_a>;
-               };
+               pinctrl-names = "default";
+               pinctrl-0 = <&divclk4_pin_a>;
        };
 
        gpio-keys {
index d1066edaea471d7ff012b9ddddfd8049622684c1..f8e9d90afab0005641e1666bbd0fbba3f3877d3a 100644 (file)
        qcom,pmic-id = <0x20009 0x2000a 0x00 0x00>;
        qcom,board-id = <31 0>;
 
-       clocks {
-               divclk2_haptics: divclk2 {
-                       compatible = "fixed-clock";
-                       #clock-cells = <0>;
-                       clock-frequency = <32768>;
-                       clock-output-names = "divclk2";
-
-                       pinctrl-names = "default";
-                       pinctrl-0 = <&divclk2_pin_a>;
-               };
+       divclk2_haptics: divclk2 {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <32768>;
+               clock-output-names = "divclk2";
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&divclk2_pin_a>;
        };
 };
 
index 3c3b6287cd274854252ea7e109d631dceddb5081..eaa43f022a65493e86d46970bdddab95c30285b3 100644 (file)
                        compatible = "qcom,pmm8654au-gpio", "qcom,spmi-gpio";
                        reg = <0x8800>;
                        gpio-controller;
-                       gpio-ranges = <&pmm8654au_2_gpios 0 0 12>;
+                       gpio-ranges = <&pmm8654au_1_gpios 0 0 12>;
                        #gpio-cells = <2>;
                        interrupt-controller;
                        #interrupt-cells = <2>;
index a7c3020a5de491bf8027f4789eab9d411c371781..06c53000bb74d47634a5460f2e18f244154e9f8a 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 08a3ad3e7ae9227429f4c89ed35ccce66ca2adc8..de0a1f2af983bee33e127f87e2cdba16b544e54c 100644 (file)
                simple-audio-card,format = "i2s";
                simple-audio-card,name = "Haikou,I2S-codec";
                simple-audio-card,mclk-fs = <512>;
+               simple-audio-card,frame-master = <&sgtl5000_codec>;
+               simple-audio-card,bitclock-master = <&sgtl5000_codec>;
 
-               simple-audio-card,codec {
-                       clocks = <&sgtl5000_clk>;
+               sgtl5000_codec: simple-audio-card,codec {
                        sound-dai = <&sgtl5000>;
+                       // Prevent the dai subsystem from overwriting the clock
+                       // frequency. We are using a fixed-frequency oscillator.
+                       system-clock-fixed;
                };
 
                simple-audio-card,cpu {
-                       bitclock-master;
-                       frame-master;
                        sound-dai = <&i2s0_8ch>;
                };
        };
index 7dccbe8a93930785ef782801f8109ae801923878..f2279aa6ca9e129120018508191c0c68a926f801 100644 (file)
 
 &i2s0 {
        pinctrl-0 = <&i2s0_2ch_bus>;
+       pinctrl-1 = <&i2s0_2ch_bus_bclk_off>;
        rockchip,capture-channels = <2>;
        rockchip,playback-channels = <2>;
        status = "okay";
index 9da0b6d77c8d2d61890dd0e58e18994836dfbfca..5bc2d4faeea6df18d529976f0fa43a9c73c5cad7 100644 (file)
                                        <4 RK_PA0 1 &pcfg_pull_none>;
                        };
 
+                       i2s0_2ch_bus_bclk_off: i2s0-2ch-bus-bclk-off {
+                               rockchip,pins =
+                                       <3 RK_PD0 RK_FUNC_GPIO &pcfg_pull_none>,
+                                       <3 RK_PD1 1 &pcfg_pull_none>,
+                                       <3 RK_PD2 1 &pcfg_pull_none>,
+                                       <3 RK_PD3 1 &pcfg_pull_none>,
+                                       <3 RK_PD7 1 &pcfg_pull_none>,
+                                       <4 RK_PA0 1 &pcfg_pull_none>;
+                       };
+
                        i2s0_8ch_bus: i2s0-8ch-bus {
                                rockchip,pins =
                                        <3 RK_PD0 1 &pcfg_pull_none>,
index 5315789f48682ae684e319361cecef5528a35aec..a789119e6483b50000e6a3a6a1aeff5fb6eabe6d 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 4d537d56eb847569d286f232186567ff253610ca..6792a1f83f2ad400c98efa360f91ae0e802b1c7c 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 96e50227f940ecbde381ccc422d9d8c1433e5e2c..5bba393760557d0b390ff39927de19d861af006d 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 5f6f84837a490375c8175626e3fec40057bb56d9..74d00feb62f03e7e2ea609be70a008989623bba4 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 f43a38ac17799d26317ab985daccd35978b2b2f3..2ddc33d93b13b28c39d84d4253150d32c61888bd 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 5882b2415596416403b8560fef9f3f540d9ed73a..1095c6647e9665267e6aa67bac2dd7bb11b091f1 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 be66e94a21bda37ff271ea7cd8204019f74b08aa..5706e74c55786a2f6498af9084c5dcab735f9218 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 b018ae12ff5f2cc288545fb43f51ebbca7624bca..444a73c2e63858cea758fb89c5d65b786bc6f5f3 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 6ad61de03d0a0c8a3dd1edf1952c28a12c97f2a0..a6030913cd58c44f1ce5cd7077fe61dac02c86db 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 6dcdae4d38cb5ab9a7aba4a2bcf83ec6b7262d48..a1e24228aaaa764f3f96a3780e60a3003694b22b 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 9ced1bf0c2b7824aef1a7285826a4c8978b35170..ee902ff2a50f808d23e3c4e88a970cca40271d17 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 6537f58b1a8cc026f087f4f73affe42e8f38873b..448b17080d3617cbf5d2fceec7e7fa62866760d4 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 0eea225fd09a7ad0ea2da29d13db7683a4a58497..a243934c5568bb0bffbc5e3b1828707a56aadad8 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 e92ec810d4494bac8ec83c7f23d0a360d9651493..0afd6136e2759cbe0773fc5a036577e7e9e09db2 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 9c52718ea7509a88ddbafa2eceef58b2e51615a6..13fd592228b188658bd25011b66fd0420ca44d66 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 c3f06fdef60998d51c985ee167949a4de9a840e5..dea3dc89234b023e919f6ca3d2866e8e1e9d5bb8 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 2517ef7c21cfc3532e86bce11d9ca7e01e902607..76ce150e7347e56e2f497e905c02dc28733e68e3 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 db125df9e08882284a6454c598d1823067dd0d38..642d71675ddb29de67beb7014520326fe378b51c 100644 (file)
@@ -15,9 +15,4 @@ DECLARE_PER_CPU(struct ia64_cpu, cpu_devices);
 
 DECLARE_PER_CPU(int, cpu_state);
 
-#ifdef CONFIG_HOTPLUG_CPU
-extern int arch_register_cpu(int num);
-extern void arch_unregister_cpu(int);
-#endif
-
 #endif /* _ASM_IA64_CPU_H_ */
index 15f6cfddcc080b47693f2b6212d4ca5fab6bf3e0..41e8fe55cd9845f2c0e285e5db888915705d9b0d 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 94a848b06f15a964c0a07575533d6ace844b7b0b..741863a187a661b8468fabbae5eb189c99b61c10 100644 (file)
@@ -59,7 +59,7 @@ void __ref arch_unregister_cpu(int num)
 }
 EXPORT_SYMBOL(arch_unregister_cpu);
 #else
-static int __init arch_register_cpu(int num)
+int __init arch_register_cpu(int num)
 {
        return register_cpu(&sysfs_cpus[num].cpu, num);
 }
index b01f5cdb27e03d778dfa400e370037c39cd7abed..beb8499dd8ed84330beecbcd61977df0aa3474f8 100644 (file)
@@ -3,5 +3,7 @@ obj-y += mm/
 obj-y += net/
 obj-y += vdso/
 
+obj-$(CONFIG_KVM) += kvm/
+
 # for cleaning
 subdir- += boot
index e14396a2ddcbfc6d6130b63dca258343a03f35cb..d889a0b97bc18f9b38cf93aaa60d86c38935fa5f 100644 (file)
@@ -129,6 +129,7 @@ config LOONGARCH
        select HAVE_KPROBES
        select HAVE_KPROBES_ON_FTRACE
        select HAVE_KRETPROBES
+       select HAVE_KVM
        select HAVE_MOD_ARCH_SPECIFIC
        select HAVE_NMI
        select HAVE_PCI
@@ -263,6 +264,9 @@ config AS_HAS_LASX_EXTENSION
 config AS_HAS_LBT_EXTENSION
        def_bool $(as-instr,movscr2gr \$a0$(comma)\$scr0)
 
+config AS_HAS_LVZ_EXTENSION
+       def_bool $(as-instr,hvcl 0)
+
 menu "Kernel type and options"
 
 source "kernel/Kconfig.hz"
@@ -676,3 +680,5 @@ source "kernel/power/Kconfig"
 source "drivers/acpi/Kconfig"
 
 endmenu
+
+source "arch/loongarch/kvm/Kconfig"
index a3b52aaa83b33634c5be146bc02d50589bf5f762..33795e4a5bd63292831d40dcb0cb8d35ed24d8ce 100644 (file)
@@ -66,6 +66,8 @@ CONFIG_EFI_ZBOOT=y
 CONFIG_EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER=y
 CONFIG_EFI_CAPSULE_LOADER=m
 CONFIG_EFI_TEST=m
+CONFIG_VIRTUALIZATION=y
+CONFIG_KVM=m
 CONFIG_JUMP_LABEL=y
 CONFIG_MODULES=y
 CONFIG_MODULE_FORCE_LOAD=y
index 5c9c03bdf91569154b9a449019e29b46049d5bef..b24437e28c6eda457b2be003b51ad3809600f7cc 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 7af0cebf28d73c5d3551eb10ecc36beb6b08d2d7..b9a4ab54285c114360c05f420b023121de44de79 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 71e1ed4165c80d8a753309fcb381b394dfa85665..008a88ead60d9a55a4a8ffb0640b53bff5a127ba 100644 (file)
@@ -65,6 +65,14 @@ enum reg2_op {
        revbd_op        = 0x0f,
        revh2w_op       = 0x10,
        revhd_op        = 0x11,
+       iocsrrdb_op     = 0x19200,
+       iocsrrdh_op     = 0x19201,
+       iocsrrdw_op     = 0x19202,
+       iocsrrdd_op     = 0x19203,
+       iocsrwrb_op     = 0x19204,
+       iocsrwrh_op     = 0x19205,
+       iocsrwrw_op     = 0x19206,
+       iocsrwrd_op     = 0x19207,
 };
 
 enum reg2i5_op {
@@ -318,6 +326,13 @@ struct reg2bstrd_format {
        unsigned int opcode : 10;
 };
 
+struct reg2csr_format {
+       unsigned int rd : 5;
+       unsigned int rj : 5;
+       unsigned int csr : 14;
+       unsigned int opcode : 8;
+};
+
 struct reg3_format {
        unsigned int rd : 5;
        unsigned int rj : 5;
@@ -346,6 +361,7 @@ union loongarch_instruction {
        struct reg2i14_format   reg2i14_format;
        struct reg2i16_format   reg2i16_format;
        struct reg2bstrd_format reg2bstrd_format;
+       struct reg2csr_format   reg2csr_format;
        struct reg3_format      reg3_format;
        struct reg3sa2_format   reg3sa2_format;
 };
index 0dcb36b32cb2527264d07480d1180b8e3bc1079f..c486c2341b6623020073bb8827eced93601ff900 100644 (file)
@@ -52,10 +52,9 @@ static inline void __iomem *ioremap_prot(phys_addr_t offset, unsigned long size,
  * @offset:    bus address of the memory
  * @size:      size of the resource to map
  */
-extern pgprot_t pgprot_wc;
-
 #define ioremap_wc(offset, size)       \
-       ioremap_prot((offset), (size), pgprot_val(pgprot_wc))
+       ioremap_prot((offset), (size),  \
+               pgprot_val(wc_enabled ? PAGE_KERNEL_WUC : PAGE_KERNEL_SUC))
 
 #define ioremap_cache(offset, size)    \
        ioremap_prot((offset), (size), pgprot_val(PAGE_KERNEL))
index deeff8158f45ce1df6bdb0c0169cd31ff8132240..cd6084f4e153feef9140ba198207b4a50fe0cfc2 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);
diff --git a/arch/loongarch/include/asm/kvm_csr.h b/arch/loongarch/include/asm/kvm_csr.h
new file mode 100644 (file)
index 0000000..724ca8b
--- /dev/null
@@ -0,0 +1,211 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
+ */
+
+#ifndef __ASM_LOONGARCH_KVM_CSR_H__
+#define __ASM_LOONGARCH_KVM_CSR_H__
+
+#include <linux/uaccess.h>
+#include <linux/kvm_host.h>
+#include <asm/loongarch.h>
+#include <asm/kvm_vcpu.h>
+
+#define gcsr_read(csr)                                         \
+({                                                             \
+       register unsigned long __v;                             \
+       __asm__ __volatile__(                                   \
+               " gcsrrd %[val], %[reg]\n\t"                    \
+               : [val] "=r" (__v)                              \
+               : [reg] "i" (csr)                               \
+               : "memory");                                    \
+       __v;                                                    \
+})
+
+#define gcsr_write(v, csr)                                     \
+({                                                             \
+       register unsigned long __v = v;                         \
+       __asm__ __volatile__ (                                  \
+               " gcsrwr %[val], %[reg]\n\t"                    \
+               : [val] "+r" (__v)                              \
+               : [reg] "i" (csr)                               \
+               : "memory");                                    \
+})
+
+#define gcsr_xchg(v, m, csr)                                   \
+({                                                             \
+       register unsigned long __v = v;                         \
+       __asm__ __volatile__(                                   \
+               " gcsrxchg %[val], %[mask], %[reg]\n\t"         \
+               : [val] "+r" (__v)                              \
+               : [mask] "r" (m), [reg] "i" (csr)               \
+               : "memory");                                    \
+       __v;                                                    \
+})
+
+/* Guest CSRS read and write */
+#define read_gcsr_crmd()               gcsr_read(LOONGARCH_CSR_CRMD)
+#define write_gcsr_crmd(val)           gcsr_write(val, LOONGARCH_CSR_CRMD)
+#define read_gcsr_prmd()               gcsr_read(LOONGARCH_CSR_PRMD)
+#define write_gcsr_prmd(val)           gcsr_write(val, LOONGARCH_CSR_PRMD)
+#define read_gcsr_euen()               gcsr_read(LOONGARCH_CSR_EUEN)
+#define write_gcsr_euen(val)           gcsr_write(val, LOONGARCH_CSR_EUEN)
+#define read_gcsr_misc()               gcsr_read(LOONGARCH_CSR_MISC)
+#define write_gcsr_misc(val)           gcsr_write(val, LOONGARCH_CSR_MISC)
+#define read_gcsr_ecfg()               gcsr_read(LOONGARCH_CSR_ECFG)
+#define write_gcsr_ecfg(val)           gcsr_write(val, LOONGARCH_CSR_ECFG)
+#define read_gcsr_estat()              gcsr_read(LOONGARCH_CSR_ESTAT)
+#define write_gcsr_estat(val)          gcsr_write(val, LOONGARCH_CSR_ESTAT)
+#define read_gcsr_era()                        gcsr_read(LOONGARCH_CSR_ERA)
+#define write_gcsr_era(val)            gcsr_write(val, LOONGARCH_CSR_ERA)
+#define read_gcsr_badv()               gcsr_read(LOONGARCH_CSR_BADV)
+#define write_gcsr_badv(val)           gcsr_write(val, LOONGARCH_CSR_BADV)
+#define read_gcsr_badi()               gcsr_read(LOONGARCH_CSR_BADI)
+#define write_gcsr_badi(val)           gcsr_write(val, LOONGARCH_CSR_BADI)
+#define read_gcsr_eentry()             gcsr_read(LOONGARCH_CSR_EENTRY)
+#define write_gcsr_eentry(val)         gcsr_write(val, LOONGARCH_CSR_EENTRY)
+
+#define read_gcsr_asid()               gcsr_read(LOONGARCH_CSR_ASID)
+#define write_gcsr_asid(val)           gcsr_write(val, LOONGARCH_CSR_ASID)
+#define read_gcsr_pgdl()               gcsr_read(LOONGARCH_CSR_PGDL)
+#define write_gcsr_pgdl(val)           gcsr_write(val, LOONGARCH_CSR_PGDL)
+#define read_gcsr_pgdh()               gcsr_read(LOONGARCH_CSR_PGDH)
+#define write_gcsr_pgdh(val)           gcsr_write(val, LOONGARCH_CSR_PGDH)
+#define write_gcsr_pgd(val)            gcsr_write(val, LOONGARCH_CSR_PGD)
+#define read_gcsr_pgd()                        gcsr_read(LOONGARCH_CSR_PGD)
+#define read_gcsr_pwctl0()             gcsr_read(LOONGARCH_CSR_PWCTL0)
+#define write_gcsr_pwctl0(val)         gcsr_write(val, LOONGARCH_CSR_PWCTL0)
+#define read_gcsr_pwctl1()             gcsr_read(LOONGARCH_CSR_PWCTL1)
+#define write_gcsr_pwctl1(val)         gcsr_write(val, LOONGARCH_CSR_PWCTL1)
+#define read_gcsr_stlbpgsize()         gcsr_read(LOONGARCH_CSR_STLBPGSIZE)
+#define write_gcsr_stlbpgsize(val)     gcsr_write(val, LOONGARCH_CSR_STLBPGSIZE)
+#define read_gcsr_rvacfg()             gcsr_read(LOONGARCH_CSR_RVACFG)
+#define write_gcsr_rvacfg(val)         gcsr_write(val, LOONGARCH_CSR_RVACFG)
+
+#define read_gcsr_cpuid()              gcsr_read(LOONGARCH_CSR_CPUID)
+#define write_gcsr_cpuid(val)          gcsr_write(val, LOONGARCH_CSR_CPUID)
+#define read_gcsr_prcfg1()             gcsr_read(LOONGARCH_CSR_PRCFG1)
+#define write_gcsr_prcfg1(val)         gcsr_write(val, LOONGARCH_CSR_PRCFG1)
+#define read_gcsr_prcfg2()             gcsr_read(LOONGARCH_CSR_PRCFG2)
+#define write_gcsr_prcfg2(val)         gcsr_write(val, LOONGARCH_CSR_PRCFG2)
+#define read_gcsr_prcfg3()             gcsr_read(LOONGARCH_CSR_PRCFG3)
+#define write_gcsr_prcfg3(val)         gcsr_write(val, LOONGARCH_CSR_PRCFG3)
+
+#define read_gcsr_kscratch0()          gcsr_read(LOONGARCH_CSR_KS0)
+#define write_gcsr_kscratch0(val)      gcsr_write(val, LOONGARCH_CSR_KS0)
+#define read_gcsr_kscratch1()          gcsr_read(LOONGARCH_CSR_KS1)
+#define write_gcsr_kscratch1(val)      gcsr_write(val, LOONGARCH_CSR_KS1)
+#define read_gcsr_kscratch2()          gcsr_read(LOONGARCH_CSR_KS2)
+#define write_gcsr_kscratch2(val)      gcsr_write(val, LOONGARCH_CSR_KS2)
+#define read_gcsr_kscratch3()          gcsr_read(LOONGARCH_CSR_KS3)
+#define write_gcsr_kscratch3(val)      gcsr_write(val, LOONGARCH_CSR_KS3)
+#define read_gcsr_kscratch4()          gcsr_read(LOONGARCH_CSR_KS4)
+#define write_gcsr_kscratch4(val)      gcsr_write(val, LOONGARCH_CSR_KS4)
+#define read_gcsr_kscratch5()          gcsr_read(LOONGARCH_CSR_KS5)
+#define write_gcsr_kscratch5(val)      gcsr_write(val, LOONGARCH_CSR_KS5)
+#define read_gcsr_kscratch6()          gcsr_read(LOONGARCH_CSR_KS6)
+#define write_gcsr_kscratch6(val)      gcsr_write(val, LOONGARCH_CSR_KS6)
+#define read_gcsr_kscratch7()          gcsr_read(LOONGARCH_CSR_KS7)
+#define write_gcsr_kscratch7(val)      gcsr_write(val, LOONGARCH_CSR_KS7)
+
+#define read_gcsr_timerid()            gcsr_read(LOONGARCH_CSR_TMID)
+#define write_gcsr_timerid(val)                gcsr_write(val, LOONGARCH_CSR_TMID)
+#define read_gcsr_timercfg()           gcsr_read(LOONGARCH_CSR_TCFG)
+#define write_gcsr_timercfg(val)       gcsr_write(val, LOONGARCH_CSR_TCFG)
+#define read_gcsr_timertick()          gcsr_read(LOONGARCH_CSR_TVAL)
+#define write_gcsr_timertick(val)      gcsr_write(val, LOONGARCH_CSR_TVAL)
+#define read_gcsr_timeroffset()                gcsr_read(LOONGARCH_CSR_CNTC)
+#define write_gcsr_timeroffset(val)    gcsr_write(val, LOONGARCH_CSR_CNTC)
+
+#define read_gcsr_llbctl()             gcsr_read(LOONGARCH_CSR_LLBCTL)
+#define write_gcsr_llbctl(val)         gcsr_write(val, LOONGARCH_CSR_LLBCTL)
+
+#define read_gcsr_tlbidx()             gcsr_read(LOONGARCH_CSR_TLBIDX)
+#define write_gcsr_tlbidx(val)         gcsr_write(val, LOONGARCH_CSR_TLBIDX)
+#define read_gcsr_tlbrentry()          gcsr_read(LOONGARCH_CSR_TLBRENTRY)
+#define write_gcsr_tlbrentry(val)      gcsr_write(val, LOONGARCH_CSR_TLBRENTRY)
+#define read_gcsr_tlbrbadv()           gcsr_read(LOONGARCH_CSR_TLBRBADV)
+#define write_gcsr_tlbrbadv(val)       gcsr_write(val, LOONGARCH_CSR_TLBRBADV)
+#define read_gcsr_tlbrera()            gcsr_read(LOONGARCH_CSR_TLBRERA)
+#define write_gcsr_tlbrera(val)                gcsr_write(val, LOONGARCH_CSR_TLBRERA)
+#define read_gcsr_tlbrsave()           gcsr_read(LOONGARCH_CSR_TLBRSAVE)
+#define write_gcsr_tlbrsave(val)       gcsr_write(val, LOONGARCH_CSR_TLBRSAVE)
+#define read_gcsr_tlbrelo0()           gcsr_read(LOONGARCH_CSR_TLBRELO0)
+#define write_gcsr_tlbrelo0(val)       gcsr_write(val, LOONGARCH_CSR_TLBRELO0)
+#define read_gcsr_tlbrelo1()           gcsr_read(LOONGARCH_CSR_TLBRELO1)
+#define write_gcsr_tlbrelo1(val)       gcsr_write(val, LOONGARCH_CSR_TLBRELO1)
+#define read_gcsr_tlbrehi()            gcsr_read(LOONGARCH_CSR_TLBREHI)
+#define write_gcsr_tlbrehi(val)                gcsr_write(val, LOONGARCH_CSR_TLBREHI)
+#define read_gcsr_tlbrprmd()           gcsr_read(LOONGARCH_CSR_TLBRPRMD)
+#define write_gcsr_tlbrprmd(val)       gcsr_write(val, LOONGARCH_CSR_TLBRPRMD)
+
+#define read_gcsr_directwin0()         gcsr_read(LOONGARCH_CSR_DMWIN0)
+#define write_gcsr_directwin0(val)     gcsr_write(val, LOONGARCH_CSR_DMWIN0)
+#define read_gcsr_directwin1()         gcsr_read(LOONGARCH_CSR_DMWIN1)
+#define write_gcsr_directwin1(val)     gcsr_write(val, LOONGARCH_CSR_DMWIN1)
+#define read_gcsr_directwin2()         gcsr_read(LOONGARCH_CSR_DMWIN2)
+#define write_gcsr_directwin2(val)     gcsr_write(val, LOONGARCH_CSR_DMWIN2)
+#define read_gcsr_directwin3()         gcsr_read(LOONGARCH_CSR_DMWIN3)
+#define write_gcsr_directwin3(val)     gcsr_write(val, LOONGARCH_CSR_DMWIN3)
+
+/* Guest related CSRs */
+#define read_csr_gtlbc()               csr_read64(LOONGARCH_CSR_GTLBC)
+#define write_csr_gtlbc(val)           csr_write64(val, LOONGARCH_CSR_GTLBC)
+#define read_csr_trgp()                        csr_read64(LOONGARCH_CSR_TRGP)
+#define read_csr_gcfg()                        csr_read64(LOONGARCH_CSR_GCFG)
+#define write_csr_gcfg(val)            csr_write64(val, LOONGARCH_CSR_GCFG)
+#define read_csr_gstat()               csr_read64(LOONGARCH_CSR_GSTAT)
+#define write_csr_gstat(val)           csr_write64(val, LOONGARCH_CSR_GSTAT)
+#define read_csr_gintc()               csr_read64(LOONGARCH_CSR_GINTC)
+#define write_csr_gintc(val)           csr_write64(val, LOONGARCH_CSR_GINTC)
+#define read_csr_gcntc()               csr_read64(LOONGARCH_CSR_GCNTC)
+#define write_csr_gcntc(val)           csr_write64(val, LOONGARCH_CSR_GCNTC)
+
+#define __BUILD_GCSR_OP(name)          __BUILD_CSR_COMMON(gcsr_##name)
+
+__BUILD_CSR_OP(gcfg)
+__BUILD_CSR_OP(gstat)
+__BUILD_CSR_OP(gtlbc)
+__BUILD_CSR_OP(gintc)
+__BUILD_GCSR_OP(llbctl)
+__BUILD_GCSR_OP(tlbidx)
+
+#define set_gcsr_estat(val)    \
+       gcsr_xchg(val, val, LOONGARCH_CSR_ESTAT)
+#define clear_gcsr_estat(val)  \
+       gcsr_xchg(~(val), val, LOONGARCH_CSR_ESTAT)
+
+#define kvm_read_hw_gcsr(id)           gcsr_read(id)
+#define kvm_write_hw_gcsr(id, val)     gcsr_write(val, id)
+
+#define kvm_save_hw_gcsr(csr, gid)     (csr->csrs[gid] = gcsr_read(gid))
+#define kvm_restore_hw_gcsr(csr, gid)  (gcsr_write(csr->csrs[gid], gid))
+
+int kvm_emu_iocsr(larch_inst inst, struct kvm_run *run, struct kvm_vcpu *vcpu);
+
+static __always_inline unsigned long kvm_read_sw_gcsr(struct loongarch_csrs *csr, int gid)
+{
+       return csr->csrs[gid];
+}
+
+static __always_inline void kvm_write_sw_gcsr(struct loongarch_csrs *csr, int gid, unsigned long val)
+{
+       csr->csrs[gid] = val;
+}
+
+static __always_inline void kvm_set_sw_gcsr(struct loongarch_csrs *csr,
+                                           int gid, unsigned long val)
+{
+       csr->csrs[gid] |= val;
+}
+
+static __always_inline void kvm_change_sw_gcsr(struct loongarch_csrs *csr,
+                                              int gid, unsigned long mask, unsigned long val)
+{
+       unsigned long _mask = mask;
+
+       csr->csrs[gid] &= ~_mask;
+       csr->csrs[gid] |= val & _mask;
+}
+
+#endif /* __ASM_LOONGARCH_KVM_CSR_H__ */
diff --git a/arch/loongarch/include/asm/kvm_host.h b/arch/loongarch/include/asm/kvm_host.h
new file mode 100644 (file)
index 0000000..1132870
--- /dev/null
@@ -0,0 +1,237 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
+ */
+
+#ifndef __ASM_LOONGARCH_KVM_HOST_H__
+#define __ASM_LOONGARCH_KVM_HOST_H__
+
+#include <linux/cpumask.h>
+#include <linux/hrtimer.h>
+#include <linux/interrupt.h>
+#include <linux/kvm.h>
+#include <linux/kvm_types.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/threads.h>
+#include <linux/types.h>
+
+#include <asm/inst.h>
+#include <asm/kvm_mmu.h>
+#include <asm/loongarch.h>
+
+/* Loongarch KVM register ids */
+#define KVM_GET_IOC_CSR_IDX(id)                ((id & KVM_CSR_IDX_MASK) >> LOONGARCH_REG_SHIFT)
+#define KVM_GET_IOC_CPUCFG_IDX(id)     ((id & KVM_CPUCFG_IDX_MASK) >> LOONGARCH_REG_SHIFT)
+
+#define KVM_MAX_VCPUS                  256
+#define KVM_MAX_CPUCFG_REGS            21
+/* memory slots that does not exposed to userspace */
+#define KVM_PRIVATE_MEM_SLOTS          0
+
+#define KVM_HALT_POLL_NS_DEFAULT       500000
+
+struct kvm_vm_stat {
+       struct kvm_vm_stat_generic generic;
+       u64 pages;
+       u64 hugepages;
+};
+
+struct kvm_vcpu_stat {
+       struct kvm_vcpu_stat_generic generic;
+       u64 int_exits;
+       u64 idle_exits;
+       u64 cpucfg_exits;
+       u64 signal_exits;
+};
+
+struct kvm_arch_memory_slot {
+};
+
+struct kvm_context {
+       unsigned long vpid_cache;
+       struct kvm_vcpu *last_vcpu;
+};
+
+struct kvm_world_switch {
+       int (*exc_entry)(void);
+       int (*enter_guest)(struct kvm_run *run, struct kvm_vcpu *vcpu);
+       unsigned long page_order;
+};
+
+#define MAX_PGTABLE_LEVELS     4
+
+struct kvm_arch {
+       /* Guest physical mm */
+       kvm_pte_t *pgd;
+       unsigned long gpa_size;
+       unsigned long invalid_ptes[MAX_PGTABLE_LEVELS];
+       unsigned int  pte_shifts[MAX_PGTABLE_LEVELS];
+       unsigned int  root_level;
+
+       s64 time_offset;
+       struct kvm_context __percpu *vmcs;
+};
+
+#define CSR_MAX_NUMS           0x800
+
+struct loongarch_csrs {
+       unsigned long csrs[CSR_MAX_NUMS];
+};
+
+/* Resume Flags */
+#define RESUME_HOST            0
+#define RESUME_GUEST           1
+
+enum emulation_result {
+       EMULATE_DONE,           /* no further processing */
+       EMULATE_DO_MMIO,        /* kvm_run filled with MMIO request */
+       EMULATE_DO_IOCSR,       /* handle IOCSR request */
+       EMULATE_FAIL,           /* can't emulate this instruction */
+       EMULATE_EXCEPT,         /* A guest exception has been generated */
+};
+
+#define KVM_LARCH_FPU          (0x1 << 0)
+#define KVM_LARCH_SWCSR_LATEST (0x1 << 1)
+#define KVM_LARCH_HWCSR_USABLE (0x1 << 2)
+
+struct kvm_vcpu_arch {
+       /*
+        * Switch pointer-to-function type to unsigned long
+        * for loading the value into register directly.
+        */
+       unsigned long host_eentry;
+       unsigned long guest_eentry;
+
+       /* Pointers stored here for easy accessing from assembly code */
+       int (*handle_exit)(struct kvm_run *run, struct kvm_vcpu *vcpu);
+
+       /* Host registers preserved across guest mode execution */
+       unsigned long host_sp;
+       unsigned long host_tp;
+       unsigned long host_pgd;
+
+       /* Host CSRs are used when handling exits from guest */
+       unsigned long badi;
+       unsigned long badv;
+       unsigned long host_ecfg;
+       unsigned long host_estat;
+       unsigned long host_percpu;
+
+       /* GPRs */
+       unsigned long gprs[32];
+       unsigned long pc;
+
+       /* Which auxiliary state is loaded (KVM_LARCH_*) */
+       unsigned int aux_inuse;
+
+       /* FPU state */
+       struct loongarch_fpu fpu FPU_ALIGN;
+
+       /* CSR state */
+       struct loongarch_csrs *csr;
+
+       /* GPR used as IO source/target */
+       u32 io_gpr;
+
+       /* KVM register to control count timer */
+       u32 count_ctl;
+       struct hrtimer swtimer;
+
+       /* Bitmask of intr that are pending */
+       unsigned long irq_pending;
+       /* Bitmask of pending intr to be cleared */
+       unsigned long irq_clear;
+
+       /* Bitmask of exceptions that are pending */
+       unsigned long exception_pending;
+       unsigned int  esubcode;
+
+       /* Cache for pages needed inside spinlock regions */
+       struct kvm_mmu_memory_cache mmu_page_cache;
+
+       /* vcpu's vpid */
+       u64 vpid;
+
+       /* Frequency of stable timer in Hz */
+       u64 timer_mhz;
+       ktime_t expire;
+
+       /* Last CPU the vCPU state was loaded on */
+       int last_sched_cpu;
+       /* mp state */
+       struct kvm_mp_state mp_state;
+       /* cpucfg */
+       u32 cpucfg[KVM_MAX_CPUCFG_REGS];
+};
+
+static inline unsigned long readl_sw_gcsr(struct loongarch_csrs *csr, int reg)
+{
+       return csr->csrs[reg];
+}
+
+static inline void writel_sw_gcsr(struct loongarch_csrs *csr, int reg, unsigned long val)
+{
+       csr->csrs[reg] = val;
+}
+
+/* Debug: dump vcpu state */
+int kvm_arch_vcpu_dump_regs(struct kvm_vcpu *vcpu);
+
+/* MMU handling */
+void kvm_flush_tlb_all(void);
+void kvm_flush_tlb_gpa(struct kvm_vcpu *vcpu, unsigned long gpa);
+int kvm_handle_mm_fault(struct kvm_vcpu *vcpu, unsigned long badv, bool write);
+
+#define KVM_ARCH_WANT_MMU_NOTIFIER
+void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
+int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end, bool blockable);
+int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end);
+int kvm_test_age_hva(struct kvm *kvm, unsigned long hva);
+
+static inline void update_pc(struct kvm_vcpu_arch *arch)
+{
+       arch->pc += 4;
+}
+
+/*
+ * kvm_is_ifetch_fault() - Find whether a TLBL exception is due to ifetch fault.
+ * @vcpu:      Virtual CPU.
+ *
+ * Returns:    Whether the TLBL exception was likely due to an instruction
+ *             fetch fault rather than a data load fault.
+ */
+static inline bool kvm_is_ifetch_fault(struct kvm_vcpu_arch *arch)
+{
+       return arch->pc == arch->badv;
+}
+
+/* Misc */
+static inline void kvm_arch_hardware_unsetup(void) {}
+static inline void kvm_arch_sync_events(struct kvm *kvm) {}
+static inline void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen) {}
+static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {}
+static inline void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu) {}
+static inline void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu) {}
+static inline void kvm_arch_vcpu_block_finish(struct kvm_vcpu *vcpu) {}
+static inline void kvm_arch_free_memslot(struct kvm *kvm, struct kvm_memory_slot *slot) {}
+void kvm_check_vpid(struct kvm_vcpu *vcpu);
+enum hrtimer_restart kvm_swtimer_wakeup(struct hrtimer *timer);
+void kvm_arch_flush_remote_tlbs_memslot(struct kvm *kvm, const struct kvm_memory_slot *memslot);
+void kvm_init_vmcs(struct kvm *kvm);
+void kvm_exc_entry(void);
+int  kvm_enter_guest(struct kvm_run *run, struct kvm_vcpu *vcpu);
+
+extern unsigned long vpid_mask;
+extern const unsigned long kvm_exception_size;
+extern const unsigned long kvm_enter_guest_size;
+extern struct kvm_world_switch *kvm_loongarch_ops;
+
+#define SW_GCSR                (1 << 0)
+#define HW_GCSR                (1 << 1)
+#define INVALID_GCSR   (1 << 2)
+
+int get_gcsr_flag(int csr);
+void set_hw_gcsr(int csr_id, unsigned long val);
+
+#endif /* __ASM_LOONGARCH_KVM_HOST_H__ */
diff --git a/arch/loongarch/include/asm/kvm_mmu.h b/arch/loongarch/include/asm/kvm_mmu.h
new file mode 100644 (file)
index 0000000..099bafc
--- /dev/null
@@ -0,0 +1,139 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
+ */
+
+#ifndef __ASM_LOONGARCH_KVM_MMU_H__
+#define __ASM_LOONGARCH_KVM_MMU_H__
+
+#include <linux/kvm_host.h>
+#include <asm/pgalloc.h>
+#include <asm/tlb.h>
+
+/*
+ * KVM_MMU_CACHE_MIN_PAGES is the number of GPA page table translation levels
+ * for which pages need to be cached.
+ */
+#define KVM_MMU_CACHE_MIN_PAGES        (CONFIG_PGTABLE_LEVELS - 1)
+
+#define _KVM_FLUSH_PGTABLE     0x1
+#define _KVM_HAS_PGMASK                0x2
+#define kvm_pfn_pte(pfn, prot) (((pfn) << PFN_PTE_SHIFT) | pgprot_val(prot))
+#define kvm_pte_pfn(x)         ((phys_addr_t)((x & _PFN_MASK) >> PFN_PTE_SHIFT))
+
+typedef unsigned long kvm_pte_t;
+typedef struct kvm_ptw_ctx kvm_ptw_ctx;
+typedef int (*kvm_pte_ops)(kvm_pte_t *pte, phys_addr_t addr, kvm_ptw_ctx *ctx);
+
+struct kvm_ptw_ctx {
+       kvm_pte_ops     ops;
+       unsigned long   flag;
+
+       /* for kvm_arch_mmu_enable_log_dirty_pt_masked use */
+       unsigned long   mask;
+       unsigned long   gfn;
+
+       /* page walk mmu info */
+       unsigned int    level;
+       unsigned long   pgtable_shift;
+       unsigned long   invalid_entry;
+       unsigned long   *invalid_ptes;
+       unsigned int    *pte_shifts;
+       void            *opaque;
+
+       /* free pte table page list */
+       struct list_head list;
+};
+
+kvm_pte_t *kvm_pgd_alloc(void);
+
+static inline void kvm_set_pte(kvm_pte_t *ptep, kvm_pte_t val)
+{
+       WRITE_ONCE(*ptep, val);
+}
+
+static inline int kvm_pte_write(kvm_pte_t pte) { return pte & _PAGE_WRITE; }
+static inline int kvm_pte_dirty(kvm_pte_t pte) { return pte & _PAGE_DIRTY; }
+static inline int kvm_pte_young(kvm_pte_t pte) { return pte & _PAGE_ACCESSED; }
+static inline int kvm_pte_huge(kvm_pte_t pte) { return pte & _PAGE_HUGE; }
+
+static inline kvm_pte_t kvm_pte_mkyoung(kvm_pte_t pte)
+{
+       return pte | _PAGE_ACCESSED;
+}
+
+static inline kvm_pte_t kvm_pte_mkold(kvm_pte_t pte)
+{
+       return pte & ~_PAGE_ACCESSED;
+}
+
+static inline kvm_pte_t kvm_pte_mkdirty(kvm_pte_t pte)
+{
+       return pte | _PAGE_DIRTY;
+}
+
+static inline kvm_pte_t kvm_pte_mkclean(kvm_pte_t pte)
+{
+       return pte & ~_PAGE_DIRTY;
+}
+
+static inline kvm_pte_t kvm_pte_mkhuge(kvm_pte_t pte)
+{
+       return pte | _PAGE_HUGE;
+}
+
+static inline kvm_pte_t kvm_pte_mksmall(kvm_pte_t pte)
+{
+       return pte & ~_PAGE_HUGE;
+}
+
+static inline int kvm_need_flush(kvm_ptw_ctx *ctx)
+{
+       return ctx->flag & _KVM_FLUSH_PGTABLE;
+}
+
+static inline kvm_pte_t *kvm_pgtable_offset(kvm_ptw_ctx *ctx, kvm_pte_t *table,
+                                       phys_addr_t addr)
+{
+
+       return table + ((addr >> ctx->pgtable_shift) & (PTRS_PER_PTE - 1));
+}
+
+static inline phys_addr_t kvm_pgtable_addr_end(kvm_ptw_ctx *ctx,
+                               phys_addr_t addr, phys_addr_t end)
+{
+       phys_addr_t boundary, size;
+
+       size = 0x1UL << ctx->pgtable_shift;
+       boundary = (addr + size) & ~(size - 1);
+       return (boundary - 1 < end - 1) ? boundary : end;
+}
+
+static inline int kvm_pte_present(kvm_ptw_ctx *ctx, kvm_pte_t *entry)
+{
+       if (!ctx || ctx->level == 0)
+               return !!(*entry & _PAGE_PRESENT);
+
+       return *entry != ctx->invalid_entry;
+}
+
+static inline int kvm_pte_none(kvm_ptw_ctx *ctx, kvm_pte_t *entry)
+{
+       return *entry == ctx->invalid_entry;
+}
+
+static inline void kvm_ptw_enter(kvm_ptw_ctx *ctx)
+{
+       ctx->level--;
+       ctx->pgtable_shift = ctx->pte_shifts[ctx->level];
+       ctx->invalid_entry = ctx->invalid_ptes[ctx->level];
+}
+
+static inline void kvm_ptw_exit(kvm_ptw_ctx *ctx)
+{
+       ctx->level++;
+       ctx->pgtable_shift = ctx->pte_shifts[ctx->level];
+       ctx->invalid_entry = ctx->invalid_ptes[ctx->level];
+}
+
+#endif /* __ASM_LOONGARCH_KVM_MMU_H__ */
diff --git a/arch/loongarch/include/asm/kvm_types.h b/arch/loongarch/include/asm/kvm_types.h
new file mode 100644 (file)
index 0000000..2fe1d4b
--- /dev/null
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
+ */
+
+#ifndef _ASM_LOONGARCH_KVM_TYPES_H
+#define _ASM_LOONGARCH_KVM_TYPES_H
+
+#define KVM_ARCH_NR_OBJS_PER_MEMORY_CACHE      40
+
+#endif /* _ASM_LOONGARCH_KVM_TYPES_H */
diff --git a/arch/loongarch/include/asm/kvm_vcpu.h b/arch/loongarch/include/asm/kvm_vcpu.h
new file mode 100644 (file)
index 0000000..553cfa2
--- /dev/null
@@ -0,0 +1,93 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
+ */
+
+#ifndef __ASM_LOONGARCH_KVM_VCPU_H__
+#define __ASM_LOONGARCH_KVM_VCPU_H__
+
+#include <linux/kvm_host.h>
+#include <asm/loongarch.h>
+
+/* Controlled by 0x5 guest estat */
+#define CPU_SIP0                       (_ULCAST_(1))
+#define CPU_SIP1                       (_ULCAST_(1) << 1)
+#define CPU_PMU                                (_ULCAST_(1) << 10)
+#define CPU_TIMER                      (_ULCAST_(1) << 11)
+#define CPU_IPI                                (_ULCAST_(1) << 12)
+
+/* Controlled by 0x52 guest exception VIP aligned to estat bit 5~12 */
+#define CPU_IP0                                (_ULCAST_(1))
+#define CPU_IP1                                (_ULCAST_(1) << 1)
+#define CPU_IP2                                (_ULCAST_(1) << 2)
+#define CPU_IP3                                (_ULCAST_(1) << 3)
+#define CPU_IP4                                (_ULCAST_(1) << 4)
+#define CPU_IP5                                (_ULCAST_(1) << 5)
+#define CPU_IP6                                (_ULCAST_(1) << 6)
+#define CPU_IP7                                (_ULCAST_(1) << 7)
+
+#define MNSEC_PER_SEC                  (NSEC_PER_SEC >> 20)
+
+/* KVM_IRQ_LINE irq field index values */
+#define KVM_LOONGSON_IRQ_TYPE_SHIFT    24
+#define KVM_LOONGSON_IRQ_TYPE_MASK     0xff
+#define KVM_LOONGSON_IRQ_VCPU_SHIFT    16
+#define KVM_LOONGSON_IRQ_VCPU_MASK     0xff
+#define KVM_LOONGSON_IRQ_NUM_SHIFT     0
+#define KVM_LOONGSON_IRQ_NUM_MASK      0xffff
+
+typedef union loongarch_instruction  larch_inst;
+typedef int (*exit_handle_fn)(struct kvm_vcpu *);
+
+int  kvm_emu_mmio_read(struct kvm_vcpu *vcpu, larch_inst inst);
+int  kvm_emu_mmio_write(struct kvm_vcpu *vcpu, larch_inst inst);
+int  kvm_complete_mmio_read(struct kvm_vcpu *vcpu, struct kvm_run *run);
+int  kvm_complete_iocsr_read(struct kvm_vcpu *vcpu, struct kvm_run *run);
+int  kvm_emu_idle(struct kvm_vcpu *vcpu);
+int  kvm_pending_timer(struct kvm_vcpu *vcpu);
+int  kvm_handle_fault(struct kvm_vcpu *vcpu, int fault);
+void kvm_deliver_intr(struct kvm_vcpu *vcpu);
+void kvm_deliver_exception(struct kvm_vcpu *vcpu);
+
+void kvm_own_fpu(struct kvm_vcpu *vcpu);
+void kvm_lose_fpu(struct kvm_vcpu *vcpu);
+void kvm_save_fpu(struct loongarch_fpu *fpu);
+void kvm_restore_fpu(struct loongarch_fpu *fpu);
+void kvm_restore_fcsr(struct loongarch_fpu *fpu);
+
+void kvm_acquire_timer(struct kvm_vcpu *vcpu);
+void kvm_init_timer(struct kvm_vcpu *vcpu, unsigned long hz);
+void kvm_reset_timer(struct kvm_vcpu *vcpu);
+void kvm_save_timer(struct kvm_vcpu *vcpu);
+void kvm_restore_timer(struct kvm_vcpu *vcpu);
+
+int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq);
+
+/*
+ * Loongarch KVM guest interrupt handling
+ */
+static inline void kvm_queue_irq(struct kvm_vcpu *vcpu, unsigned int irq)
+{
+       set_bit(irq, &vcpu->arch.irq_pending);
+       clear_bit(irq, &vcpu->arch.irq_clear);
+}
+
+static inline void kvm_dequeue_irq(struct kvm_vcpu *vcpu, unsigned int irq)
+{
+       clear_bit(irq, &vcpu->arch.irq_pending);
+       set_bit(irq, &vcpu->arch.irq_clear);
+}
+
+static inline int kvm_queue_exception(struct kvm_vcpu *vcpu,
+                       unsigned int code, unsigned int subcode)
+{
+       /* only one exception can be injected */
+       if (!vcpu->arch.exception_pending) {
+               set_bit(code, &vcpu->arch.exception_pending);
+               vcpu->arch.esubcode = subcode;
+               return 0;
+       } else
+               return -1;
+}
+
+#endif /* __ASM_LOONGARCH_KVM_VCPU_H__ */
index 81b0c4cfbf4f24efb57335d76ea03921a1e04e4b..e2eca1a25b4ef7af3f5fb788d2a9e2d8fd6592d8 100644 (file)
        .cfi_endproc;                                   \
        SYM_END(name, SYM_T_FUNC)
 
+#define SYM_CODE_START(name)                           \
+       SYM_START(name, SYM_L_GLOBAL, SYM_A_ALIGN)      \
+       .cfi_startproc;
+
+#define SYM_CODE_END(name)                             \
+       .cfi_endproc;                                   \
+       SYM_END(name, SYM_T_NONE)
+
 #endif
index 33531d432b492d201f98ae64b941255a94355f91..9b4957cefa8ad24cdd792629240d5cc08bed264a 100644 (file)
 #define LOONGARCH_CSR_ECFG             0x4     /* Exception config */
 #define  CSR_ECFG_VS_SHIFT             16
 #define  CSR_ECFG_VS_WIDTH             3
+#define  CSR_ECFG_VS_SHIFT_END         (CSR_ECFG_VS_SHIFT + CSR_ECFG_VS_WIDTH - 1)
 #define  CSR_ECFG_VS                   (_ULCAST_(0x7) << CSR_ECFG_VS_SHIFT)
 #define  CSR_ECFG_IM_SHIFT             0
 #define  CSR_ECFG_IM_WIDTH             14
 #define  CSR_TLBLO1_V                  (_ULCAST_(0x1) << CSR_TLBLO1_V_SHIFT)
 
 #define LOONGARCH_CSR_GTLBC            0x15    /* Guest TLB control */
-#define  CSR_GTLBC_RID_SHIFT           16
-#define  CSR_GTLBC_RID_WIDTH           8
-#define  CSR_GTLBC_RID                 (_ULCAST_(0xff) << CSR_GTLBC_RID_SHIFT)
+#define  CSR_GTLBC_TGID_SHIFT          16
+#define  CSR_GTLBC_TGID_WIDTH          8
+#define  CSR_GTLBC_TGID_SHIFT_END      (CSR_GTLBC_TGID_SHIFT + CSR_GTLBC_TGID_WIDTH - 1)
+#define  CSR_GTLBC_TGID                        (_ULCAST_(0xff) << CSR_GTLBC_TGID_SHIFT)
 #define  CSR_GTLBC_TOTI_SHIFT          13
 #define  CSR_GTLBC_TOTI                        (_ULCAST_(0x1) << CSR_GTLBC_TOTI_SHIFT)
-#define  CSR_GTLBC_USERID_SHIFT                12
-#define  CSR_GTLBC_USERID              (_ULCAST_(0x1) << CSR_GTLBC_USERID_SHIFT)
+#define  CSR_GTLBC_USETGID_SHIFT       12
+#define  CSR_GTLBC_USETGID             (_ULCAST_(0x1) << CSR_GTLBC_USETGID_SHIFT)
 #define  CSR_GTLBC_GMTLBSZ_SHIFT       0
 #define  CSR_GTLBC_GMTLBSZ_WIDTH       6
 #define  CSR_GTLBC_GMTLBSZ             (_ULCAST_(0x3f) << CSR_GTLBC_GMTLBSZ_SHIFT)
 #define LOONGARCH_CSR_GSTAT            0x50    /* Guest status */
 #define  CSR_GSTAT_GID_SHIFT           16
 #define  CSR_GSTAT_GID_WIDTH           8
+#define  CSR_GSTAT_GID_SHIFT_END       (CSR_GSTAT_GID_SHIFT + CSR_GSTAT_GID_WIDTH - 1)
 #define  CSR_GSTAT_GID                 (_ULCAST_(0xff) << CSR_GSTAT_GID_SHIFT)
 #define  CSR_GSTAT_GIDBIT_SHIFT                4
 #define  CSR_GSTAT_GIDBIT_WIDTH                6
 #define  CSR_GCFG_MATC_GUEST           (_ULCAST_(0x0) << CSR_GCFG_MATC_SHITF)
 #define  CSR_GCFG_MATC_ROOT            (_ULCAST_(0x1) << CSR_GCFG_MATC_SHITF)
 #define  CSR_GCFG_MATC_NEST            (_ULCAST_(0x2) << CSR_GCFG_MATC_SHITF)
+#define  CSR_GCFG_MATP_NEST_SHIFT      2
+#define  CSR_GCFG_MATP_NEST            (_ULCAST_(0x1) << CSR_GCFG_MATP_NEST_SHIFT)
+#define  CSR_GCFG_MATP_ROOT_SHIFT      1
+#define  CSR_GCFG_MATP_ROOT            (_ULCAST_(0x1) << CSR_GCFG_MATP_ROOT_SHIFT)
+#define  CSR_GCFG_MATP_GUEST_SHIFT     0
+#define  CSR_GCFG_MATP_GUEST           (_ULCAST_(0x1) << CSR_GCFG_MATP_GUEST_SHIFT)
 
 #define LOONGARCH_CSR_GINTC            0x52    /* Guest interrupt control */
 #define  CSR_GINTC_HC_SHIFT            16
index 35348d4c4209ad55773290cd0cb88dfd6b37db93..21319c1e045c216fffaaecc5370b0677cf48aada 100644 (file)
@@ -105,13 +105,15 @@ static inline pgprot_t pgprot_noncached(pgprot_t _prot)
        return __pgprot(prot);
 }
 
+extern bool wc_enabled;
+
 #define pgprot_writecombine pgprot_writecombine
 
 static inline pgprot_t pgprot_writecombine(pgprot_t _prot)
 {
        unsigned long prot = pgprot_val(_prot);
 
-       prot = (prot & ~_CACHE_MASK) | _CACHE_WUC;
+       prot = (prot & ~_CACHE_MASK) | (wc_enabled ? _CACHE_WUC : _CACHE_SUC);
 
        return __pgprot(prot);
 }
index 66ecb480c894aa3f29843e711e374812fff3e658..f81e5f01d61905f5b8d7da4786ba512258381acd 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);
 
diff --git a/arch/loongarch/include/uapi/asm/kvm.h b/arch/loongarch/include/uapi/asm/kvm.h
new file mode 100644 (file)
index 0000000..c6ad2ee
--- /dev/null
@@ -0,0 +1,108 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/*
+ * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
+ */
+
+#ifndef __UAPI_ASM_LOONGARCH_KVM_H
+#define __UAPI_ASM_LOONGARCH_KVM_H
+
+#include <linux/types.h>
+
+/*
+ * KVM LoongArch specific structures and definitions.
+ *
+ * Some parts derived from the x86 version of this file.
+ */
+
+#define __KVM_HAVE_READONLY_MEM
+
+#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
+#define KVM_DIRTY_LOG_PAGE_OFFSET      64
+
+/*
+ * for KVM_GET_REGS and KVM_SET_REGS
+ */
+struct kvm_regs {
+       /* out (KVM_GET_REGS) / in (KVM_SET_REGS) */
+       __u64 gpr[32];
+       __u64 pc;
+};
+
+/*
+ * for KVM_GET_FPU and KVM_SET_FPU
+ */
+struct kvm_fpu {
+       __u32 fcsr;
+       __u64 fcc;    /* 8x8 */
+       struct kvm_fpureg {
+               __u64 val64[4];
+       } fpr[32];
+};
+
+/*
+ * For LoongArch, we use KVM_SET_ONE_REG and KVM_GET_ONE_REG to access various
+ * registers.  The id field is broken down as follows:
+ *
+ *  bits[63..52] - As per linux/kvm.h
+ *  bits[51..32] - Must be zero.
+ *  bits[31..16] - Register set.
+ *
+ * Register set = 0: GP registers from kvm_regs (see definitions below).
+ *
+ * Register set = 1: CSR registers.
+ *
+ * Register set = 2: KVM specific registers (see definitions below).
+ *
+ * Register set = 3: FPU / SIMD registers (see definitions below).
+ *
+ * Other sets registers may be added in the future.  Each set would
+ * have its own identifier in bits[31..16].
+ */
+
+#define KVM_REG_LOONGARCH_GPR          (KVM_REG_LOONGARCH | 0x00000ULL)
+#define KVM_REG_LOONGARCH_CSR          (KVM_REG_LOONGARCH | 0x10000ULL)
+#define KVM_REG_LOONGARCH_KVM          (KVM_REG_LOONGARCH | 0x20000ULL)
+#define KVM_REG_LOONGARCH_FPSIMD       (KVM_REG_LOONGARCH | 0x30000ULL)
+#define KVM_REG_LOONGARCH_CPUCFG       (KVM_REG_LOONGARCH | 0x40000ULL)
+#define KVM_REG_LOONGARCH_MASK         (KVM_REG_LOONGARCH | 0x70000ULL)
+#define KVM_CSR_IDX_MASK               0x7fff
+#define KVM_CPUCFG_IDX_MASK            0x7fff
+
+/*
+ * KVM_REG_LOONGARCH_KVM - KVM specific control registers.
+ */
+
+#define KVM_REG_LOONGARCH_COUNTER      (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 1)
+#define KVM_REG_LOONGARCH_VCPU_RESET   (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 2)
+
+#define LOONGARCH_REG_SHIFT            3
+#define LOONGARCH_REG_64(TYPE, REG)    (TYPE | KVM_REG_SIZE_U64 | (REG << LOONGARCH_REG_SHIFT))
+#define KVM_IOC_CSRID(REG)             LOONGARCH_REG_64(KVM_REG_LOONGARCH_CSR, REG)
+#define KVM_IOC_CPUCFG(REG)            LOONGARCH_REG_64(KVM_REG_LOONGARCH_CPUCFG, REG)
+
+struct kvm_debug_exit_arch {
+};
+
+/* for KVM_SET_GUEST_DEBUG */
+struct kvm_guest_debug_arch {
+};
+
+/* definition of registers in kvm_run */
+struct kvm_sync_regs {
+};
+
+/* dummy definition */
+struct kvm_sregs {
+};
+
+struct kvm_iocsr_entry {
+       __u32 addr;
+       __u32 pad;
+       __u64 data;
+};
+
+#define KVM_NR_IRQCHIPS                1
+#define KVM_IRQCHIP_NUM_PINS   64
+#define KVM_MAX_CORES          256
+
+#endif /* __UAPI_ASM_LOONGARCH_KVM_H */
index c56ea0b7544899e2b7ccf6aee30c8ae40fe350d0..4fcc168f07323154b4d7fc6712ab7a2298bb0d3e 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 9450e09073ebf7411e200a21a5a666c7dad092be..8e00a754e548943ae4dba5d330a1354426c713d1 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 8da0726777edb41ea66d47f640308c18435f4551..173fe514fc9ecf2974c01c1e06b8f130988da9a7 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/mm.h>
 #include <linux/kbuild.h>
 #include <linux/suspend.h>
+#include <linux/kvm_host.h>
 #include <asm/cpu-info.h>
 #include <asm/ptrace.h>
 #include <asm/processor.h>
@@ -289,3 +290,34 @@ void output_fgraph_ret_regs_defines(void)
        BLANK();
 }
 #endif
+
+void output_kvm_defines(void)
+{
+       COMMENT("KVM/LoongArch Specific offsets.");
+
+       OFFSET(VCPU_FCC, kvm_vcpu_arch, fpu.fcc);
+       OFFSET(VCPU_FCSR0, kvm_vcpu_arch, fpu.fcsr);
+       BLANK();
+
+       OFFSET(KVM_VCPU_ARCH, kvm_vcpu, arch);
+       OFFSET(KVM_VCPU_KVM, kvm_vcpu, kvm);
+       OFFSET(KVM_VCPU_RUN, kvm_vcpu, run);
+       BLANK();
+
+       OFFSET(KVM_ARCH_HSP, kvm_vcpu_arch, host_sp);
+       OFFSET(KVM_ARCH_HTP, kvm_vcpu_arch, host_tp);
+       OFFSET(KVM_ARCH_HPGD, kvm_vcpu_arch, host_pgd);
+       OFFSET(KVM_ARCH_HANDLE_EXIT, kvm_vcpu_arch, handle_exit);
+       OFFSET(KVM_ARCH_HEENTRY, kvm_vcpu_arch, host_eentry);
+       OFFSET(KVM_ARCH_GEENTRY, kvm_vcpu_arch, guest_eentry);
+       OFFSET(KVM_ARCH_GPC, kvm_vcpu_arch, pc);
+       OFFSET(KVM_ARCH_GGPR, kvm_vcpu_arch, gprs);
+       OFFSET(KVM_ARCH_HBADI, kvm_vcpu_arch, badi);
+       OFFSET(KVM_ARCH_HBADV, kvm_vcpu_arch, badv);
+       OFFSET(KVM_ARCH_HECFG, kvm_vcpu_arch, host_ecfg);
+       OFFSET(KVM_ARCH_HESTAT, kvm_vcpu_arch, host_estat);
+       OFFSET(KVM_ARCH_HPERCPU, kvm_vcpu_arch, host_percpu);
+
+       OFFSET(KVM_GPGD, kvm, arch.pgd);
+       BLANK();
+}
index 65518bb8f47285e406b95f8ba4c63a29e2c23a4a..1ec8e4c4cc2bd89d5af2492b0b31158ce8b53f9e 100644 (file)
@@ -18,7 +18,7 @@
        .text
        .cfi_sections   .debug_frame
        .align  5
-SYM_FUNC_START(handle_syscall)
+SYM_CODE_START(handle_syscall)
        csrrd           t0, PERCPU_BASE_KS
        la.pcrel        t1, kernelsp
        add.d           t1, t1, t0
@@ -71,7 +71,7 @@ SYM_FUNC_START(handle_syscall)
        bl              do_syscall
 
        RESTORE_ALL_AND_RET
-SYM_FUNC_END(handle_syscall)
+SYM_CODE_END(handle_syscall)
 _ASM_NOKPROBE(handle_syscall)
 
 SYM_CODE_START(ret_from_fork)
index 78f0663846575b584b4554f99e1d3436eea9acec..2bb3aa2dcfcb2e67935389d76585e813c7a6e169 100644 (file)
@@ -31,7 +31,7 @@ SYM_FUNC_START(__arch_cpu_idle)
 1:     jr      ra
 SYM_FUNC_END(__arch_cpu_idle)
 
-SYM_FUNC_START(handle_vint)
+SYM_CODE_START(handle_vint)
        BACKUP_T0T1
        SAVE_ALL
        la_abs  t1, __arch_cpu_idle
@@ -46,11 +46,11 @@ SYM_FUNC_START(handle_vint)
        la_abs  t0, do_vint
        jirl    ra, t0, 0
        RESTORE_ALL_AND_RET
-SYM_FUNC_END(handle_vint)
+SYM_CODE_END(handle_vint)
 
-SYM_FUNC_START(except_vec_cex)
+SYM_CODE_START(except_vec_cex)
        b       cache_parity_error
-SYM_FUNC_END(except_vec_cex)
+SYM_CODE_END(except_vec_cex)
 
        .macro  build_prep_badv
        csrrd   t0, LOONGARCH_CSR_BADV
@@ -66,7 +66,7 @@ SYM_FUNC_END(except_vec_cex)
 
        .macro  BUILD_HANDLER exception handler prep
        .align  5
-       SYM_FUNC_START(handle_\exception)
+       SYM_CODE_START(handle_\exception)
        666:
        BACKUP_T0T1
        SAVE_ALL
@@ -76,7 +76,7 @@ SYM_FUNC_END(except_vec_cex)
        jirl    ra, t0, 0
        668:
        RESTORE_ALL_AND_RET
-       SYM_FUNC_END(handle_\exception)
+       SYM_CODE_END(handle_\exception)
        SYM_DATA(unwind_hint_\exception, .word 668b - 666b)
        .endm
 
@@ -93,7 +93,7 @@ SYM_FUNC_END(except_vec_cex)
        BUILD_HANDLER watch watch none
        BUILD_HANDLER reserved reserved none    /* others */
 
-SYM_FUNC_START(handle_sys)
+SYM_CODE_START(handle_sys)
        la_abs  t0, handle_syscall
        jr      t0
-SYM_FUNC_END(handle_sys)
+SYM_CODE_END(handle_sys)
index 4a4107a6a9651535fc6cfb72f21cc1fb64f7eeed..aed901c57fb439493c560de777fbc86689f827ae 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 d4dbcda1c4b0a42a7d7de52fe9f457a22d4940cb..e2f30ff9afde825aea7f83bb529dc9e1cc5dd785 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 b8b86088b2dd2dbda770bfe30e6954b592d6c4ea..b13b2858fe392398823cb8f261665a964250a836 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 c7d33c489e048ccc0c5ec41b164b6b70c685e6d1..6e65ff12d5c7dc5062bc4d9bce24f4ef68f3b8da 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 3cb082e0c99298c44ebbf062a0e6d42be7073dc6..767d94cce0de07d74892733b339a55dd5e6ded0e 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 d13252553a7c7d6f7916fda58f7fcdc1d9bae126..f49f6b053763d1e729b68b870b1b64ffe09d4504 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 7783f0a3d742c7e0cce68d93cc9252eee4e7f381..aed65915e932e2963913ac2b4ada44102eed9e32 100644 (file)
@@ -161,19 +161,19 @@ static void __init smbios_parse(void)
 }
 
 #ifdef CONFIG_ARCH_WRITECOMBINE
-pgprot_t pgprot_wc = PAGE_KERNEL_WUC;
+bool wc_enabled = true;
 #else
-pgprot_t pgprot_wc = PAGE_KERNEL_SUC;
+bool wc_enabled = false;
 #endif
 
-EXPORT_SYMBOL(pgprot_wc);
+EXPORT_SYMBOL(wc_enabled);
 
 static int __init setup_writecombine(char *p)
 {
        if (!strcmp(p, "on"))
-               pgprot_wc = PAGE_KERNEL_WUC;
+               wc_enabled = true;
        else if (!strcmp(p, "off"))
-               pgprot_wc = PAGE_KERNEL_SUC;
+               wc_enabled = false;
        else
                pr_warn("Unknown writecombine setting \"%s\".\n", p);
 
index 504fdfe852030f54ca66a00fdde05abd4d577907..4a3686d133494921d64853e6c94b061dfe262bc0 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 6667b0a90f81de12e294d267c7f3f13c6e24fcdc..ef35c871244f0825e998359a3913318bfb872434 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 3fc4211db9895f71bc356b075fbb79f6779bbbe6..b4c5acd7aa3b324d133c0b5bd5e5169bfec5d4f7 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 c189e03cd5da84b6ebcde9533560d66f98010b5e..3064af94db9c2e14e953a4aad68c2a8d28588447 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 caa7cd8590788ca39cdc27205951bc1a368fcff7..3fd1660066983b247d1493864a9437e831282e3e 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 65214774ef7c6bade648ccf4f8702cdefc7baac1..aebfc3733a760713836fb5255045e1e9948ca5f4 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 b1686afcf876663c99e010c40ec84f44d8d55a88..bb2ec86f37a8eb636ef61cbcb9f86fd5869eef4c 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)
        }
diff --git a/arch/loongarch/kvm/Kconfig b/arch/loongarch/kvm/Kconfig
new file mode 100644 (file)
index 0000000..fda425b
--- /dev/null
@@ -0,0 +1,40 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# KVM configuration
+#
+
+source "virt/kvm/Kconfig"
+
+menuconfig VIRTUALIZATION
+       bool "Virtualization"
+       help
+         Say Y here to get to see options for using your Linux host to run
+         other operating systems inside virtual machines (guests).
+         This option alone does not add any kernel code.
+
+         If you say N, all options in this submenu will be skipped and
+         disabled.
+
+if VIRTUALIZATION
+
+config KVM
+       tristate "Kernel-based Virtual Machine (KVM) support"
+       depends on AS_HAS_LVZ_EXTENSION
+       depends on HAVE_KVM
+       select HAVE_KVM_DIRTY_RING_ACQ_REL
+       select HAVE_KVM_EVENTFD
+       select HAVE_KVM_VCPU_ASYNC_IOCTL
+       select KVM_GENERIC_DIRTYLOG_READ_PROTECT
+       select KVM_GENERIC_HARDWARE_ENABLING
+       select KVM_MMIO
+       select KVM_XFER_TO_GUEST_WORK
+       select MMU_NOTIFIER
+       select PREEMPT_NOTIFIERS
+       help
+         Support hosting virtualized guest machines using
+         hardware virtualization extensions. You will need
+         a processor equipped with virtualization extensions.
+
+         If unsure, say N.
+
+endif # VIRTUALIZATION
diff --git a/arch/loongarch/kvm/Makefile b/arch/loongarch/kvm/Makefile
new file mode 100644 (file)
index 0000000..244467d
--- /dev/null
@@ -0,0 +1,22 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for LoongArch KVM support
+#
+
+ccflags-y += -I $(srctree)/$(src)
+
+include $(srctree)/virt/kvm/Makefile.kvm
+
+obj-$(CONFIG_KVM) += kvm.o
+
+kvm-y += exit.o
+kvm-y += interrupt.o
+kvm-y += main.o
+kvm-y += mmu.o
+kvm-y += switch.o
+kvm-y += timer.o
+kvm-y += tlb.o
+kvm-y += vcpu.o
+kvm-y += vm.o
+
+CFLAGS_exit.o  += $(call cc-option,-Wno-override-init,)
diff --git a/arch/loongarch/kvm/exit.c b/arch/loongarch/kvm/exit.c
new file mode 100644 (file)
index 0000000..ce8de3f
--- /dev/null
@@ -0,0 +1,696 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
+ */
+
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/kvm_host.h>
+#include <linux/module.h>
+#include <linux/preempt.h>
+#include <linux/vmalloc.h>
+#include <asm/fpu.h>
+#include <asm/inst.h>
+#include <asm/loongarch.h>
+#include <asm/mmzone.h>
+#include <asm/numa.h>
+#include <asm/time.h>
+#include <asm/tlb.h>
+#include <asm/kvm_csr.h>
+#include <asm/kvm_vcpu.h>
+#include "trace.h"
+
+static unsigned long kvm_emu_read_csr(struct kvm_vcpu *vcpu, int csrid)
+{
+       unsigned long val = 0;
+       struct loongarch_csrs *csr = vcpu->arch.csr;
+
+       /*
+        * From LoongArch Reference Manual Volume 1 Chapter 4.2.1
+        * For undefined CSR id, return value is 0
+        */
+       if (get_gcsr_flag(csrid) & SW_GCSR)
+               val = kvm_read_sw_gcsr(csr, csrid);
+       else
+               pr_warn_once("Unsupported csrrd 0x%x with pc %lx\n", csrid, vcpu->arch.pc);
+
+       return val;
+}
+
+static unsigned long kvm_emu_write_csr(struct kvm_vcpu *vcpu, int csrid, unsigned long val)
+{
+       unsigned long old = 0;
+       struct loongarch_csrs *csr = vcpu->arch.csr;
+
+       if (get_gcsr_flag(csrid) & SW_GCSR) {
+               old = kvm_read_sw_gcsr(csr, csrid);
+               kvm_write_sw_gcsr(csr, csrid, val);
+       } else
+               pr_warn_once("Unsupported csrwr 0x%x with pc %lx\n", csrid, vcpu->arch.pc);
+
+       return old;
+}
+
+static unsigned long kvm_emu_xchg_csr(struct kvm_vcpu *vcpu, int csrid,
+                               unsigned long csr_mask, unsigned long val)
+{
+       unsigned long old = 0;
+       struct loongarch_csrs *csr = vcpu->arch.csr;
+
+       if (get_gcsr_flag(csrid) & SW_GCSR) {
+               old = kvm_read_sw_gcsr(csr, csrid);
+               val = (old & ~csr_mask) | (val & csr_mask);
+               kvm_write_sw_gcsr(csr, csrid, val);
+               old = old & csr_mask;
+       } else
+               pr_warn_once("Unsupported csrxchg 0x%x with pc %lx\n", csrid, vcpu->arch.pc);
+
+       return old;
+}
+
+static int kvm_handle_csr(struct kvm_vcpu *vcpu, larch_inst inst)
+{
+       unsigned int rd, rj, csrid;
+       unsigned long csr_mask, val = 0;
+
+       /*
+        * CSR value mask imm
+        * rj = 0 means csrrd
+        * rj = 1 means csrwr
+        * rj != 0,1 means csrxchg
+        */
+       rd = inst.reg2csr_format.rd;
+       rj = inst.reg2csr_format.rj;
+       csrid = inst.reg2csr_format.csr;
+
+       /* Process CSR ops */
+       switch (rj) {
+       case 0: /* process csrrd */
+               val = kvm_emu_read_csr(vcpu, csrid);
+               vcpu->arch.gprs[rd] = val;
+               break;
+       case 1: /* process csrwr */
+               val = vcpu->arch.gprs[rd];
+               val = kvm_emu_write_csr(vcpu, csrid, val);
+               vcpu->arch.gprs[rd] = val;
+               break;
+       default: /* process csrxchg */
+               val = vcpu->arch.gprs[rd];
+               csr_mask = vcpu->arch.gprs[rj];
+               val = kvm_emu_xchg_csr(vcpu, csrid, csr_mask, val);
+               vcpu->arch.gprs[rd] = val;
+       }
+
+       return EMULATE_DONE;
+}
+
+int kvm_emu_iocsr(larch_inst inst, struct kvm_run *run, struct kvm_vcpu *vcpu)
+{
+       int ret;
+       unsigned long val;
+       u32 addr, rd, rj, opcode;
+
+       /*
+        * Each IOCSR with different opcode
+        */
+       rd = inst.reg2_format.rd;
+       rj = inst.reg2_format.rj;
+       opcode = inst.reg2_format.opcode;
+       addr = vcpu->arch.gprs[rj];
+       ret = EMULATE_DO_IOCSR;
+       run->iocsr_io.phys_addr = addr;
+       run->iocsr_io.is_write = 0;
+
+       /* LoongArch is Little endian */
+       switch (opcode) {
+       case iocsrrdb_op:
+               run->iocsr_io.len = 1;
+               break;
+       case iocsrrdh_op:
+               run->iocsr_io.len = 2;
+               break;
+       case iocsrrdw_op:
+               run->iocsr_io.len = 4;
+               break;
+       case iocsrrdd_op:
+               run->iocsr_io.len = 8;
+               break;
+       case iocsrwrb_op:
+               run->iocsr_io.len = 1;
+               run->iocsr_io.is_write = 1;
+               break;
+       case iocsrwrh_op:
+               run->iocsr_io.len = 2;
+               run->iocsr_io.is_write = 1;
+               break;
+       case iocsrwrw_op:
+               run->iocsr_io.len = 4;
+               run->iocsr_io.is_write = 1;
+               break;
+       case iocsrwrd_op:
+               run->iocsr_io.len = 8;
+               run->iocsr_io.is_write = 1;
+               break;
+       default:
+               ret = EMULATE_FAIL;
+               break;
+       }
+
+       if (ret == EMULATE_DO_IOCSR) {
+               if (run->iocsr_io.is_write) {
+                       val = vcpu->arch.gprs[rd];
+                       memcpy(run->iocsr_io.data, &val, run->iocsr_io.len);
+               }
+               vcpu->arch.io_gpr = rd;
+       }
+
+       return ret;
+}
+
+int kvm_complete_iocsr_read(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+       enum emulation_result er = EMULATE_DONE;
+       unsigned long *gpr = &vcpu->arch.gprs[vcpu->arch.io_gpr];
+
+       switch (run->iocsr_io.len) {
+       case 1:
+               *gpr = *(s8 *)run->iocsr_io.data;
+               break;
+       case 2:
+               *gpr = *(s16 *)run->iocsr_io.data;
+               break;
+       case 4:
+               *gpr = *(s32 *)run->iocsr_io.data;
+               break;
+       case 8:
+               *gpr = *(s64 *)run->iocsr_io.data;
+               break;
+       default:
+               kvm_err("Bad IOCSR length: %d, addr is 0x%lx\n",
+                               run->iocsr_io.len, vcpu->arch.badv);
+               er = EMULATE_FAIL;
+               break;
+       }
+
+       return er;
+}
+
+int kvm_emu_idle(struct kvm_vcpu *vcpu)
+{
+       ++vcpu->stat.idle_exits;
+       trace_kvm_exit_idle(vcpu, KVM_TRACE_EXIT_IDLE);
+
+       if (!kvm_arch_vcpu_runnable(vcpu)) {
+               /*
+                * Switch to the software timer before halt-polling/blocking as
+                * the guest's timer may be a break event for the vCPU, and the
+                * hypervisor timer runs only when the CPU is in guest mode.
+                * Switch before halt-polling so that KVM recognizes an expired
+                * timer before blocking.
+                */
+               kvm_save_timer(vcpu);
+               kvm_vcpu_block(vcpu);
+       }
+
+       return EMULATE_DONE;
+}
+
+static int kvm_trap_handle_gspr(struct kvm_vcpu *vcpu)
+{
+       int rd, rj;
+       unsigned int index;
+       unsigned long curr_pc;
+       larch_inst inst;
+       enum emulation_result er = EMULATE_DONE;
+       struct kvm_run *run = vcpu->run;
+
+       /* Fetch the instruction */
+       inst.word = vcpu->arch.badi;
+       curr_pc = vcpu->arch.pc;
+       update_pc(&vcpu->arch);
+
+       trace_kvm_exit_gspr(vcpu, inst.word);
+       er = EMULATE_FAIL;
+       switch (((inst.word >> 24) & 0xff)) {
+       case 0x0: /* CPUCFG GSPR */
+               if (inst.reg2_format.opcode == 0x1B) {
+                       rd = inst.reg2_format.rd;
+                       rj = inst.reg2_format.rj;
+                       ++vcpu->stat.cpucfg_exits;
+                       index = vcpu->arch.gprs[rj];
+                       er = EMULATE_DONE;
+                       /*
+                        * By LoongArch Reference Manual 2.2.10.5
+                        * return value is 0 for undefined cpucfg index
+                        */
+                       if (index < KVM_MAX_CPUCFG_REGS)
+                               vcpu->arch.gprs[rd] = vcpu->arch.cpucfg[index];
+                       else
+                               vcpu->arch.gprs[rd] = 0;
+               }
+               break;
+       case 0x4: /* CSR{RD,WR,XCHG} GSPR */
+               er = kvm_handle_csr(vcpu, inst);
+               break;
+       case 0x6: /* Cache, Idle and IOCSR GSPR */
+               switch (((inst.word >> 22) & 0x3ff)) {
+               case 0x18: /* Cache GSPR */
+                       er = EMULATE_DONE;
+                       trace_kvm_exit_cache(vcpu, KVM_TRACE_EXIT_CACHE);
+                       break;
+               case 0x19: /* Idle/IOCSR GSPR */
+                       switch (((inst.word >> 15) & 0x1ffff)) {
+                       case 0xc90: /* IOCSR GSPR */
+                               er = kvm_emu_iocsr(inst, run, vcpu);
+                               break;
+                       case 0xc91: /* Idle GSPR */
+                               er = kvm_emu_idle(vcpu);
+                               break;
+                       default:
+                               er = EMULATE_FAIL;
+                               break;
+                       }
+                       break;
+               default:
+                       er = EMULATE_FAIL;
+                       break;
+               }
+               break;
+       default:
+               er = EMULATE_FAIL;
+               break;
+       }
+
+       /* Rollback PC only if emulation was unsuccessful */
+       if (er == EMULATE_FAIL) {
+               kvm_err("[%#lx]%s: unsupported gspr instruction 0x%08x\n",
+                       curr_pc, __func__, inst.word);
+
+               kvm_arch_vcpu_dump_regs(vcpu);
+               vcpu->arch.pc = curr_pc;
+       }
+
+       return er;
+}
+
+/*
+ * Trigger GSPR:
+ * 1) Execute CPUCFG instruction;
+ * 2) Execute CACOP/IDLE instructions;
+ * 3) Access to unimplemented CSRs/IOCSRs.
+ */
+static int kvm_handle_gspr(struct kvm_vcpu *vcpu)
+{
+       int ret = RESUME_GUEST;
+       enum emulation_result er = EMULATE_DONE;
+
+       er = kvm_trap_handle_gspr(vcpu);
+
+       if (er == EMULATE_DONE) {
+               ret = RESUME_GUEST;
+       } else if (er == EMULATE_DO_MMIO) {
+               vcpu->run->exit_reason = KVM_EXIT_MMIO;
+               ret = RESUME_HOST;
+       } else if (er == EMULATE_DO_IOCSR) {
+               vcpu->run->exit_reason = KVM_EXIT_LOONGARCH_IOCSR;
+               ret = RESUME_HOST;
+       } else {
+               kvm_queue_exception(vcpu, EXCCODE_INE, 0);
+               ret = RESUME_GUEST;
+       }
+
+       return ret;
+}
+
+int kvm_emu_mmio_read(struct kvm_vcpu *vcpu, larch_inst inst)
+{
+       int ret;
+       unsigned int op8, opcode, rd;
+       struct kvm_run *run = vcpu->run;
+
+       run->mmio.phys_addr = vcpu->arch.badv;
+       vcpu->mmio_needed = 2;  /* signed */
+       op8 = (inst.word >> 24) & 0xff;
+       ret = EMULATE_DO_MMIO;
+
+       switch (op8) {
+       case 0x24 ... 0x27:     /* ldptr.w/d process */
+               rd = inst.reg2i14_format.rd;
+               opcode = inst.reg2i14_format.opcode;
+
+               switch (opcode) {
+               case ldptrw_op:
+                       run->mmio.len = 4;
+                       break;
+               case ldptrd_op:
+                       run->mmio.len = 8;
+                       break;
+               default:
+                       break;
+               }
+               break;
+       case 0x28 ... 0x2e:     /* ld.b/h/w/d, ld.bu/hu/wu process */
+               rd = inst.reg2i12_format.rd;
+               opcode = inst.reg2i12_format.opcode;
+
+               switch (opcode) {
+               case ldb_op:
+                       run->mmio.len = 1;
+                       break;
+               case ldbu_op:
+                       vcpu->mmio_needed = 1;  /* unsigned */
+                       run->mmio.len = 1;
+                       break;
+               case ldh_op:
+                       run->mmio.len = 2;
+                       break;
+               case ldhu_op:
+                       vcpu->mmio_needed = 1;  /* unsigned */
+                       run->mmio.len = 2;
+                       break;
+               case ldw_op:
+                       run->mmio.len = 4;
+                       break;
+               case ldwu_op:
+                       vcpu->mmio_needed = 1;  /* unsigned */
+                       run->mmio.len = 4;
+                       break;
+               case ldd_op:
+                       run->mmio.len = 8;
+                       break;
+               default:
+                       ret = EMULATE_FAIL;
+                       break;
+               }
+               break;
+       case 0x38:      /* ldx.b/h/w/d, ldx.bu/hu/wu process */
+               rd = inst.reg3_format.rd;
+               opcode = inst.reg3_format.opcode;
+
+               switch (opcode) {
+               case ldxb_op:
+                       run->mmio.len = 1;
+                       break;
+               case ldxbu_op:
+                       run->mmio.len = 1;
+                       vcpu->mmio_needed = 1;  /* unsigned */
+                       break;
+               case ldxh_op:
+                       run->mmio.len = 2;
+                       break;
+               case ldxhu_op:
+                       run->mmio.len = 2;
+                       vcpu->mmio_needed = 1;  /* unsigned */
+                       break;
+               case ldxw_op:
+                       run->mmio.len = 4;
+                       break;
+               case ldxwu_op:
+                       run->mmio.len = 4;
+                       vcpu->mmio_needed = 1;  /* unsigned */
+                       break;
+               case ldxd_op:
+                       run->mmio.len = 8;
+                       break;
+               default:
+                       ret = EMULATE_FAIL;
+                       break;
+               }
+               break;
+       default:
+               ret = EMULATE_FAIL;
+       }
+
+       if (ret == EMULATE_DO_MMIO) {
+               /* Set for kvm_complete_mmio_read() use */
+               vcpu->arch.io_gpr = rd;
+               run->mmio.is_write = 0;
+               vcpu->mmio_is_write = 0;
+       } else {
+               kvm_err("Read not supported Inst=0x%08x @%lx BadVaddr:%#lx\n",
+                       inst.word, vcpu->arch.pc, vcpu->arch.badv);
+               kvm_arch_vcpu_dump_regs(vcpu);
+               vcpu->mmio_needed = 0;
+       }
+
+       return ret;
+}
+
+int kvm_complete_mmio_read(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+       enum emulation_result er = EMULATE_DONE;
+       unsigned long *gpr = &vcpu->arch.gprs[vcpu->arch.io_gpr];
+
+       /* Update with new PC */
+       update_pc(&vcpu->arch);
+       switch (run->mmio.len) {
+       case 1:
+               if (vcpu->mmio_needed == 2)
+                       *gpr = *(s8 *)run->mmio.data;
+               else
+                       *gpr = *(u8 *)run->mmio.data;
+               break;
+       case 2:
+               if (vcpu->mmio_needed == 2)
+                       *gpr = *(s16 *)run->mmio.data;
+               else
+                       *gpr = *(u16 *)run->mmio.data;
+               break;
+       case 4:
+               if (vcpu->mmio_needed == 2)
+                       *gpr = *(s32 *)run->mmio.data;
+               else
+                       *gpr = *(u32 *)run->mmio.data;
+               break;
+       case 8:
+               *gpr = *(s64 *)run->mmio.data;
+               break;
+       default:
+               kvm_err("Bad MMIO length: %d, addr is 0x%lx\n",
+                               run->mmio.len, vcpu->arch.badv);
+               er = EMULATE_FAIL;
+               break;
+       }
+
+       return er;
+}
+
+int kvm_emu_mmio_write(struct kvm_vcpu *vcpu, larch_inst inst)
+{
+       int ret;
+       unsigned int rd, op8, opcode;
+       unsigned long curr_pc, rd_val = 0;
+       struct kvm_run *run = vcpu->run;
+       void *data = run->mmio.data;
+
+       /*
+        * Update PC and hold onto current PC in case there is
+        * an error and we want to rollback the PC
+        */
+       curr_pc = vcpu->arch.pc;
+       update_pc(&vcpu->arch);
+
+       op8 = (inst.word >> 24) & 0xff;
+       run->mmio.phys_addr = vcpu->arch.badv;
+       ret = EMULATE_DO_MMIO;
+       switch (op8) {
+       case 0x24 ... 0x27:     /* stptr.w/d process */
+               rd = inst.reg2i14_format.rd;
+               opcode = inst.reg2i14_format.opcode;
+
+               switch (opcode) {
+               case stptrw_op:
+                       run->mmio.len = 4;
+                       *(unsigned int *)data = vcpu->arch.gprs[rd];
+                       break;
+               case stptrd_op:
+                       run->mmio.len = 8;
+                       *(unsigned long *)data = vcpu->arch.gprs[rd];
+                       break;
+               default:
+                       ret = EMULATE_FAIL;
+                       break;
+               }
+               break;
+       case 0x28 ... 0x2e:     /* st.b/h/w/d  process */
+               rd = inst.reg2i12_format.rd;
+               opcode = inst.reg2i12_format.opcode;
+               rd_val = vcpu->arch.gprs[rd];
+
+               switch (opcode) {
+               case stb_op:
+                       run->mmio.len = 1;
+                       *(unsigned char *)data = rd_val;
+                       break;
+               case sth_op:
+                       run->mmio.len = 2;
+                       *(unsigned short *)data = rd_val;
+                       break;
+               case stw_op:
+                       run->mmio.len = 4;
+                       *(unsigned int *)data = rd_val;
+                       break;
+               case std_op:
+                       run->mmio.len = 8;
+                       *(unsigned long *)data = rd_val;
+                       break;
+               default:
+                       ret = EMULATE_FAIL;
+                       break;
+               }
+               break;
+       case 0x38:      /* stx.b/h/w/d process */
+               rd = inst.reg3_format.rd;
+               opcode = inst.reg3_format.opcode;
+
+               switch (opcode) {
+               case stxb_op:
+                       run->mmio.len = 1;
+                       *(unsigned char *)data = vcpu->arch.gprs[rd];
+                       break;
+               case stxh_op:
+                       run->mmio.len = 2;
+                       *(unsigned short *)data = vcpu->arch.gprs[rd];
+                       break;
+               case stxw_op:
+                       run->mmio.len = 4;
+                       *(unsigned int *)data = vcpu->arch.gprs[rd];
+                       break;
+               case stxd_op:
+                       run->mmio.len = 8;
+                       *(unsigned long *)data = vcpu->arch.gprs[rd];
+                       break;
+               default:
+                       ret = EMULATE_FAIL;
+                       break;
+               }
+               break;
+       default:
+               ret = EMULATE_FAIL;
+       }
+
+       if (ret == EMULATE_DO_MMIO) {
+               run->mmio.is_write = 1;
+               vcpu->mmio_needed = 1;
+               vcpu->mmio_is_write = 1;
+       } else {
+               vcpu->arch.pc = curr_pc;
+               kvm_err("Write not supported Inst=0x%08x @%lx BadVaddr:%#lx\n",
+                       inst.word, vcpu->arch.pc, vcpu->arch.badv);
+               kvm_arch_vcpu_dump_regs(vcpu);
+               /* Rollback PC if emulation was unsuccessful */
+       }
+
+       return ret;
+}
+
+static int kvm_handle_rdwr_fault(struct kvm_vcpu *vcpu, bool write)
+{
+       int ret;
+       larch_inst inst;
+       enum emulation_result er = EMULATE_DONE;
+       struct kvm_run *run = vcpu->run;
+       unsigned long badv = vcpu->arch.badv;
+
+       ret = kvm_handle_mm_fault(vcpu, badv, write);
+       if (ret) {
+               /* Treat as MMIO */
+               inst.word = vcpu->arch.badi;
+               if (write) {
+                       er = kvm_emu_mmio_write(vcpu, inst);
+               } else {
+                       /* A code fetch fault doesn't count as an MMIO */
+                       if (kvm_is_ifetch_fault(&vcpu->arch)) {
+                               kvm_queue_exception(vcpu, EXCCODE_ADE, EXSUBCODE_ADEF);
+                               return RESUME_GUEST;
+                       }
+
+                       er = kvm_emu_mmio_read(vcpu, inst);
+               }
+       }
+
+       if (er == EMULATE_DONE) {
+               ret = RESUME_GUEST;
+       } else if (er == EMULATE_DO_MMIO) {
+               run->exit_reason = KVM_EXIT_MMIO;
+               ret = RESUME_HOST;
+       } else {
+               kvm_queue_exception(vcpu, EXCCODE_ADE, EXSUBCODE_ADEM);
+               ret = RESUME_GUEST;
+       }
+
+       return ret;
+}
+
+static int kvm_handle_read_fault(struct kvm_vcpu *vcpu)
+{
+       return kvm_handle_rdwr_fault(vcpu, false);
+}
+
+static int kvm_handle_write_fault(struct kvm_vcpu *vcpu)
+{
+       return kvm_handle_rdwr_fault(vcpu, true);
+}
+
+/**
+ * kvm_handle_fpu_disabled() - Guest used fpu however it is disabled at host
+ * @vcpu:      Virtual CPU context.
+ *
+ * Handle when the guest attempts to use fpu which hasn't been allowed
+ * by the root context.
+ */
+static int kvm_handle_fpu_disabled(struct kvm_vcpu *vcpu)
+{
+       struct kvm_run *run = vcpu->run;
+
+       /*
+        * If guest FPU not present, the FPU operation should have been
+        * treated as a reserved instruction!
+        * If FPU already in use, we shouldn't get this at all.
+        */
+       if (WARN_ON(vcpu->arch.aux_inuse & KVM_LARCH_FPU)) {
+               kvm_err("%s internal error\n", __func__);
+               run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
+               return RESUME_HOST;
+       }
+
+       kvm_own_fpu(vcpu);
+
+       return RESUME_GUEST;
+}
+
+/*
+ * LoongArch KVM callback handling for unimplemented guest exiting
+ */
+static int kvm_fault_ni(struct kvm_vcpu *vcpu)
+{
+       unsigned int ecode, inst;
+       unsigned long estat, badv;
+
+       /* Fetch the instruction */
+       inst = vcpu->arch.badi;
+       badv = vcpu->arch.badv;
+       estat = vcpu->arch.host_estat;
+       ecode = (estat & CSR_ESTAT_EXC) >> CSR_ESTAT_EXC_SHIFT;
+       kvm_err("ECode: %d PC=%#lx Inst=0x%08x BadVaddr=%#lx ESTAT=%#lx\n",
+                       ecode, vcpu->arch.pc, inst, badv, read_gcsr_estat());
+       kvm_arch_vcpu_dump_regs(vcpu);
+       kvm_queue_exception(vcpu, EXCCODE_INE, 0);
+
+       return RESUME_GUEST;
+}
+
+static exit_handle_fn kvm_fault_tables[EXCCODE_INT_START] = {
+       [0 ... EXCCODE_INT_START - 1]   = kvm_fault_ni,
+       [EXCCODE_TLBI]                  = kvm_handle_read_fault,
+       [EXCCODE_TLBL]                  = kvm_handle_read_fault,
+       [EXCCODE_TLBS]                  = kvm_handle_write_fault,
+       [EXCCODE_TLBM]                  = kvm_handle_write_fault,
+       [EXCCODE_FPDIS]                 = kvm_handle_fpu_disabled,
+       [EXCCODE_GSPR]                  = kvm_handle_gspr,
+};
+
+int kvm_handle_fault(struct kvm_vcpu *vcpu, int fault)
+{
+       return kvm_fault_tables[fault](vcpu);
+}
diff --git a/arch/loongarch/kvm/interrupt.c b/arch/loongarch/kvm/interrupt.c
new file mode 100644 (file)
index 0000000..4c3f22d
--- /dev/null
@@ -0,0 +1,183 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
+ */
+
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <asm/kvm_csr.h>
+#include <asm/kvm_vcpu.h>
+
+static unsigned int priority_to_irq[EXCCODE_INT_NUM] = {
+       [INT_TI]        = CPU_TIMER,
+       [INT_IPI]       = CPU_IPI,
+       [INT_SWI0]      = CPU_SIP0,
+       [INT_SWI1]      = CPU_SIP1,
+       [INT_HWI0]      = CPU_IP0,
+       [INT_HWI1]      = CPU_IP1,
+       [INT_HWI2]      = CPU_IP2,
+       [INT_HWI3]      = CPU_IP3,
+       [INT_HWI4]      = CPU_IP4,
+       [INT_HWI5]      = CPU_IP5,
+       [INT_HWI6]      = CPU_IP6,
+       [INT_HWI7]      = CPU_IP7,
+};
+
+static int kvm_irq_deliver(struct kvm_vcpu *vcpu, unsigned int priority)
+{
+       unsigned int irq = 0;
+
+       clear_bit(priority, &vcpu->arch.irq_pending);
+       if (priority < EXCCODE_INT_NUM)
+               irq = priority_to_irq[priority];
+
+       switch (priority) {
+       case INT_TI:
+       case INT_IPI:
+       case INT_SWI0:
+       case INT_SWI1:
+               set_gcsr_estat(irq);
+               break;
+
+       case INT_HWI0 ... INT_HWI7:
+               set_csr_gintc(irq);
+               break;
+
+       default:
+               break;
+       }
+
+       return 1;
+}
+
+static int kvm_irq_clear(struct kvm_vcpu *vcpu, unsigned int priority)
+{
+       unsigned int irq = 0;
+
+       clear_bit(priority, &vcpu->arch.irq_clear);
+       if (priority < EXCCODE_INT_NUM)
+               irq = priority_to_irq[priority];
+
+       switch (priority) {
+       case INT_TI:
+       case INT_IPI:
+       case INT_SWI0:
+       case INT_SWI1:
+               clear_gcsr_estat(irq);
+               break;
+
+       case INT_HWI0 ... INT_HWI7:
+               clear_csr_gintc(irq);
+               break;
+
+       default:
+               break;
+       }
+
+       return 1;
+}
+
+void kvm_deliver_intr(struct kvm_vcpu *vcpu)
+{
+       unsigned int priority;
+       unsigned long *pending = &vcpu->arch.irq_pending;
+       unsigned long *pending_clr = &vcpu->arch.irq_clear;
+
+       if (!(*pending) && !(*pending_clr))
+               return;
+
+       if (*pending_clr) {
+               priority = __ffs(*pending_clr);
+               while (priority <= INT_IPI) {
+                       kvm_irq_clear(vcpu, priority);
+                       priority = find_next_bit(pending_clr,
+                                       BITS_PER_BYTE * sizeof(*pending_clr),
+                                       priority + 1);
+               }
+       }
+
+       if (*pending) {
+               priority = __ffs(*pending);
+               while (priority <= INT_IPI) {
+                       kvm_irq_deliver(vcpu, priority);
+                       priority = find_next_bit(pending,
+                                       BITS_PER_BYTE * sizeof(*pending),
+                                       priority + 1);
+               }
+       }
+}
+
+int kvm_pending_timer(struct kvm_vcpu *vcpu)
+{
+       return test_bit(INT_TI, &vcpu->arch.irq_pending);
+}
+
+/*
+ * Only support illegal instruction or illegal Address Error exception,
+ * Other exceptions are injected by hardware in kvm mode
+ */
+static void _kvm_deliver_exception(struct kvm_vcpu *vcpu,
+                               unsigned int code, unsigned int subcode)
+{
+       unsigned long val, vec_size;
+
+       /*
+        * BADV is added for EXCCODE_ADE exception
+        *  Use PC register (GVA address) if it is instruction exeception
+        *  Else use BADV from host side (GPA address) for data exeception
+        */
+       if (code == EXCCODE_ADE) {
+               if (subcode == EXSUBCODE_ADEF)
+                       val = vcpu->arch.pc;
+               else
+                       val = vcpu->arch.badv;
+               kvm_write_hw_gcsr(LOONGARCH_CSR_BADV, val);
+       }
+
+       /* Set exception instruction */
+       kvm_write_hw_gcsr(LOONGARCH_CSR_BADI, vcpu->arch.badi);
+
+       /*
+        * Save CRMD in PRMD
+        * Set IRQ disabled and PLV0 with CRMD
+        */
+       val = kvm_read_hw_gcsr(LOONGARCH_CSR_CRMD);
+       kvm_write_hw_gcsr(LOONGARCH_CSR_PRMD, val);
+       val = val & ~(CSR_CRMD_PLV | CSR_CRMD_IE);
+       kvm_write_hw_gcsr(LOONGARCH_CSR_CRMD, val);
+
+       /* Set exception PC address */
+       kvm_write_hw_gcsr(LOONGARCH_CSR_ERA, vcpu->arch.pc);
+
+       /*
+        * Set exception code
+        * Exception and interrupt can be inject at the same time
+        * Hardware will handle exception first and then extern interrupt
+        * Exception code is Ecode in ESTAT[16:21]
+        * Interrupt code in ESTAT[0:12]
+        */
+       val = kvm_read_hw_gcsr(LOONGARCH_CSR_ESTAT);
+       val = (val & ~CSR_ESTAT_EXC) | code;
+       kvm_write_hw_gcsr(LOONGARCH_CSR_ESTAT, val);
+
+       /* Calculate expcetion entry address */
+       val = kvm_read_hw_gcsr(LOONGARCH_CSR_ECFG);
+       vec_size = (val & CSR_ECFG_VS) >> CSR_ECFG_VS_SHIFT;
+       if (vec_size)
+               vec_size = (1 << vec_size) * 4;
+       val =  kvm_read_hw_gcsr(LOONGARCH_CSR_EENTRY);
+       vcpu->arch.pc = val + code * vec_size;
+}
+
+void kvm_deliver_exception(struct kvm_vcpu *vcpu)
+{
+       unsigned int code;
+       unsigned long *pending = &vcpu->arch.exception_pending;
+
+       if (*pending) {
+               code = __ffs(*pending);
+               _kvm_deliver_exception(vcpu, code, vcpu->arch.esubcode);
+               *pending = 0;
+               vcpu->arch.esubcode = 0;
+       }
+}
diff --git a/arch/loongarch/kvm/main.c b/arch/loongarch/kvm/main.c
new file mode 100644 (file)
index 0000000..1c1d519
--- /dev/null
@@ -0,0 +1,420 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
+ */
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/kvm_host.h>
+#include <asm/cacheflush.h>
+#include <asm/cpufeature.h>
+#include <asm/kvm_csr.h>
+#include "trace.h"
+
+unsigned long vpid_mask;
+struct kvm_world_switch *kvm_loongarch_ops;
+static int gcsr_flag[CSR_MAX_NUMS];
+static struct kvm_context __percpu *vmcs;
+
+int get_gcsr_flag(int csr)
+{
+       if (csr < CSR_MAX_NUMS)
+               return gcsr_flag[csr];
+
+       return INVALID_GCSR;
+}
+
+static inline void set_gcsr_sw_flag(int csr)
+{
+       if (csr < CSR_MAX_NUMS)
+               gcsr_flag[csr] |= SW_GCSR;
+}
+
+static inline void set_gcsr_hw_flag(int csr)
+{
+       if (csr < CSR_MAX_NUMS)
+               gcsr_flag[csr] |= HW_GCSR;
+}
+
+/*
+ * The default value of gcsr_flag[CSR] is 0, and we use this
+ * function to set the flag to 1 (SW_GCSR) or 2 (HW_GCSR) if the
+ * gcsr is software or hardware. It will be used by get/set_gcsr,
+ * if gcsr_flag is HW we should use gcsrrd/gcsrwr to access it,
+ * else use software csr to emulate it.
+ */
+static void kvm_init_gcsr_flag(void)
+{
+       set_gcsr_hw_flag(LOONGARCH_CSR_CRMD);
+       set_gcsr_hw_flag(LOONGARCH_CSR_PRMD);
+       set_gcsr_hw_flag(LOONGARCH_CSR_EUEN);
+       set_gcsr_hw_flag(LOONGARCH_CSR_MISC);
+       set_gcsr_hw_flag(LOONGARCH_CSR_ECFG);
+       set_gcsr_hw_flag(LOONGARCH_CSR_ESTAT);
+       set_gcsr_hw_flag(LOONGARCH_CSR_ERA);
+       set_gcsr_hw_flag(LOONGARCH_CSR_BADV);
+       set_gcsr_hw_flag(LOONGARCH_CSR_BADI);
+       set_gcsr_hw_flag(LOONGARCH_CSR_EENTRY);
+       set_gcsr_hw_flag(LOONGARCH_CSR_TLBIDX);
+       set_gcsr_hw_flag(LOONGARCH_CSR_TLBEHI);
+       set_gcsr_hw_flag(LOONGARCH_CSR_TLBELO0);
+       set_gcsr_hw_flag(LOONGARCH_CSR_TLBELO1);
+       set_gcsr_hw_flag(LOONGARCH_CSR_ASID);
+       set_gcsr_hw_flag(LOONGARCH_CSR_PGDL);
+       set_gcsr_hw_flag(LOONGARCH_CSR_PGDH);
+       set_gcsr_hw_flag(LOONGARCH_CSR_PGD);
+       set_gcsr_hw_flag(LOONGARCH_CSR_PWCTL0);
+       set_gcsr_hw_flag(LOONGARCH_CSR_PWCTL1);
+       set_gcsr_hw_flag(LOONGARCH_CSR_STLBPGSIZE);
+       set_gcsr_hw_flag(LOONGARCH_CSR_RVACFG);
+       set_gcsr_hw_flag(LOONGARCH_CSR_CPUID);
+       set_gcsr_hw_flag(LOONGARCH_CSR_PRCFG1);
+       set_gcsr_hw_flag(LOONGARCH_CSR_PRCFG2);
+       set_gcsr_hw_flag(LOONGARCH_CSR_PRCFG3);
+       set_gcsr_hw_flag(LOONGARCH_CSR_KS0);
+       set_gcsr_hw_flag(LOONGARCH_CSR_KS1);
+       set_gcsr_hw_flag(LOONGARCH_CSR_KS2);
+       set_gcsr_hw_flag(LOONGARCH_CSR_KS3);
+       set_gcsr_hw_flag(LOONGARCH_CSR_KS4);
+       set_gcsr_hw_flag(LOONGARCH_CSR_KS5);
+       set_gcsr_hw_flag(LOONGARCH_CSR_KS6);
+       set_gcsr_hw_flag(LOONGARCH_CSR_KS7);
+       set_gcsr_hw_flag(LOONGARCH_CSR_TMID);
+       set_gcsr_hw_flag(LOONGARCH_CSR_TCFG);
+       set_gcsr_hw_flag(LOONGARCH_CSR_TVAL);
+       set_gcsr_hw_flag(LOONGARCH_CSR_TINTCLR);
+       set_gcsr_hw_flag(LOONGARCH_CSR_CNTC);
+       set_gcsr_hw_flag(LOONGARCH_CSR_LLBCTL);
+       set_gcsr_hw_flag(LOONGARCH_CSR_TLBRENTRY);
+       set_gcsr_hw_flag(LOONGARCH_CSR_TLBRBADV);
+       set_gcsr_hw_flag(LOONGARCH_CSR_TLBRERA);
+       set_gcsr_hw_flag(LOONGARCH_CSR_TLBRSAVE);
+       set_gcsr_hw_flag(LOONGARCH_CSR_TLBRELO0);
+       set_gcsr_hw_flag(LOONGARCH_CSR_TLBRELO1);
+       set_gcsr_hw_flag(LOONGARCH_CSR_TLBREHI);
+       set_gcsr_hw_flag(LOONGARCH_CSR_TLBRPRMD);
+       set_gcsr_hw_flag(LOONGARCH_CSR_DMWIN0);
+       set_gcsr_hw_flag(LOONGARCH_CSR_DMWIN1);
+       set_gcsr_hw_flag(LOONGARCH_CSR_DMWIN2);
+       set_gcsr_hw_flag(LOONGARCH_CSR_DMWIN3);
+
+       set_gcsr_sw_flag(LOONGARCH_CSR_IMPCTL1);
+       set_gcsr_sw_flag(LOONGARCH_CSR_IMPCTL2);
+       set_gcsr_sw_flag(LOONGARCH_CSR_MERRCTL);
+       set_gcsr_sw_flag(LOONGARCH_CSR_MERRINFO1);
+       set_gcsr_sw_flag(LOONGARCH_CSR_MERRINFO2);
+       set_gcsr_sw_flag(LOONGARCH_CSR_MERRENTRY);
+       set_gcsr_sw_flag(LOONGARCH_CSR_MERRERA);
+       set_gcsr_sw_flag(LOONGARCH_CSR_MERRSAVE);
+       set_gcsr_sw_flag(LOONGARCH_CSR_CTAG);
+       set_gcsr_sw_flag(LOONGARCH_CSR_DEBUG);
+       set_gcsr_sw_flag(LOONGARCH_CSR_DERA);
+       set_gcsr_sw_flag(LOONGARCH_CSR_DESAVE);
+
+       set_gcsr_sw_flag(LOONGARCH_CSR_FWPC);
+       set_gcsr_sw_flag(LOONGARCH_CSR_FWPS);
+       set_gcsr_sw_flag(LOONGARCH_CSR_MWPC);
+       set_gcsr_sw_flag(LOONGARCH_CSR_MWPS);
+
+       set_gcsr_sw_flag(LOONGARCH_CSR_DB0ADDR);
+       set_gcsr_sw_flag(LOONGARCH_CSR_DB0MASK);
+       set_gcsr_sw_flag(LOONGARCH_CSR_DB0CTRL);
+       set_gcsr_sw_flag(LOONGARCH_CSR_DB0ASID);
+       set_gcsr_sw_flag(LOONGARCH_CSR_DB1ADDR);
+       set_gcsr_sw_flag(LOONGARCH_CSR_DB1MASK);
+       set_gcsr_sw_flag(LOONGARCH_CSR_DB1CTRL);
+       set_gcsr_sw_flag(LOONGARCH_CSR_DB1ASID);
+       set_gcsr_sw_flag(LOONGARCH_CSR_DB2ADDR);
+       set_gcsr_sw_flag(LOONGARCH_CSR_DB2MASK);
+       set_gcsr_sw_flag(LOONGARCH_CSR_DB2CTRL);
+       set_gcsr_sw_flag(LOONGARCH_CSR_DB2ASID);
+       set_gcsr_sw_flag(LOONGARCH_CSR_DB3ADDR);
+       set_gcsr_sw_flag(LOONGARCH_CSR_DB3MASK);
+       set_gcsr_sw_flag(LOONGARCH_CSR_DB3CTRL);
+       set_gcsr_sw_flag(LOONGARCH_CSR_DB3ASID);
+       set_gcsr_sw_flag(LOONGARCH_CSR_DB4ADDR);
+       set_gcsr_sw_flag(LOONGARCH_CSR_DB4MASK);
+       set_gcsr_sw_flag(LOONGARCH_CSR_DB4CTRL);
+       set_gcsr_sw_flag(LOONGARCH_CSR_DB4ASID);
+       set_gcsr_sw_flag(LOONGARCH_CSR_DB5ADDR);
+       set_gcsr_sw_flag(LOONGARCH_CSR_DB5MASK);
+       set_gcsr_sw_flag(LOONGARCH_CSR_DB5CTRL);
+       set_gcsr_sw_flag(LOONGARCH_CSR_DB5ASID);
+       set_gcsr_sw_flag(LOONGARCH_CSR_DB6ADDR);
+       set_gcsr_sw_flag(LOONGARCH_CSR_DB6MASK);
+       set_gcsr_sw_flag(LOONGARCH_CSR_DB6CTRL);
+       set_gcsr_sw_flag(LOONGARCH_CSR_DB6ASID);
+       set_gcsr_sw_flag(LOONGARCH_CSR_DB7ADDR);
+       set_gcsr_sw_flag(LOONGARCH_CSR_DB7MASK);
+       set_gcsr_sw_flag(LOONGARCH_CSR_DB7CTRL);
+       set_gcsr_sw_flag(LOONGARCH_CSR_DB7ASID);
+
+       set_gcsr_sw_flag(LOONGARCH_CSR_IB0ADDR);
+       set_gcsr_sw_flag(LOONGARCH_CSR_IB0MASK);
+       set_gcsr_sw_flag(LOONGARCH_CSR_IB0CTRL);
+       set_gcsr_sw_flag(LOONGARCH_CSR_IB0ASID);
+       set_gcsr_sw_flag(LOONGARCH_CSR_IB1ADDR);
+       set_gcsr_sw_flag(LOONGARCH_CSR_IB1MASK);
+       set_gcsr_sw_flag(LOONGARCH_CSR_IB1CTRL);
+       set_gcsr_sw_flag(LOONGARCH_CSR_IB1ASID);
+       set_gcsr_sw_flag(LOONGARCH_CSR_IB2ADDR);
+       set_gcsr_sw_flag(LOONGARCH_CSR_IB2MASK);
+       set_gcsr_sw_flag(LOONGARCH_CSR_IB2CTRL);
+       set_gcsr_sw_flag(LOONGARCH_CSR_IB2ASID);
+       set_gcsr_sw_flag(LOONGARCH_CSR_IB3ADDR);
+       set_gcsr_sw_flag(LOONGARCH_CSR_IB3MASK);
+       set_gcsr_sw_flag(LOONGARCH_CSR_IB3CTRL);
+       set_gcsr_sw_flag(LOONGARCH_CSR_IB3ASID);
+       set_gcsr_sw_flag(LOONGARCH_CSR_IB4ADDR);
+       set_gcsr_sw_flag(LOONGARCH_CSR_IB4MASK);
+       set_gcsr_sw_flag(LOONGARCH_CSR_IB4CTRL);
+       set_gcsr_sw_flag(LOONGARCH_CSR_IB4ASID);
+       set_gcsr_sw_flag(LOONGARCH_CSR_IB5ADDR);
+       set_gcsr_sw_flag(LOONGARCH_CSR_IB5MASK);
+       set_gcsr_sw_flag(LOONGARCH_CSR_IB5CTRL);
+       set_gcsr_sw_flag(LOONGARCH_CSR_IB5ASID);
+       set_gcsr_sw_flag(LOONGARCH_CSR_IB6ADDR);
+       set_gcsr_sw_flag(LOONGARCH_CSR_IB6MASK);
+       set_gcsr_sw_flag(LOONGARCH_CSR_IB6CTRL);
+       set_gcsr_sw_flag(LOONGARCH_CSR_IB6ASID);
+       set_gcsr_sw_flag(LOONGARCH_CSR_IB7ADDR);
+       set_gcsr_sw_flag(LOONGARCH_CSR_IB7MASK);
+       set_gcsr_sw_flag(LOONGARCH_CSR_IB7CTRL);
+       set_gcsr_sw_flag(LOONGARCH_CSR_IB7ASID);
+
+       set_gcsr_sw_flag(LOONGARCH_CSR_PERFCTRL0);
+       set_gcsr_sw_flag(LOONGARCH_CSR_PERFCNTR0);
+       set_gcsr_sw_flag(LOONGARCH_CSR_PERFCTRL1);
+       set_gcsr_sw_flag(LOONGARCH_CSR_PERFCNTR1);
+       set_gcsr_sw_flag(LOONGARCH_CSR_PERFCTRL2);
+       set_gcsr_sw_flag(LOONGARCH_CSR_PERFCNTR2);
+       set_gcsr_sw_flag(LOONGARCH_CSR_PERFCTRL3);
+       set_gcsr_sw_flag(LOONGARCH_CSR_PERFCNTR3);
+}
+
+static void kvm_update_vpid(struct kvm_vcpu *vcpu, int cpu)
+{
+       unsigned long vpid;
+       struct kvm_context *context;
+
+       context = per_cpu_ptr(vcpu->kvm->arch.vmcs, cpu);
+       vpid = context->vpid_cache + 1;
+       if (!(vpid & vpid_mask)) {
+               /* finish round of vpid loop */
+               if (unlikely(!vpid))
+                       vpid = vpid_mask + 1;
+
+               ++vpid; /* vpid 0 reserved for root */
+
+               /* start new vpid cycle */
+               kvm_flush_tlb_all();
+       }
+
+       context->vpid_cache = vpid;
+       vcpu->arch.vpid = vpid;
+}
+
+void kvm_check_vpid(struct kvm_vcpu *vcpu)
+{
+       int cpu;
+       bool migrated;
+       unsigned long ver, old, vpid;
+       struct kvm_context *context;
+
+       cpu = smp_processor_id();
+       /*
+        * Are we entering guest context on a different CPU to last time?
+        * If so, the vCPU's guest TLB state on this CPU may be stale.
+        */
+       context = per_cpu_ptr(vcpu->kvm->arch.vmcs, cpu);
+       migrated = (vcpu->cpu != cpu);
+
+       /*
+        * Check if our vpid is of an older version
+        *
+        * We also discard the stored vpid if we've executed on
+        * another CPU, as the guest mappings may have changed without
+        * hypervisor knowledge.
+        */
+       ver = vcpu->arch.vpid & ~vpid_mask;
+       old = context->vpid_cache  & ~vpid_mask;
+       if (migrated || (ver != old)) {
+               kvm_update_vpid(vcpu, cpu);
+               trace_kvm_vpid_change(vcpu, vcpu->arch.vpid);
+               vcpu->cpu = cpu;
+       }
+
+       /* Restore GSTAT(0x50).vpid */
+       vpid = (vcpu->arch.vpid & vpid_mask) << CSR_GSTAT_GID_SHIFT;
+       change_csr_gstat(vpid_mask << CSR_GSTAT_GID_SHIFT, vpid);
+}
+
+void kvm_init_vmcs(struct kvm *kvm)
+{
+       kvm->arch.vmcs = vmcs;
+}
+
+long kvm_arch_dev_ioctl(struct file *filp,
+                       unsigned int ioctl, unsigned long arg)
+{
+       return -ENOIOCTLCMD;
+}
+
+int kvm_arch_hardware_enable(void)
+{
+       unsigned long env, gcfg = 0;
+
+       env = read_csr_gcfg();
+
+       /* First init gcfg, gstat, gintc, gtlbc. All guest use the same config */
+       write_csr_gcfg(0);
+       write_csr_gstat(0);
+       write_csr_gintc(0);
+       clear_csr_gtlbc(CSR_GTLBC_USETGID | CSR_GTLBC_TOTI);
+
+       /*
+        * Enable virtualization features granting guest direct control of
+        * certain features:
+        * GCI=2:       Trap on init or unimplement cache instruction.
+        * TORU=0:      Trap on Root Unimplement.
+        * CACTRL=1:    Root control cache.
+        * TOP=0:       Trap on Previlege.
+        * TOE=0:       Trap on Exception.
+        * TIT=0:       Trap on Timer.
+        */
+       if (env & CSR_GCFG_GCIP_ALL)
+               gcfg |= CSR_GCFG_GCI_SECURE;
+       if (env & CSR_GCFG_MATC_ROOT)
+               gcfg |= CSR_GCFG_MATC_ROOT;
+
+       gcfg |= CSR_GCFG_TIT;
+       write_csr_gcfg(gcfg);
+
+       kvm_flush_tlb_all();
+
+       /* Enable using TGID  */
+       set_csr_gtlbc(CSR_GTLBC_USETGID);
+       kvm_debug("GCFG:%lx GSTAT:%lx GINTC:%lx GTLBC:%lx",
+                 read_csr_gcfg(), read_csr_gstat(), read_csr_gintc(), read_csr_gtlbc());
+
+       return 0;
+}
+
+void kvm_arch_hardware_disable(void)
+{
+       write_csr_gcfg(0);
+       write_csr_gstat(0);
+       write_csr_gintc(0);
+       clear_csr_gtlbc(CSR_GTLBC_USETGID | CSR_GTLBC_TOTI);
+
+       /* Flush any remaining guest TLB entries */
+       kvm_flush_tlb_all();
+}
+
+static int kvm_loongarch_env_init(void)
+{
+       int cpu, order;
+       void *addr;
+       struct kvm_context *context;
+
+       vmcs = alloc_percpu(struct kvm_context);
+       if (!vmcs) {
+               pr_err("kvm: failed to allocate percpu kvm_context\n");
+               return -ENOMEM;
+       }
+
+       kvm_loongarch_ops = kzalloc(sizeof(*kvm_loongarch_ops), GFP_KERNEL);
+       if (!kvm_loongarch_ops) {
+               free_percpu(vmcs);
+               vmcs = NULL;
+               return -ENOMEM;
+       }
+
+       /*
+        * PGD register is shared between root kernel and kvm hypervisor.
+        * So world switch entry should be in DMW area rather than TLB area
+        * to avoid page fault reenter.
+        *
+        * In future if hardware pagetable walking is supported, we won't
+        * need to copy world switch code to DMW area.
+        */
+       order = get_order(kvm_exception_size + kvm_enter_guest_size);
+       addr = (void *)__get_free_pages(GFP_KERNEL, order);
+       if (!addr) {
+               free_percpu(vmcs);
+               vmcs = NULL;
+               kfree(kvm_loongarch_ops);
+               kvm_loongarch_ops = NULL;
+               return -ENOMEM;
+       }
+
+       memcpy(addr, kvm_exc_entry, kvm_exception_size);
+       memcpy(addr + kvm_exception_size, kvm_enter_guest, kvm_enter_guest_size);
+       flush_icache_range((unsigned long)addr, (unsigned long)addr + kvm_exception_size + kvm_enter_guest_size);
+       kvm_loongarch_ops->exc_entry = addr;
+       kvm_loongarch_ops->enter_guest = addr + kvm_exception_size;
+       kvm_loongarch_ops->page_order = order;
+
+       vpid_mask = read_csr_gstat();
+       vpid_mask = (vpid_mask & CSR_GSTAT_GIDBIT) >> CSR_GSTAT_GIDBIT_SHIFT;
+       if (vpid_mask)
+               vpid_mask = GENMASK(vpid_mask - 1, 0);
+
+       for_each_possible_cpu(cpu) {
+               context = per_cpu_ptr(vmcs, cpu);
+               context->vpid_cache = vpid_mask + 1;
+               context->last_vcpu = NULL;
+       }
+
+       kvm_init_gcsr_flag();
+
+       return 0;
+}
+
+static void kvm_loongarch_env_exit(void)
+{
+       unsigned long addr;
+
+       if (vmcs)
+               free_percpu(vmcs);
+
+       if (kvm_loongarch_ops) {
+               if (kvm_loongarch_ops->exc_entry) {
+                       addr = (unsigned long)kvm_loongarch_ops->exc_entry;
+                       free_pages(addr, kvm_loongarch_ops->page_order);
+               }
+               kfree(kvm_loongarch_ops);
+       }
+}
+
+static int kvm_loongarch_init(void)
+{
+       int r;
+
+       if (!cpu_has_lvz) {
+               kvm_info("Hardware virtualization not available\n");
+               return -ENODEV;
+       }
+       r = kvm_loongarch_env_init();
+       if (r)
+               return r;
+
+       return kvm_init(sizeof(struct kvm_vcpu), 0, THIS_MODULE);
+}
+
+static void kvm_loongarch_exit(void)
+{
+       kvm_exit();
+       kvm_loongarch_env_exit();
+}
+
+module_init(kvm_loongarch_init);
+module_exit(kvm_loongarch_exit);
+
+#ifdef MODULE
+static const struct cpu_feature kvm_feature[] = {
+       { .feature = cpu_feature(LOONGARCH_LVZ) },
+       {},
+};
+MODULE_DEVICE_TABLE(cpu, kvm_feature);
+#endif
diff --git a/arch/loongarch/kvm/mmu.c b/arch/loongarch/kvm/mmu.c
new file mode 100644 (file)
index 0000000..80480df
--- /dev/null
@@ -0,0 +1,914 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
+ */
+
+#include <linux/highmem.h>
+#include <linux/hugetlb.h>
+#include <linux/kvm_host.h>
+#include <linux/page-flags.h>
+#include <linux/uaccess.h>
+#include <asm/mmu_context.h>
+#include <asm/pgalloc.h>
+#include <asm/tlb.h>
+#include <asm/kvm_mmu.h>
+
+static inline void kvm_ptw_prepare(struct kvm *kvm, kvm_ptw_ctx *ctx)
+{
+       ctx->level = kvm->arch.root_level;
+       /* pte table */
+       ctx->invalid_ptes  = kvm->arch.invalid_ptes;
+       ctx->pte_shifts    = kvm->arch.pte_shifts;
+       ctx->pgtable_shift = ctx->pte_shifts[ctx->level];
+       ctx->invalid_entry = ctx->invalid_ptes[ctx->level];
+       ctx->opaque        = kvm;
+}
+
+/*
+ * Mark a range of guest physical address space old (all accesses fault) in the
+ * VM's GPA page table to allow detection of commonly used pages.
+ */
+static int kvm_mkold_pte(kvm_pte_t *pte, phys_addr_t addr, kvm_ptw_ctx *ctx)
+{
+       if (kvm_pte_young(*pte)) {
+               *pte = kvm_pte_mkold(*pte);
+               return 1;
+       }
+
+       return 0;
+}
+
+/*
+ * Mark a range of guest physical address space clean (writes fault) in the VM's
+ * GPA page table to allow dirty page tracking.
+ */
+static int kvm_mkclean_pte(kvm_pte_t *pte, phys_addr_t addr, kvm_ptw_ctx *ctx)
+{
+       gfn_t offset;
+       kvm_pte_t val;
+
+       val = *pte;
+       /*
+        * For kvm_arch_mmu_enable_log_dirty_pt_masked with mask, start and end
+        * may cross hugepage, for first huge page parameter addr is equal to
+        * start, however for the second huge page addr is base address of
+        * this huge page, rather than start or end address
+        */
+       if ((ctx->flag & _KVM_HAS_PGMASK) && !kvm_pte_huge(val)) {
+               offset = (addr >> PAGE_SHIFT) - ctx->gfn;
+               if (!(BIT(offset) & ctx->mask))
+                       return 0;
+       }
+
+       /*
+        * Need not split huge page now, just set write-proect pte bit
+        * Split huge page until next write fault
+        */
+       if (kvm_pte_dirty(val)) {
+               *pte = kvm_pte_mkclean(val);
+               return 1;
+       }
+
+       return 0;
+}
+
+/*
+ * Clear pte entry
+ */
+static int kvm_flush_pte(kvm_pte_t *pte, phys_addr_t addr, kvm_ptw_ctx *ctx)
+{
+       struct kvm *kvm;
+
+       kvm = ctx->opaque;
+       if (ctx->level)
+               kvm->stat.hugepages--;
+       else
+               kvm->stat.pages--;
+
+       *pte = ctx->invalid_entry;
+
+       return 1;
+}
+
+/*
+ * kvm_pgd_alloc() - Allocate and initialise a KVM GPA page directory.
+ *
+ * Allocate a blank KVM GPA page directory (PGD) for representing guest physical
+ * to host physical page mappings.
+ *
+ * Returns:    Pointer to new KVM GPA page directory.
+ *             NULL on allocation failure.
+ */
+kvm_pte_t *kvm_pgd_alloc(void)
+{
+       kvm_pte_t *pgd;
+
+       pgd = (kvm_pte_t *)__get_free_pages(GFP_KERNEL, 0);
+       if (pgd)
+               pgd_init((void *)pgd);
+
+       return pgd;
+}
+
+static void _kvm_pte_init(void *addr, unsigned long val)
+{
+       unsigned long *p, *end;
+
+       p = (unsigned long *)addr;
+       end = p + PTRS_PER_PTE;
+       do {
+               p[0] = val;
+               p[1] = val;
+               p[2] = val;
+               p[3] = val;
+               p[4] = val;
+               p += 8;
+               p[-3] = val;
+               p[-2] = val;
+               p[-1] = val;
+       } while (p != end);
+}
+
+/*
+ * Caller must hold kvm->mm_lock
+ *
+ * Walk the page tables of kvm to find the PTE corresponding to the
+ * address @addr. If page tables don't exist for @addr, they will be created
+ * from the MMU cache if @cache is not NULL.
+ */
+static kvm_pte_t *kvm_populate_gpa(struct kvm *kvm,
+                               struct kvm_mmu_memory_cache *cache,
+                               unsigned long addr, int level)
+{
+       kvm_ptw_ctx ctx;
+       kvm_pte_t *entry, *child;
+
+       kvm_ptw_prepare(kvm, &ctx);
+       child = kvm->arch.pgd;
+       while (ctx.level > level) {
+               entry = kvm_pgtable_offset(&ctx, child, addr);
+               if (kvm_pte_none(&ctx, entry)) {
+                       if (!cache)
+                               return NULL;
+
+                       child = kvm_mmu_memory_cache_alloc(cache);
+                       _kvm_pte_init(child, ctx.invalid_ptes[ctx.level - 1]);
+                       kvm_set_pte(entry, __pa(child));
+               } else if (kvm_pte_huge(*entry)) {
+                       return entry;
+               } else
+                       child = (kvm_pte_t *)__va(PHYSADDR(*entry));
+               kvm_ptw_enter(&ctx);
+       }
+
+       entry = kvm_pgtable_offset(&ctx, child, addr);
+
+       return entry;
+}
+
+/*
+ * Page walker for VM shadow mmu at last level
+ * The last level is small pte page or huge pmd page
+ */
+static int kvm_ptw_leaf(kvm_pte_t *dir, phys_addr_t addr, phys_addr_t end, kvm_ptw_ctx *ctx)
+{
+       int ret;
+       phys_addr_t next, start, size;
+       struct list_head *list;
+       kvm_pte_t *entry, *child;
+
+       ret = 0;
+       start = addr;
+       child = (kvm_pte_t *)__va(PHYSADDR(*dir));
+       entry = kvm_pgtable_offset(ctx, child, addr);
+       do {
+               next = addr + (0x1UL << ctx->pgtable_shift);
+               if (!kvm_pte_present(ctx, entry))
+                       continue;
+
+               ret |= ctx->ops(entry, addr, ctx);
+       } while (entry++, addr = next, addr < end);
+
+       if (kvm_need_flush(ctx)) {
+               size = 0x1UL << (ctx->pgtable_shift + PAGE_SHIFT - 3);
+               if (start + size == end) {
+                       list = (struct list_head *)child;
+                       list_add_tail(list, &ctx->list);
+                       *dir = ctx->invalid_ptes[ctx->level + 1];
+               }
+       }
+
+       return ret;
+}
+
+/*
+ * Page walker for VM shadow mmu at page table dir level
+ */
+static int kvm_ptw_dir(kvm_pte_t *dir, phys_addr_t addr, phys_addr_t end, kvm_ptw_ctx *ctx)
+{
+       int ret;
+       phys_addr_t next, start, size;
+       struct list_head *list;
+       kvm_pte_t *entry, *child;
+
+       ret = 0;
+       start = addr;
+       child = (kvm_pte_t *)__va(PHYSADDR(*dir));
+       entry = kvm_pgtable_offset(ctx, child, addr);
+       do {
+               next = kvm_pgtable_addr_end(ctx, addr, end);
+               if (!kvm_pte_present(ctx, entry))
+                       continue;
+
+               if (kvm_pte_huge(*entry)) {
+                       ret |= ctx->ops(entry, addr, ctx);
+                       continue;
+               }
+
+               kvm_ptw_enter(ctx);
+               if (ctx->level == 0)
+                       ret |= kvm_ptw_leaf(entry, addr, next, ctx);
+               else
+                       ret |= kvm_ptw_dir(entry, addr, next, ctx);
+               kvm_ptw_exit(ctx);
+       }  while (entry++, addr = next, addr < end);
+
+       if (kvm_need_flush(ctx)) {
+               size = 0x1UL << (ctx->pgtable_shift + PAGE_SHIFT - 3);
+               if (start + size == end) {
+                       list = (struct list_head *)child;
+                       list_add_tail(list, &ctx->list);
+                       *dir = ctx->invalid_ptes[ctx->level + 1];
+               }
+       }
+
+       return ret;
+}
+
+/*
+ * Page walker for VM shadow mmu at page root table
+ */
+static int kvm_ptw_top(kvm_pte_t *dir, phys_addr_t addr, phys_addr_t end, kvm_ptw_ctx *ctx)
+{
+       int ret;
+       phys_addr_t next;
+       kvm_pte_t *entry;
+
+       ret = 0;
+       entry = kvm_pgtable_offset(ctx, dir, addr);
+       do {
+               next = kvm_pgtable_addr_end(ctx, addr, end);
+               if (!kvm_pte_present(ctx, entry))
+                       continue;
+
+               kvm_ptw_enter(ctx);
+               ret |= kvm_ptw_dir(entry, addr, next, ctx);
+               kvm_ptw_exit(ctx);
+       }  while (entry++, addr = next, addr < end);
+
+       return ret;
+}
+
+/*
+ * kvm_flush_range() - Flush a range of guest physical addresses.
+ * @kvm:       KVM pointer.
+ * @start_gfn: Guest frame number of first page in GPA range to flush.
+ * @end_gfn:   Guest frame number of last page in GPA range to flush.
+ * @lock:      Whether to hold mmu_lock or not
+ *
+ * Flushes a range of GPA mappings from the GPA page tables.
+ */
+static void kvm_flush_range(struct kvm *kvm, gfn_t start_gfn, gfn_t end_gfn, int lock)
+{
+       int ret;
+       kvm_ptw_ctx ctx;
+       struct list_head *pos, *temp;
+
+       ctx.ops = kvm_flush_pte;
+       ctx.flag = _KVM_FLUSH_PGTABLE;
+       kvm_ptw_prepare(kvm, &ctx);
+       INIT_LIST_HEAD(&ctx.list);
+
+       if (lock) {
+               spin_lock(&kvm->mmu_lock);
+               ret = kvm_ptw_top(kvm->arch.pgd, start_gfn << PAGE_SHIFT,
+                                       end_gfn << PAGE_SHIFT, &ctx);
+               spin_unlock(&kvm->mmu_lock);
+       } else
+               ret = kvm_ptw_top(kvm->arch.pgd, start_gfn << PAGE_SHIFT,
+                                       end_gfn << PAGE_SHIFT, &ctx);
+
+       /* Flush vpid for each vCPU individually */
+       if (ret)
+               kvm_flush_remote_tlbs(kvm);
+
+       /*
+        * free pte table page after mmu_lock
+        * the pte table page is linked together with ctx.list
+        */
+       list_for_each_safe(pos, temp, &ctx.list) {
+               list_del(pos);
+               free_page((unsigned long)pos);
+       }
+}
+
+/*
+ * kvm_mkclean_gpa_pt() - Make a range of guest physical addresses clean.
+ * @kvm:       KVM pointer.
+ * @start_gfn: Guest frame number of first page in GPA range to flush.
+ * @end_gfn:   Guest frame number of last page in GPA range to flush.
+ *
+ * Make a range of GPA mappings clean so that guest writes will fault and
+ * trigger dirty page logging.
+ *
+ * The caller must hold the @kvm->mmu_lock spinlock.
+ *
+ * Returns:    Whether any GPA mappings were modified, which would require
+ *             derived mappings (GVA page tables & TLB enties) to be
+ *             invalidated.
+ */
+static int kvm_mkclean_gpa_pt(struct kvm *kvm, gfn_t start_gfn, gfn_t end_gfn)
+{
+       kvm_ptw_ctx ctx;
+
+       ctx.ops = kvm_mkclean_pte;
+       ctx.flag = 0;
+       kvm_ptw_prepare(kvm, &ctx);
+       return kvm_ptw_top(kvm->arch.pgd, start_gfn << PAGE_SHIFT, end_gfn << PAGE_SHIFT, &ctx);
+}
+
+/*
+ * kvm_arch_mmu_enable_log_dirty_pt_masked() - write protect dirty pages
+ * @kvm:       The KVM pointer
+ * @slot:      The memory slot associated with mask
+ * @gfn_offset:        The gfn offset in memory slot
+ * @mask:      The mask of dirty pages at offset 'gfn_offset' in this memory
+ *             slot to be write protected
+ *
+ * Walks bits set in mask write protects the associated pte's. Caller must
+ * acquire @kvm->mmu_lock.
+ */
+void kvm_arch_mmu_enable_log_dirty_pt_masked(struct kvm *kvm,
+               struct kvm_memory_slot *slot, gfn_t gfn_offset, unsigned long mask)
+{
+       kvm_ptw_ctx ctx;
+       gfn_t base_gfn = slot->base_gfn + gfn_offset;
+       gfn_t start = base_gfn + __ffs(mask);
+       gfn_t end = base_gfn + __fls(mask) + 1;
+
+       ctx.ops = kvm_mkclean_pte;
+       ctx.flag = _KVM_HAS_PGMASK;
+       ctx.mask = mask;
+       ctx.gfn = base_gfn;
+       kvm_ptw_prepare(kvm, &ctx);
+
+       kvm_ptw_top(kvm->arch.pgd, start << PAGE_SHIFT, end << PAGE_SHIFT, &ctx);
+}
+
+void kvm_arch_commit_memory_region(struct kvm *kvm,
+                                  struct kvm_memory_slot *old,
+                                  const struct kvm_memory_slot *new,
+                                  enum kvm_mr_change change)
+{
+       int needs_flush;
+
+       /*
+        * If dirty page logging is enabled, write protect all pages in the slot
+        * ready for dirty logging.
+        *
+        * There is no need to do this in any of the following cases:
+        * CREATE:      No dirty mappings will already exist.
+        * MOVE/DELETE: The old mappings will already have been cleaned up by
+        *              kvm_arch_flush_shadow_memslot()
+        */
+       if (change == KVM_MR_FLAGS_ONLY &&
+           (!(old->flags & KVM_MEM_LOG_DIRTY_PAGES) &&
+            new->flags & KVM_MEM_LOG_DIRTY_PAGES)) {
+               spin_lock(&kvm->mmu_lock);
+               /* Write protect GPA page table entries */
+               needs_flush = kvm_mkclean_gpa_pt(kvm, new->base_gfn,
+                                       new->base_gfn + new->npages);
+               spin_unlock(&kvm->mmu_lock);
+               if (needs_flush)
+                       kvm_flush_remote_tlbs(kvm);
+       }
+}
+
+void kvm_arch_flush_shadow_all(struct kvm *kvm)
+{
+       kvm_flush_range(kvm, 0, kvm->arch.gpa_size >> PAGE_SHIFT, 0);
+}
+
+void kvm_arch_flush_shadow_memslot(struct kvm *kvm, struct kvm_memory_slot *slot)
+{
+       /*
+        * The slot has been made invalid (ready for moving or deletion), so we
+        * need to ensure that it can no longer be accessed by any guest vCPUs.
+        */
+       kvm_flush_range(kvm, slot->base_gfn, slot->base_gfn + slot->npages, 1);
+}
+
+bool kvm_unmap_gfn_range(struct kvm *kvm, struct kvm_gfn_range *range)
+{
+       kvm_ptw_ctx ctx;
+
+       ctx.flag = 0;
+       ctx.ops = kvm_flush_pte;
+       kvm_ptw_prepare(kvm, &ctx);
+       INIT_LIST_HEAD(&ctx.list);
+
+       return kvm_ptw_top(kvm->arch.pgd, range->start << PAGE_SHIFT,
+                       range->end << PAGE_SHIFT, &ctx);
+}
+
+bool kvm_set_spte_gfn(struct kvm *kvm, struct kvm_gfn_range *range)
+{
+       unsigned long prot_bits;
+       kvm_pte_t *ptep;
+       kvm_pfn_t pfn = pte_pfn(range->arg.pte);
+       gpa_t gpa = range->start << PAGE_SHIFT;
+
+       ptep = kvm_populate_gpa(kvm, NULL, gpa, 0);
+       if (!ptep)
+               return false;
+
+       /* Replacing an absent or old page doesn't need flushes */
+       if (!kvm_pte_present(NULL, ptep) || !kvm_pte_young(*ptep)) {
+               kvm_set_pte(ptep, 0);
+               return false;
+       }
+
+       /* Fill new pte if write protected or page migrated */
+       prot_bits = _PAGE_PRESENT | __READABLE;
+       prot_bits |= _CACHE_MASK & pte_val(range->arg.pte);
+
+       /*
+        * Set _PAGE_WRITE or _PAGE_DIRTY iff old and new pte both support
+        * _PAGE_WRITE for map_page_fast if next page write fault
+        * _PAGE_DIRTY since gpa has already recorded as dirty page
+        */
+       prot_bits |= __WRITEABLE & *ptep & pte_val(range->arg.pte);
+       kvm_set_pte(ptep, kvm_pfn_pte(pfn, __pgprot(prot_bits)));
+
+       return true;
+}
+
+bool kvm_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range)
+{
+       kvm_ptw_ctx ctx;
+
+       ctx.flag = 0;
+       ctx.ops = kvm_mkold_pte;
+       kvm_ptw_prepare(kvm, &ctx);
+
+       return kvm_ptw_top(kvm->arch.pgd, range->start << PAGE_SHIFT,
+                               range->end << PAGE_SHIFT, &ctx);
+}
+
+bool kvm_test_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range)
+{
+       gpa_t gpa = range->start << PAGE_SHIFT;
+       kvm_pte_t *ptep = kvm_populate_gpa(kvm, NULL, gpa, 0);
+
+       if (ptep && kvm_pte_present(NULL, ptep) && kvm_pte_young(*ptep))
+               return true;
+
+       return false;
+}
+
+/*
+ * kvm_map_page_fast() - Fast path GPA fault handler.
+ * @vcpu:              vCPU pointer.
+ * @gpa:               Guest physical address of fault.
+ * @write:     Whether the fault was due to a write.
+ *
+ * Perform fast path GPA fault handling, doing all that can be done without
+ * calling into KVM. This handles marking old pages young (for idle page
+ * tracking), and dirtying of clean pages (for dirty page logging).
+ *
+ * Returns:    0 on success, in which case we can update derived mappings and
+ *             resume guest execution.
+ *             -EFAULT on failure due to absent GPA mapping or write to
+ *             read-only page, in which case KVM must be consulted.
+ */
+static int kvm_map_page_fast(struct kvm_vcpu *vcpu, unsigned long gpa, bool write)
+{
+       int ret = 0;
+       kvm_pfn_t pfn = 0;
+       kvm_pte_t *ptep, changed, new;
+       gfn_t gfn = gpa >> PAGE_SHIFT;
+       struct kvm *kvm = vcpu->kvm;
+       struct kvm_memory_slot *slot;
+
+       spin_lock(&kvm->mmu_lock);
+
+       /* Fast path - just check GPA page table for an existing entry */
+       ptep = kvm_populate_gpa(kvm, NULL, gpa, 0);
+       if (!ptep || !kvm_pte_present(NULL, ptep)) {
+               ret = -EFAULT;
+               goto out;
+       }
+
+       /* Track access to pages marked old */
+       new = *ptep;
+       if (!kvm_pte_young(new))
+               new = kvm_pte_mkyoung(new);
+               /* call kvm_set_pfn_accessed() after unlock */
+
+       if (write && !kvm_pte_dirty(new)) {
+               if (!kvm_pte_write(new)) {
+                       ret = -EFAULT;
+                       goto out;
+               }
+
+               if (kvm_pte_huge(new)) {
+                       /*
+                        * Do not set write permission when dirty logging is
+                        * enabled for HugePages
+                        */
+                       slot = gfn_to_memslot(kvm, gfn);
+                       if (kvm_slot_dirty_track_enabled(slot)) {
+                               ret = -EFAULT;
+                               goto out;
+                       }
+               }
+
+               /* Track dirtying of writeable pages */
+               new = kvm_pte_mkdirty(new);
+       }
+
+       changed = new ^ (*ptep);
+       if (changed) {
+               kvm_set_pte(ptep, new);
+               pfn = kvm_pte_pfn(new);
+       }
+       spin_unlock(&kvm->mmu_lock);
+
+       /*
+        * Fixme: pfn may be freed after mmu_lock
+        * kvm_try_get_pfn(pfn)/kvm_release_pfn pair to prevent this?
+        */
+       if (kvm_pte_young(changed))
+               kvm_set_pfn_accessed(pfn);
+
+       if (kvm_pte_dirty(changed)) {
+               mark_page_dirty(kvm, gfn);
+               kvm_set_pfn_dirty(pfn);
+       }
+       return ret;
+out:
+       spin_unlock(&kvm->mmu_lock);
+       return ret;
+}
+
+static bool fault_supports_huge_mapping(struct kvm_memory_slot *memslot,
+                               unsigned long hva, unsigned long map_size, bool write)
+{
+       size_t size;
+       gpa_t gpa_start;
+       hva_t uaddr_start, uaddr_end;
+
+       /* Disable dirty logging on HugePages */
+       if (kvm_slot_dirty_track_enabled(memslot) && write)
+               return false;
+
+       size = memslot->npages * PAGE_SIZE;
+       gpa_start = memslot->base_gfn << PAGE_SHIFT;
+       uaddr_start = memslot->userspace_addr;
+       uaddr_end = uaddr_start + size;
+
+       /*
+        * Pages belonging to memslots that don't have the same alignment
+        * within a PMD for userspace and GPA cannot be mapped with stage-2
+        * PMD entries, because we'll end up mapping the wrong pages.
+        *
+        * Consider a layout like the following:
+        *
+        *    memslot->userspace_addr:
+        *    +-----+--------------------+--------------------+---+
+        *    |abcde|fgh  Stage-1 block  |    Stage-1 block tv|xyz|
+        *    +-----+--------------------+--------------------+---+
+        *
+        *    memslot->base_gfn << PAGE_SIZE:
+        *      +---+--------------------+--------------------+-----+
+        *      |abc|def  Stage-2 block  |    Stage-2 block   |tvxyz|
+        *      +---+--------------------+--------------------+-----+
+        *
+        * If we create those stage-2 blocks, we'll end up with this incorrect
+        * mapping:
+        *   d -> f
+        *   e -> g
+        *   f -> h
+        */
+       if ((gpa_start & (map_size - 1)) != (uaddr_start & (map_size - 1)))
+               return false;
+
+       /*
+        * Next, let's make sure we're not trying to map anything not covered
+        * by the memslot. This means we have to prohibit block size mappings
+        * for the beginning and end of a non-block aligned and non-block sized
+        * memory slot (illustrated by the head and tail parts of the
+        * userspace view above containing pages 'abcde' and 'xyz',
+        * respectively).
+        *
+        * Note that it doesn't matter if we do the check using the
+        * userspace_addr or the base_gfn, as both are equally aligned (per
+        * the check above) and equally sized.
+        */
+       return (hva & ~(map_size - 1)) >= uaddr_start &&
+               (hva & ~(map_size - 1)) + map_size <= uaddr_end;
+}
+
+/*
+ * Lookup the mapping level for @gfn in the current mm.
+ *
+ * WARNING!  Use of host_pfn_mapping_level() requires the caller and the end
+ * consumer to be tied into KVM's handlers for MMU notifier events!
+ *
+ * There are several ways to safely use this helper:
+ *
+ * - Check mmu_invalidate_retry_hva() after grabbing the mapping level, before
+ *   consuming it.  In this case, mmu_lock doesn't need to be held during the
+ *   lookup, but it does need to be held while checking the MMU notifier.
+ *
+ * - Hold mmu_lock AND ensure there is no in-progress MMU notifier invalidation
+ *   event for the hva.  This can be done by explicit checking the MMU notifier
+ *   or by ensuring that KVM already has a valid mapping that covers the hva.
+ *
+ * - Do not use the result to install new mappings, e.g. use the host mapping
+ *   level only to decide whether or not to zap an entry.  In this case, it's
+ *   not required to hold mmu_lock (though it's highly likely the caller will
+ *   want to hold mmu_lock anyways, e.g. to modify SPTEs).
+ *
+ * Note!  The lookup can still race with modifications to host page tables, but
+ * the above "rules" ensure KVM will not _consume_ the result of the walk if a
+ * race with the primary MMU occurs.
+ */
+static int host_pfn_mapping_level(struct kvm *kvm, gfn_t gfn,
+                               const struct kvm_memory_slot *slot)
+{
+       int level = 0;
+       unsigned long hva;
+       unsigned long flags;
+       pgd_t pgd;
+       p4d_t p4d;
+       pud_t pud;
+       pmd_t pmd;
+
+       /*
+        * Note, using the already-retrieved memslot and __gfn_to_hva_memslot()
+        * is not solely for performance, it's also necessary to avoid the
+        * "writable" check in __gfn_to_hva_many(), which will always fail on
+        * read-only memslots due to gfn_to_hva() assuming writes.  Earlier
+        * page fault steps have already verified the guest isn't writing a
+        * read-only memslot.
+        */
+       hva = __gfn_to_hva_memslot(slot, gfn);
+
+       /*
+        * Disable IRQs to prevent concurrent tear down of host page tables,
+        * e.g. if the primary MMU promotes a P*D to a huge page and then frees
+        * the original page table.
+        */
+       local_irq_save(flags);
+
+       /*
+        * Read each entry once.  As above, a non-leaf entry can be promoted to
+        * a huge page _during_ this walk.  Re-reading the entry could send the
+        * walk into the weeks, e.g. p*d_large() returns false (sees the old
+        * value) and then p*d_offset() walks into the target huge page instead
+        * of the old page table (sees the new value).
+        */
+       pgd = READ_ONCE(*pgd_offset(kvm->mm, hva));
+       if (pgd_none(pgd))
+               goto out;
+
+       p4d = READ_ONCE(*p4d_offset(&pgd, hva));
+       if (p4d_none(p4d) || !p4d_present(p4d))
+               goto out;
+
+       pud = READ_ONCE(*pud_offset(&p4d, hva));
+       if (pud_none(pud) || !pud_present(pud))
+               goto out;
+
+       pmd = READ_ONCE(*pmd_offset(&pud, hva));
+       if (pmd_none(pmd) || !pmd_present(pmd))
+               goto out;
+
+       if (kvm_pte_huge(pmd_val(pmd)))
+               level = 1;
+
+out:
+       local_irq_restore(flags);
+       return level;
+}
+
+/*
+ * Split huge page
+ */
+static kvm_pte_t *kvm_split_huge(struct kvm_vcpu *vcpu, kvm_pte_t *ptep, gfn_t gfn)
+{
+       int i;
+       kvm_pte_t val, *child;
+       struct kvm *kvm = vcpu->kvm;
+       struct kvm_mmu_memory_cache *memcache;
+
+       memcache = &vcpu->arch.mmu_page_cache;
+       child = kvm_mmu_memory_cache_alloc(memcache);
+       val = kvm_pte_mksmall(*ptep);
+       for (i = 0; i < PTRS_PER_PTE; i++) {
+               kvm_set_pte(child + i, val);
+               val += PAGE_SIZE;
+       }
+
+       /* The later kvm_flush_tlb_gpa() will flush hugepage tlb */
+       kvm_set_pte(ptep, __pa(child));
+
+       kvm->stat.hugepages--;
+       kvm->stat.pages += PTRS_PER_PTE;
+
+       return child + (gfn & (PTRS_PER_PTE - 1));
+}
+
+/*
+ * kvm_map_page() - Map a guest physical page.
+ * @vcpu:              vCPU pointer.
+ * @gpa:               Guest physical address of fault.
+ * @write:     Whether the fault was due to a write.
+ *
+ * Handle GPA faults by creating a new GPA mapping (or updating an existing
+ * one).
+ *
+ * This takes care of marking pages young or dirty (idle/dirty page tracking),
+ * asking KVM for the corresponding PFN, and creating a mapping in the GPA page
+ * tables. Derived mappings (GVA page tables and TLBs) must be handled by the
+ * caller.
+ *
+ * Returns:    0 on success
+ *             -EFAULT if there is no memory region at @gpa or a write was
+ *             attempted to a read-only memory region. This is usually handled
+ *             as an MMIO access.
+ */
+static int kvm_map_page(struct kvm_vcpu *vcpu, unsigned long gpa, bool write)
+{
+       bool writeable;
+       int srcu_idx, err, retry_no = 0, level;
+       unsigned long hva, mmu_seq, prot_bits;
+       kvm_pfn_t pfn;
+       kvm_pte_t *ptep, new_pte;
+       gfn_t gfn = gpa >> PAGE_SHIFT;
+       struct kvm *kvm = vcpu->kvm;
+       struct kvm_memory_slot *memslot;
+       struct kvm_mmu_memory_cache *memcache = &vcpu->arch.mmu_page_cache;
+
+       /* Try the fast path to handle old / clean pages */
+       srcu_idx = srcu_read_lock(&kvm->srcu);
+       err = kvm_map_page_fast(vcpu, gpa, write);
+       if (!err)
+               goto out;
+
+       memslot = gfn_to_memslot(kvm, gfn);
+       hva = gfn_to_hva_memslot_prot(memslot, gfn, &writeable);
+       if (kvm_is_error_hva(hva) || (write && !writeable)) {
+               err = -EFAULT;
+               goto out;
+       }
+
+       /* We need a minimum of cached pages ready for page table creation */
+       err = kvm_mmu_topup_memory_cache(memcache, KVM_MMU_CACHE_MIN_PAGES);
+       if (err)
+               goto out;
+
+retry:
+       /*
+        * Used to check for invalidations in progress, of the pfn that is
+        * returned by pfn_to_pfn_prot below.
+        */
+       mmu_seq = kvm->mmu_invalidate_seq;
+       /*
+        * Ensure the read of mmu_invalidate_seq isn't reordered with PTE reads in
+        * gfn_to_pfn_prot() (which calls get_user_pages()), so that we don't
+        * risk the page we get a reference to getting unmapped before we have a
+        * chance to grab the mmu_lock without mmu_invalidate_retry() noticing.
+        *
+        * This smp_rmb() pairs with the effective smp_wmb() of the combination
+        * of the pte_unmap_unlock() after the PTE is zapped, and the
+        * spin_lock() in kvm_mmu_invalidate_invalidate_<page|range_end>() before
+        * mmu_invalidate_seq is incremented.
+        */
+       smp_rmb();
+
+       /* Slow path - ask KVM core whether we can access this GPA */
+       pfn = gfn_to_pfn_prot(kvm, gfn, write, &writeable);
+       if (is_error_noslot_pfn(pfn)) {
+               err = -EFAULT;
+               goto out;
+       }
+
+       /* Check if an invalidation has taken place since we got pfn */
+       spin_lock(&kvm->mmu_lock);
+       if (mmu_invalidate_retry_hva(kvm, mmu_seq, hva)) {
+               /*
+                * This can happen when mappings are changed asynchronously, but
+                * also synchronously if a COW is triggered by
+                * gfn_to_pfn_prot().
+                */
+               spin_unlock(&kvm->mmu_lock);
+               kvm_release_pfn_clean(pfn);
+               if (retry_no > 100) {
+                       retry_no = 0;
+                       schedule();
+               }
+               retry_no++;
+               goto retry;
+       }
+
+       /*
+        * For emulated devices such virtio device, actual cache attribute is
+        * determined by physical machine.
+        * For pass through physical device, it should be uncachable
+        */
+       prot_bits = _PAGE_PRESENT | __READABLE;
+       if (pfn_valid(pfn))
+               prot_bits |= _CACHE_CC;
+       else
+               prot_bits |= _CACHE_SUC;
+
+       if (writeable) {
+               prot_bits |= _PAGE_WRITE;
+               if (write)
+                       prot_bits |= __WRITEABLE;
+       }
+
+       /* Disable dirty logging on HugePages */
+       level = 0;
+       if (!fault_supports_huge_mapping(memslot, hva, PMD_SIZE, write)) {
+               level = 0;
+       } else {
+               level = host_pfn_mapping_level(kvm, gfn, memslot);
+               if (level == 1) {
+                       gfn = gfn & ~(PTRS_PER_PTE - 1);
+                       pfn = pfn & ~(PTRS_PER_PTE - 1);
+               }
+       }
+
+       /* Ensure page tables are allocated */
+       ptep = kvm_populate_gpa(kvm, memcache, gpa, level);
+       new_pte = kvm_pfn_pte(pfn, __pgprot(prot_bits));
+       if (level == 1) {
+               new_pte = kvm_pte_mkhuge(new_pte);
+               /*
+                * previous pmd entry is invalid_pte_table
+                * there is invalid tlb with small page
+                * need flush these invalid tlbs for current vcpu
+                */
+               kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu);
+               ++kvm->stat.hugepages;
+       }  else if (kvm_pte_huge(*ptep) && write)
+               ptep = kvm_split_huge(vcpu, ptep, gfn);
+       else
+               ++kvm->stat.pages;
+       kvm_set_pte(ptep, new_pte);
+       spin_unlock(&kvm->mmu_lock);
+
+       if (prot_bits & _PAGE_DIRTY) {
+               mark_page_dirty_in_slot(kvm, memslot, gfn);
+               kvm_set_pfn_dirty(pfn);
+       }
+
+       kvm_set_pfn_accessed(pfn);
+       kvm_release_pfn_clean(pfn);
+out:
+       srcu_read_unlock(&kvm->srcu, srcu_idx);
+       return err;
+}
+
+int kvm_handle_mm_fault(struct kvm_vcpu *vcpu, unsigned long gpa, bool write)
+{
+       int ret;
+
+       ret = kvm_map_page(vcpu, gpa, write);
+       if (ret)
+               return ret;
+
+       /* Invalidate this entry in the TLB */
+       kvm_flush_tlb_gpa(vcpu, gpa);
+
+       return 0;
+}
+
+void kvm_arch_sync_dirty_log(struct kvm *kvm, struct kvm_memory_slot *memslot)
+{
+}
+
+int kvm_arch_prepare_memory_region(struct kvm *kvm, const struct kvm_memory_slot *old,
+                                  struct kvm_memory_slot *new, enum kvm_mr_change change)
+{
+       return 0;
+}
+
+void kvm_arch_flush_remote_tlbs_memslot(struct kvm *kvm,
+                                       const struct kvm_memory_slot *memslot)
+{
+       kvm_flush_remote_tlbs(kvm);
+}
diff --git a/arch/loongarch/kvm/switch.S b/arch/loongarch/kvm/switch.S
new file mode 100644 (file)
index 0000000..0ed9040
--- /dev/null
@@ -0,0 +1,250 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
+ */
+
+#include <linux/linkage.h>
+#include <asm/asm.h>
+#include <asm/asmmacro.h>
+#include <asm/loongarch.h>
+#include <asm/regdef.h>
+#include <asm/stackframe.h>
+
+#define HGPR_OFFSET(x)         (PT_R0 + 8*x)
+#define GGPR_OFFSET(x)         (KVM_ARCH_GGPR + 8*x)
+
+.macro kvm_save_host_gpr base
+       .irp n,1,2,3,22,23,24,25,26,27,28,29,30,31
+       st.d    $r\n, \base, HGPR_OFFSET(\n)
+       .endr
+.endm
+
+.macro kvm_restore_host_gpr base
+       .irp n,1,2,3,22,23,24,25,26,27,28,29,30,31
+       ld.d    $r\n, \base, HGPR_OFFSET(\n)
+       .endr
+.endm
+
+/*
+ * Save and restore all GPRs except base register,
+ * and default value of base register is a2.
+ */
+.macro kvm_save_guest_gprs base
+       .irp n,1,2,3,4,5,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
+       st.d    $r\n, \base, GGPR_OFFSET(\n)
+       .endr
+.endm
+
+.macro kvm_restore_guest_gprs base
+       .irp n,1,2,3,4,5,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
+       ld.d    $r\n, \base, GGPR_OFFSET(\n)
+       .endr
+.endm
+
+/*
+ * Prepare switch to guest, save host regs and restore guest regs.
+ * a2: kvm_vcpu_arch, don't touch it until 'ertn'
+ * t0, t1: temp register
+ */
+.macro kvm_switch_to_guest
+       /* Set host ECFG.VS=0, all exceptions share one exception entry */
+       csrrd           t0, LOONGARCH_CSR_ECFG
+       bstrins.w       t0, zero, CSR_ECFG_VS_SHIFT_END, CSR_ECFG_VS_SHIFT
+       csrwr           t0, LOONGARCH_CSR_ECFG
+
+       /* Load up the new EENTRY */
+       ld.d    t0, a2, KVM_ARCH_GEENTRY
+       csrwr   t0, LOONGARCH_CSR_EENTRY
+
+       /* Set Guest ERA */
+       ld.d    t0, a2, KVM_ARCH_GPC
+       csrwr   t0, LOONGARCH_CSR_ERA
+
+       /* Save host PGDL */
+       csrrd   t0, LOONGARCH_CSR_PGDL
+       st.d    t0, a2, KVM_ARCH_HPGD
+
+       /* Switch to kvm */
+       ld.d    t1, a2, KVM_VCPU_KVM - KVM_VCPU_ARCH
+
+       /* Load guest PGDL */
+       li.w    t0, KVM_GPGD
+       ldx.d   t0, t1, t0
+       csrwr   t0, LOONGARCH_CSR_PGDL
+
+       /* Mix GID and RID */
+       csrrd           t1, LOONGARCH_CSR_GSTAT
+       bstrpick.w      t1, t1, CSR_GSTAT_GID_SHIFT_END, CSR_GSTAT_GID_SHIFT
+       csrrd           t0, LOONGARCH_CSR_GTLBC
+       bstrins.w       t0, t1, CSR_GTLBC_TGID_SHIFT_END, CSR_GTLBC_TGID_SHIFT
+       csrwr           t0, LOONGARCH_CSR_GTLBC
+
+       /*
+        * Enable intr in root mode with future ertn so that host interrupt
+        * can be responsed during VM runs
+        * Guest CRMD comes from separate GCSR_CRMD register
+        */
+       ori     t0, zero, CSR_PRMD_PIE
+       csrxchg t0, t0,   LOONGARCH_CSR_PRMD
+
+       /* Set PVM bit to setup ertn to guest context */
+       ori     t0, zero, CSR_GSTAT_PVM
+       csrxchg t0, t0,   LOONGARCH_CSR_GSTAT
+
+       /* Load Guest GPRs */
+       kvm_restore_guest_gprs a2
+       /* Load KVM_ARCH register */
+       ld.d    a2, a2, (KVM_ARCH_GGPR + 8 * REG_A2)
+
+       ertn /* Switch to guest: GSTAT.PGM = 1, ERRCTL.ISERR = 0, TLBRPRMD.ISTLBR = 0 */
+.endm
+
+       /*
+        * Exception entry for general exception from guest mode
+        *  - IRQ is disabled
+        *  - kernel privilege in root mode
+        *  - page mode keep unchanged from previous PRMD in root mode
+        *  - Fixme: tlb exception cannot happen since registers relative with TLB
+        *  -        is still in guest mode, such as pgd table/vmid registers etc,
+        *  -        will fix with hw page walk enabled in future
+        * load kvm_vcpu from reserved CSR KVM_VCPU_KS, and save a2 to KVM_TEMP_KS
+        */
+       .text
+       .cfi_sections   .debug_frame
+SYM_CODE_START(kvm_exc_entry)
+       csrwr   a2,   KVM_TEMP_KS
+       csrrd   a2,   KVM_VCPU_KS
+       addi.d  a2,   a2, KVM_VCPU_ARCH
+
+       /* After save GPRs, free to use any GPR */
+       kvm_save_guest_gprs a2
+       /* Save guest A2 */
+       csrrd   t0,     KVM_TEMP_KS
+       st.d    t0,     a2,     (KVM_ARCH_GGPR + 8 * REG_A2)
+
+       /* A2 is kvm_vcpu_arch, A1 is free to use */
+       csrrd   s1,   KVM_VCPU_KS
+       ld.d    s0,   s1, KVM_VCPU_RUN
+
+       csrrd   t0,   LOONGARCH_CSR_ESTAT
+       st.d    t0,   a2, KVM_ARCH_HESTAT
+       csrrd   t0,   LOONGARCH_CSR_ERA
+       st.d    t0,   a2, KVM_ARCH_GPC
+       csrrd   t0,   LOONGARCH_CSR_BADV
+       st.d    t0,   a2, KVM_ARCH_HBADV
+       csrrd   t0,   LOONGARCH_CSR_BADI
+       st.d    t0,   a2, KVM_ARCH_HBADI
+
+       /* Restore host ECFG.VS */
+       csrrd   t0, LOONGARCH_CSR_ECFG
+       ld.d    t1, a2, KVM_ARCH_HECFG
+       or      t0, t0, t1
+       csrwr   t0, LOONGARCH_CSR_ECFG
+
+       /* Restore host EENTRY */
+       ld.d    t0, a2, KVM_ARCH_HEENTRY
+       csrwr   t0, LOONGARCH_CSR_EENTRY
+
+       /* Restore host pgd table */
+       ld.d    t0, a2, KVM_ARCH_HPGD
+       csrwr   t0, LOONGARCH_CSR_PGDL
+
+       /*
+        * Disable PGM bit to enter root mode by default with next ertn
+        */
+       ori     t0, zero, CSR_GSTAT_PVM
+       csrxchg zero, t0, LOONGARCH_CSR_GSTAT
+
+       /*
+        * Clear GTLBC.TGID field
+        *       0: for root  tlb update in future tlb instr
+        *  others: for guest tlb update like gpa to hpa in future tlb instr
+        */
+       csrrd   t0, LOONGARCH_CSR_GTLBC
+       bstrins.w       t0, zero, CSR_GTLBC_TGID_SHIFT_END, CSR_GTLBC_TGID_SHIFT
+       csrwr   t0, LOONGARCH_CSR_GTLBC
+       ld.d    tp, a2, KVM_ARCH_HTP
+       ld.d    sp, a2, KVM_ARCH_HSP
+       /* restore per cpu register */
+       ld.d    u0, a2, KVM_ARCH_HPERCPU
+       addi.d  sp, sp, -PT_SIZE
+
+       /* Prepare handle exception */
+       or      a0, s0, zero
+       or      a1, s1, zero
+       ld.d    t8, a2, KVM_ARCH_HANDLE_EXIT
+       jirl    ra, t8, 0
+
+       or      a2, s1, zero
+       addi.d  a2, a2, KVM_VCPU_ARCH
+
+       /* Resume host when ret <= 0 */
+       blez    a0, ret_to_host
+
+       /*
+         * Return to guest
+         * Save per cpu register again, maybe switched to another cpu
+         */
+       st.d    u0, a2, KVM_ARCH_HPERCPU
+
+       /* Save kvm_vcpu to kscratch */
+       csrwr   s1, KVM_VCPU_KS
+       kvm_switch_to_guest
+
+ret_to_host:
+       ld.d    a2, a2, KVM_ARCH_HSP
+       addi.d  a2, a2, -PT_SIZE
+       kvm_restore_host_gpr    a2
+       jr      ra
+
+SYM_INNER_LABEL(kvm_exc_entry_end, SYM_L_LOCAL)
+SYM_CODE_END(kvm_exc_entry)
+
+/*
+ * int kvm_enter_guest(struct kvm_run *run, struct kvm_vcpu *vcpu)
+ *
+ * @register_param:
+ *  a0: kvm_run* run
+ *  a1: kvm_vcpu* vcpu
+ */
+SYM_FUNC_START(kvm_enter_guest)
+       /* Allocate space in stack bottom */
+       addi.d  a2, sp, -PT_SIZE
+       /* Save host GPRs */
+       kvm_save_host_gpr a2
+
+       /* Save host CRMD, PRMD to stack */
+       csrrd   a3, LOONGARCH_CSR_CRMD
+       st.d    a3, a2, PT_CRMD
+       csrrd   a3, LOONGARCH_CSR_PRMD
+       st.d    a3, a2, PT_PRMD
+
+       addi.d  a2, a1, KVM_VCPU_ARCH
+       st.d    sp, a2, KVM_ARCH_HSP
+       st.d    tp, a2, KVM_ARCH_HTP
+       /* Save per cpu register */
+       st.d    u0, a2, KVM_ARCH_HPERCPU
+
+       /* Save kvm_vcpu to kscratch */
+       csrwr   a1, KVM_VCPU_KS
+       kvm_switch_to_guest
+SYM_INNER_LABEL(kvm_enter_guest_end, SYM_L_LOCAL)
+SYM_FUNC_END(kvm_enter_guest)
+
+SYM_FUNC_START(kvm_save_fpu)
+       fpu_save_csr    a0 t1
+       fpu_save_double a0 t1
+       fpu_save_cc     a0 t1 t2
+       jr              ra
+SYM_FUNC_END(kvm_save_fpu)
+
+SYM_FUNC_START(kvm_restore_fpu)
+       fpu_restore_double a0 t1
+       fpu_restore_csr    a0 t1 t2
+       fpu_restore_cc     a0 t1 t2
+       jr                 ra
+SYM_FUNC_END(kvm_restore_fpu)
+
+       .section ".rodata"
+SYM_DATA(kvm_exception_size, .quad kvm_exc_entry_end - kvm_exc_entry)
+SYM_DATA(kvm_enter_guest_size, .quad kvm_enter_guest_end - kvm_enter_guest)
diff --git a/arch/loongarch/kvm/timer.c b/arch/loongarch/kvm/timer.c
new file mode 100644 (file)
index 0000000..284bf55
--- /dev/null
@@ -0,0 +1,197 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
+ */
+
+#include <linux/kvm_host.h>
+#include <asm/kvm_csr.h>
+#include <asm/kvm_vcpu.h>
+
+/*
+ * ktime_to_tick() - Scale ktime_t to timer tick value.
+ */
+static inline u64 ktime_to_tick(struct kvm_vcpu *vcpu, ktime_t now)
+{
+       u64 delta;
+
+       delta = ktime_to_ns(now);
+       return div_u64(delta * vcpu->arch.timer_mhz, MNSEC_PER_SEC);
+}
+
+static inline u64 tick_to_ns(struct kvm_vcpu *vcpu, u64 tick)
+{
+       return div_u64(tick * MNSEC_PER_SEC, vcpu->arch.timer_mhz);
+}
+
+/*
+ * Push timer forward on timeout.
+ * Handle an hrtimer event by push the hrtimer forward a period.
+ */
+static enum hrtimer_restart kvm_count_timeout(struct kvm_vcpu *vcpu)
+{
+       unsigned long cfg, period;
+
+       /* Add periodic tick to current expire time */
+       cfg = kvm_read_sw_gcsr(vcpu->arch.csr, LOONGARCH_CSR_TCFG);
+       if (cfg & CSR_TCFG_PERIOD) {
+               period = tick_to_ns(vcpu, cfg & CSR_TCFG_VAL);
+               hrtimer_add_expires_ns(&vcpu->arch.swtimer, period);
+               return HRTIMER_RESTART;
+       } else
+               return HRTIMER_NORESTART;
+}
+
+/* Low level hrtimer wake routine */
+enum hrtimer_restart kvm_swtimer_wakeup(struct hrtimer *timer)
+{
+       struct kvm_vcpu *vcpu;
+
+       vcpu = container_of(timer, struct kvm_vcpu, arch.swtimer);
+       kvm_queue_irq(vcpu, INT_TI);
+       rcuwait_wake_up(&vcpu->wait);
+
+       return kvm_count_timeout(vcpu);
+}
+
+/*
+ * Initialise the timer to the specified frequency, zero it
+ */
+void kvm_init_timer(struct kvm_vcpu *vcpu, unsigned long timer_hz)
+{
+       vcpu->arch.timer_mhz = timer_hz >> 20;
+
+       /* Starting at 0 */
+       kvm_write_sw_gcsr(vcpu->arch.csr, LOONGARCH_CSR_TVAL, 0);
+}
+
+/*
+ * Restore hard timer state and enable guest to access timer registers
+ * without trap, should be called with irq disabled
+ */
+void kvm_acquire_timer(struct kvm_vcpu *vcpu)
+{
+       unsigned long cfg;
+
+       cfg = read_csr_gcfg();
+       if (!(cfg & CSR_GCFG_TIT))
+               return;
+
+       /* Enable guest access to hard timer */
+       write_csr_gcfg(cfg & ~CSR_GCFG_TIT);
+
+       /*
+        * Freeze the soft-timer and sync the guest stable timer with it. We do
+        * this with interrupts disabled to avoid latency.
+        */
+       hrtimer_cancel(&vcpu->arch.swtimer);
+}
+
+/*
+ * Restore soft timer state from saved context.
+ */
+void kvm_restore_timer(struct kvm_vcpu *vcpu)
+{
+       unsigned long cfg, delta, period;
+       ktime_t expire, now;
+       struct loongarch_csrs *csr = vcpu->arch.csr;
+
+       /*
+        * Set guest stable timer cfg csr
+        */
+       cfg = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_TCFG);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_ESTAT);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TCFG);
+       if (!(cfg & CSR_TCFG_EN)) {
+               /* Guest timer is disabled, just restore timer registers */
+               kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TVAL);
+               return;
+       }
+
+       /*
+        * Set remainder tick value if not expired
+        */
+       now = ktime_get();
+       expire = vcpu->arch.expire;
+       if (ktime_before(now, expire))
+               delta = ktime_to_tick(vcpu, ktime_sub(expire, now));
+       else {
+               if (cfg & CSR_TCFG_PERIOD) {
+                       period = cfg & CSR_TCFG_VAL;
+                       delta = ktime_to_tick(vcpu, ktime_sub(now, expire));
+                       delta = period - (delta % period);
+               } else
+                       delta = 0;
+               /*
+                * Inject timer here though sw timer should inject timer
+                * interrupt async already, since sw timer may be cancelled
+                * during injecting intr async in function kvm_acquire_timer
+                */
+               kvm_queue_irq(vcpu, INT_TI);
+       }
+
+       write_gcsr_timertick(delta);
+}
+
+/*
+ * Save guest timer state and switch to software emulation of guest
+ * timer. The hard timer must already be in use, so preemption should be
+ * disabled.
+ */
+static void _kvm_save_timer(struct kvm_vcpu *vcpu)
+{
+       unsigned long ticks, delta;
+       ktime_t expire;
+       struct loongarch_csrs *csr = vcpu->arch.csr;
+
+       ticks = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_TVAL);
+       delta = tick_to_ns(vcpu, ticks);
+       expire = ktime_add_ns(ktime_get(), delta);
+       vcpu->arch.expire = expire;
+       if (ticks) {
+               /*
+                * Update hrtimer to use new timeout
+                * HRTIMER_MODE_PINNED is suggested since vcpu may run in
+                * the same physical cpu in next time
+                */
+               hrtimer_cancel(&vcpu->arch.swtimer);
+               hrtimer_start(&vcpu->arch.swtimer, expire, HRTIMER_MODE_ABS_PINNED);
+       } else
+               /*
+                * Inject timer interrupt so that hall polling can dectect and exit
+                */
+               kvm_queue_irq(vcpu, INT_TI);
+}
+
+/*
+ * Save guest timer state and switch to soft guest timer if hard timer was in
+ * use.
+ */
+void kvm_save_timer(struct kvm_vcpu *vcpu)
+{
+       unsigned long cfg;
+       struct loongarch_csrs *csr = vcpu->arch.csr;
+
+       preempt_disable();
+       cfg = read_csr_gcfg();
+       if (!(cfg & CSR_GCFG_TIT)) {
+               /* Disable guest use of hard timer */
+               write_csr_gcfg(cfg | CSR_GCFG_TIT);
+
+               /* Save hard timer state */
+               kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TCFG);
+               kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TVAL);
+               if (kvm_read_sw_gcsr(csr, LOONGARCH_CSR_TCFG) & CSR_TCFG_EN)
+                       _kvm_save_timer(vcpu);
+       }
+
+       /* Save timer-related state to vCPU context */
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_ESTAT);
+       preempt_enable();
+}
+
+void kvm_reset_timer(struct kvm_vcpu *vcpu)
+{
+       write_gcsr_timercfg(0);
+       kvm_write_sw_gcsr(vcpu->arch.csr, LOONGARCH_CSR_TCFG, 0);
+       hrtimer_cancel(&vcpu->arch.swtimer);
+}
diff --git a/arch/loongarch/kvm/tlb.c b/arch/loongarch/kvm/tlb.c
new file mode 100644 (file)
index 0000000..02535df
--- /dev/null
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
+ */
+
+#include <linux/kvm_host.h>
+#include <asm/tlb.h>
+#include <asm/kvm_csr.h>
+
+/*
+ * kvm_flush_tlb_all() - Flush all root TLB entries for guests.
+ *
+ * Invalidate all entries including GVA-->GPA and GPA-->HPA mappings.
+ */
+void kvm_flush_tlb_all(void)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       invtlb_all(INVTLB_ALLGID, 0, 0);
+       local_irq_restore(flags);
+}
+
+void kvm_flush_tlb_gpa(struct kvm_vcpu *vcpu, unsigned long gpa)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       gpa &= (PAGE_MASK << 1);
+       invtlb(INVTLB_GID_ADDR, read_csr_gstat() & CSR_GSTAT_GID, gpa);
+       local_irq_restore(flags);
+}
diff --git a/arch/loongarch/kvm/trace.h b/arch/loongarch/kvm/trace.h
new file mode 100644 (file)
index 0000000..a1e35d6
--- /dev/null
@@ -0,0 +1,162 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
+ */
+
+#if !defined(_TRACE_KVM_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_KVM_H
+
+#include <linux/tracepoint.h>
+#include <asm/kvm_csr.h>
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM   kvm
+
+/*
+ * Tracepoints for VM enters
+ */
+DECLARE_EVENT_CLASS(kvm_transition,
+       TP_PROTO(struct kvm_vcpu *vcpu),
+       TP_ARGS(vcpu),
+       TP_STRUCT__entry(
+               __field(unsigned long, pc)
+       ),
+
+       TP_fast_assign(
+               __entry->pc = vcpu->arch.pc;
+       ),
+
+       TP_printk("PC: 0x%08lx", __entry->pc)
+);
+
+DEFINE_EVENT(kvm_transition, kvm_enter,
+            TP_PROTO(struct kvm_vcpu *vcpu),
+            TP_ARGS(vcpu));
+
+DEFINE_EVENT(kvm_transition, kvm_reenter,
+            TP_PROTO(struct kvm_vcpu *vcpu),
+            TP_ARGS(vcpu));
+
+DEFINE_EVENT(kvm_transition, kvm_out,
+            TP_PROTO(struct kvm_vcpu *vcpu),
+            TP_ARGS(vcpu));
+
+/* Further exit reasons */
+#define KVM_TRACE_EXIT_IDLE            64
+#define KVM_TRACE_EXIT_CACHE           65
+
+/* Tracepoints for VM exits */
+#define kvm_trace_symbol_exit_types                    \
+       { KVM_TRACE_EXIT_IDLE,          "IDLE" },       \
+       { KVM_TRACE_EXIT_CACHE,         "CACHE" }
+
+DECLARE_EVENT_CLASS(kvm_exit,
+           TP_PROTO(struct kvm_vcpu *vcpu, unsigned int reason),
+           TP_ARGS(vcpu, reason),
+           TP_STRUCT__entry(
+                       __field(unsigned long, pc)
+                       __field(unsigned int, reason)
+           ),
+
+           TP_fast_assign(
+                       __entry->pc = vcpu->arch.pc;
+                       __entry->reason = reason;
+           ),
+
+           TP_printk("[%s]PC: 0x%08lx",
+                     __print_symbolic(__entry->reason,
+                                      kvm_trace_symbol_exit_types),
+                     __entry->pc)
+);
+
+DEFINE_EVENT(kvm_exit, kvm_exit_idle,
+            TP_PROTO(struct kvm_vcpu *vcpu, unsigned int reason),
+            TP_ARGS(vcpu, reason));
+
+DEFINE_EVENT(kvm_exit, kvm_exit_cache,
+            TP_PROTO(struct kvm_vcpu *vcpu, unsigned int reason),
+            TP_ARGS(vcpu, reason));
+
+DEFINE_EVENT(kvm_exit, kvm_exit,
+            TP_PROTO(struct kvm_vcpu *vcpu, unsigned int reason),
+            TP_ARGS(vcpu, reason));
+
+TRACE_EVENT(kvm_exit_gspr,
+           TP_PROTO(struct kvm_vcpu *vcpu, unsigned int inst_word),
+           TP_ARGS(vcpu, inst_word),
+           TP_STRUCT__entry(
+                       __field(unsigned int, inst_word)
+           ),
+
+           TP_fast_assign(
+                       __entry->inst_word = inst_word;
+           ),
+
+           TP_printk("Inst word: 0x%08x", __entry->inst_word)
+);
+
+#define KVM_TRACE_AUX_SAVE             0
+#define KVM_TRACE_AUX_RESTORE          1
+#define KVM_TRACE_AUX_ENABLE           2
+#define KVM_TRACE_AUX_DISABLE          3
+#define KVM_TRACE_AUX_DISCARD          4
+
+#define KVM_TRACE_AUX_FPU              1
+
+#define kvm_trace_symbol_aux_op                                \
+       { KVM_TRACE_AUX_SAVE,           "save" },       \
+       { KVM_TRACE_AUX_RESTORE,        "restore" },    \
+       { KVM_TRACE_AUX_ENABLE,         "enable" },     \
+       { KVM_TRACE_AUX_DISABLE,        "disable" },    \
+       { KVM_TRACE_AUX_DISCARD,        "discard" }
+
+#define kvm_trace_symbol_aux_state                     \
+       { KVM_TRACE_AUX_FPU,     "FPU" }
+
+TRACE_EVENT(kvm_aux,
+           TP_PROTO(struct kvm_vcpu *vcpu, unsigned int op,
+                    unsigned int state),
+           TP_ARGS(vcpu, op, state),
+           TP_STRUCT__entry(
+                       __field(unsigned long, pc)
+                       __field(u8, op)
+                       __field(u8, state)
+           ),
+
+           TP_fast_assign(
+                       __entry->pc = vcpu->arch.pc;
+                       __entry->op = op;
+                       __entry->state = state;
+           ),
+
+           TP_printk("%s %s PC: 0x%08lx",
+                     __print_symbolic(__entry->op,
+                                      kvm_trace_symbol_aux_op),
+                     __print_symbolic(__entry->state,
+                                      kvm_trace_symbol_aux_state),
+                     __entry->pc)
+);
+
+TRACE_EVENT(kvm_vpid_change,
+           TP_PROTO(struct kvm_vcpu *vcpu, unsigned long vpid),
+           TP_ARGS(vcpu, vpid),
+           TP_STRUCT__entry(
+                       __field(unsigned long, vpid)
+           ),
+
+           TP_fast_assign(
+                       __entry->vpid = vpid;
+           ),
+
+           TP_printk("VPID: 0x%08lx", __entry->vpid)
+);
+
+#endif /* _TRACE_KVM_H */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH ../../arch/loongarch/kvm
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c
new file mode 100644 (file)
index 0000000..73d0c2b
--- /dev/null
@@ -0,0 +1,939 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
+ */
+
+#include <linux/kvm_host.h>
+#include <linux/entry-kvm.h>
+#include <asm/fpu.h>
+#include <asm/loongarch.h>
+#include <asm/setup.h>
+#include <asm/time.h>
+
+#define CREATE_TRACE_POINTS
+#include "trace.h"
+
+const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
+       KVM_GENERIC_VCPU_STATS(),
+       STATS_DESC_COUNTER(VCPU, int_exits),
+       STATS_DESC_COUNTER(VCPU, idle_exits),
+       STATS_DESC_COUNTER(VCPU, cpucfg_exits),
+       STATS_DESC_COUNTER(VCPU, signal_exits),
+};
+
+const struct kvm_stats_header kvm_vcpu_stats_header = {
+       .name_size = KVM_STATS_NAME_SIZE,
+       .num_desc = ARRAY_SIZE(kvm_vcpu_stats_desc),
+       .id_offset = sizeof(struct kvm_stats_header),
+       .desc_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE,
+       .data_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE +
+                      sizeof(kvm_vcpu_stats_desc),
+};
+
+/*
+ * kvm_check_requests - check and handle pending vCPU requests
+ *
+ * Return: RESUME_GUEST if we should enter the guest
+ *         RESUME_HOST  if we should exit to userspace
+ */
+static int kvm_check_requests(struct kvm_vcpu *vcpu)
+{
+       if (!kvm_request_pending(vcpu))
+               return RESUME_GUEST;
+
+       if (kvm_check_request(KVM_REQ_TLB_FLUSH, vcpu))
+               vcpu->arch.vpid = 0;  /* Drop vpid for this vCPU */
+
+       if (kvm_dirty_ring_check_request(vcpu))
+               return RESUME_HOST;
+
+       return RESUME_GUEST;
+}
+
+/*
+ * Check and handle pending signal and vCPU requests etc
+ * Run with irq enabled and preempt enabled
+ *
+ * Return: RESUME_GUEST if we should enter the guest
+ *         RESUME_HOST  if we should exit to userspace
+ *         < 0 if we should exit to userspace, where the return value
+ *         indicates an error
+ */
+static int kvm_enter_guest_check(struct kvm_vcpu *vcpu)
+{
+       int ret;
+
+       /*
+        * Check conditions before entering the guest
+        */
+       ret = xfer_to_guest_mode_handle_work(vcpu);
+       if (ret < 0)
+               return ret;
+
+       ret = kvm_check_requests(vcpu);
+
+       return ret;
+}
+
+/*
+ * Called with irq enabled
+ *
+ * Return: RESUME_GUEST if we should enter the guest, and irq disabled
+ *         Others if we should exit to userspace
+ */
+static int kvm_pre_enter_guest(struct kvm_vcpu *vcpu)
+{
+       int ret;
+
+       do {
+               ret = kvm_enter_guest_check(vcpu);
+               if (ret != RESUME_GUEST)
+                       break;
+
+               /*
+                * Handle vcpu timer, interrupts, check requests and
+                * check vmid before vcpu enter guest
+                */
+               local_irq_disable();
+               kvm_acquire_timer(vcpu);
+               kvm_deliver_intr(vcpu);
+               kvm_deliver_exception(vcpu);
+               /* Make sure the vcpu mode has been written */
+               smp_store_mb(vcpu->mode, IN_GUEST_MODE);
+               kvm_check_vpid(vcpu);
+               vcpu->arch.host_eentry = csr_read64(LOONGARCH_CSR_EENTRY);
+               /* Clear KVM_LARCH_SWCSR_LATEST as CSR will change when enter guest */
+               vcpu->arch.aux_inuse &= ~KVM_LARCH_SWCSR_LATEST;
+
+               if (kvm_request_pending(vcpu) || xfer_to_guest_mode_work_pending()) {
+                       /* make sure the vcpu mode has been written */
+                       smp_store_mb(vcpu->mode, OUTSIDE_GUEST_MODE);
+                       local_irq_enable();
+                       ret = -EAGAIN;
+               }
+       } while (ret != RESUME_GUEST);
+
+       return ret;
+}
+
+/*
+ * Return 1 for resume guest and "<= 0" for resume host.
+ */
+static int kvm_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu)
+{
+       int ret = RESUME_GUEST;
+       unsigned long estat = vcpu->arch.host_estat;
+       u32 intr = estat & 0x1fff; /* Ignore NMI */
+       u32 ecode = (estat & CSR_ESTAT_EXC) >> CSR_ESTAT_EXC_SHIFT;
+
+       vcpu->mode = OUTSIDE_GUEST_MODE;
+
+       /* Set a default exit reason */
+       run->exit_reason = KVM_EXIT_UNKNOWN;
+
+       guest_timing_exit_irqoff();
+       guest_state_exit_irqoff();
+       local_irq_enable();
+
+       trace_kvm_exit(vcpu, ecode);
+       if (ecode) {
+               ret = kvm_handle_fault(vcpu, ecode);
+       } else {
+               WARN(!intr, "vm exiting with suspicious irq\n");
+               ++vcpu->stat.int_exits;
+       }
+
+       if (ret == RESUME_GUEST)
+               ret = kvm_pre_enter_guest(vcpu);
+
+       if (ret != RESUME_GUEST) {
+               local_irq_disable();
+               return ret;
+       }
+
+       guest_timing_enter_irqoff();
+       guest_state_enter_irqoff();
+       trace_kvm_reenter(vcpu);
+
+       return RESUME_GUEST;
+}
+
+int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)
+{
+       return !!(vcpu->arch.irq_pending) &&
+               vcpu->arch.mp_state.mp_state == KVM_MP_STATE_RUNNABLE;
+}
+
+int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu)
+{
+       return kvm_vcpu_exiting_guest_mode(vcpu) == IN_GUEST_MODE;
+}
+
+bool kvm_arch_vcpu_in_kernel(struct kvm_vcpu *vcpu)
+{
+       return false;
+}
+
+vm_fault_t kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf)
+{
+       return VM_FAULT_SIGBUS;
+}
+
+int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
+                                 struct kvm_translation *tr)
+{
+       return -EINVAL;
+}
+
+int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
+{
+       return kvm_pending_timer(vcpu) ||
+               kvm_read_hw_gcsr(LOONGARCH_CSR_ESTAT) & (1 << INT_TI);
+}
+
+int kvm_arch_vcpu_dump_regs(struct kvm_vcpu *vcpu)
+{
+       int i;
+
+       kvm_debug("vCPU Register Dump:\n");
+       kvm_debug("\tPC = 0x%08lx\n", vcpu->arch.pc);
+       kvm_debug("\tExceptions: %08lx\n", vcpu->arch.irq_pending);
+
+       for (i = 0; i < 32; i += 4) {
+               kvm_debug("\tGPR%02d: %08lx %08lx %08lx %08lx\n", i,
+                      vcpu->arch.gprs[i], vcpu->arch.gprs[i + 1],
+                      vcpu->arch.gprs[i + 2], vcpu->arch.gprs[i + 3]);
+       }
+
+       kvm_debug("\tCRMD: 0x%08lx, ESTAT: 0x%08lx\n",
+                 kvm_read_hw_gcsr(LOONGARCH_CSR_CRMD),
+                 kvm_read_hw_gcsr(LOONGARCH_CSR_ESTAT));
+
+       kvm_debug("\tERA: 0x%08lx\n", kvm_read_hw_gcsr(LOONGARCH_CSR_ERA));
+
+       return 0;
+}
+
+int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu,
+                               struct kvm_mp_state *mp_state)
+{
+       *mp_state = vcpu->arch.mp_state;
+
+       return 0;
+}
+
+int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
+                               struct kvm_mp_state *mp_state)
+{
+       int ret = 0;
+
+       switch (mp_state->mp_state) {
+       case KVM_MP_STATE_RUNNABLE:
+               vcpu->arch.mp_state = *mp_state;
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
+                                       struct kvm_guest_debug *dbg)
+{
+       return -EINVAL;
+}
+
+/**
+ * kvm_migrate_count() - Migrate timer.
+ * @vcpu:       Virtual CPU.
+ *
+ * Migrate hrtimer to the current CPU by cancelling and restarting it
+ * if the hrtimer is active.
+ *
+ * Must be called when the vCPU is migrated to a different CPU, so that
+ * the timer can interrupt the guest at the new CPU, and the timer irq can
+ * be delivered to the vCPU.
+ */
+static void kvm_migrate_count(struct kvm_vcpu *vcpu)
+{
+       if (hrtimer_cancel(&vcpu->arch.swtimer))
+               hrtimer_restart(&vcpu->arch.swtimer);
+}
+
+static int _kvm_getcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 *val)
+{
+       unsigned long gintc;
+       struct loongarch_csrs *csr = vcpu->arch.csr;
+
+       if (get_gcsr_flag(id) & INVALID_GCSR)
+               return -EINVAL;
+
+       if (id == LOONGARCH_CSR_ESTAT) {
+               /* ESTAT IP0~IP7 get from GINTC */
+               gintc = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_GINTC) & 0xff;
+               *val = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_ESTAT) | (gintc << 2);
+               return 0;
+       }
+
+       /*
+        * Get software CSR state since software state is consistent
+        * with hardware for synchronous ioctl
+        */
+       *val = kvm_read_sw_gcsr(csr, id);
+
+       return 0;
+}
+
+static int _kvm_setcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 val)
+{
+       int ret = 0, gintc;
+       struct loongarch_csrs *csr = vcpu->arch.csr;
+
+       if (get_gcsr_flag(id) & INVALID_GCSR)
+               return -EINVAL;
+
+       if (id == LOONGARCH_CSR_ESTAT) {
+               /* ESTAT IP0~IP7 inject through GINTC */
+               gintc = (val >> 2) & 0xff;
+               kvm_set_sw_gcsr(csr, LOONGARCH_CSR_GINTC, gintc);
+
+               gintc = val & ~(0xffUL << 2);
+               kvm_set_sw_gcsr(csr, LOONGARCH_CSR_ESTAT, gintc);
+
+               return ret;
+       }
+
+       kvm_write_sw_gcsr(csr, id, val);
+
+       return ret;
+}
+
+static int kvm_get_one_reg(struct kvm_vcpu *vcpu,
+               const struct kvm_one_reg *reg, u64 *v)
+{
+       int id, ret = 0;
+       u64 type = reg->id & KVM_REG_LOONGARCH_MASK;
+
+       switch (type) {
+       case KVM_REG_LOONGARCH_CSR:
+               id = KVM_GET_IOC_CSR_IDX(reg->id);
+               ret = _kvm_getcsr(vcpu, id, v);
+               break;
+       case KVM_REG_LOONGARCH_CPUCFG:
+               id = KVM_GET_IOC_CPUCFG_IDX(reg->id);
+               if (id >= 0 && id < KVM_MAX_CPUCFG_REGS)
+                       *v = vcpu->arch.cpucfg[id];
+               else
+                       ret = -EINVAL;
+               break;
+       case KVM_REG_LOONGARCH_KVM:
+               switch (reg->id) {
+               case KVM_REG_LOONGARCH_COUNTER:
+                       *v = drdtime() + vcpu->kvm->arch.time_offset;
+                       break;
+               default:
+                       ret = -EINVAL;
+                       break;
+               }
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+static int kvm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+       int ret = 0;
+       u64 v, size = reg->id & KVM_REG_SIZE_MASK;
+
+       switch (size) {
+       case KVM_REG_SIZE_U64:
+               ret = kvm_get_one_reg(vcpu, reg, &v);
+               if (ret)
+                       return ret;
+               ret = put_user(v, (u64 __user *)(long)reg->addr);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+static int kvm_set_one_reg(struct kvm_vcpu *vcpu,
+                       const struct kvm_one_reg *reg, u64 v)
+{
+       int id, ret = 0;
+       u64 type = reg->id & KVM_REG_LOONGARCH_MASK;
+
+       switch (type) {
+       case KVM_REG_LOONGARCH_CSR:
+               id = KVM_GET_IOC_CSR_IDX(reg->id);
+               ret = _kvm_setcsr(vcpu, id, v);
+               break;
+       case KVM_REG_LOONGARCH_CPUCFG:
+               id = KVM_GET_IOC_CPUCFG_IDX(reg->id);
+               if (id >= 0 && id < KVM_MAX_CPUCFG_REGS)
+                       vcpu->arch.cpucfg[id] = (u32)v;
+               else
+                       ret = -EINVAL;
+               break;
+       case KVM_REG_LOONGARCH_KVM:
+               switch (reg->id) {
+               case KVM_REG_LOONGARCH_COUNTER:
+                       /*
+                        * gftoffset is relative with board, not vcpu
+                        * only set for the first time for smp system
+                        */
+                       if (vcpu->vcpu_id == 0)
+                               vcpu->kvm->arch.time_offset = (signed long)(v - drdtime());
+                       break;
+               case KVM_REG_LOONGARCH_VCPU_RESET:
+                       kvm_reset_timer(vcpu);
+                       memset(&vcpu->arch.irq_pending, 0, sizeof(vcpu->arch.irq_pending));
+                       memset(&vcpu->arch.irq_clear, 0, sizeof(vcpu->arch.irq_clear));
+                       break;
+               default:
+                       ret = -EINVAL;
+                       break;
+               }
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+static int kvm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+       int ret = 0;
+       u64 v, size = reg->id & KVM_REG_SIZE_MASK;
+
+       switch (size) {
+       case KVM_REG_SIZE_U64:
+               ret = get_user(v, (u64 __user *)(long)reg->addr);
+               if (ret)
+                       return ret;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return kvm_set_one_reg(vcpu, reg, v);
+}
+
+int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
+{
+       return -ENOIOCTLCMD;
+}
+
+int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
+{
+       return -ENOIOCTLCMD;
+}
+
+int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(vcpu->arch.gprs); i++)
+               regs->gpr[i] = vcpu->arch.gprs[i];
+
+       regs->pc = vcpu->arch.pc;
+
+       return 0;
+}
+
+int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
+{
+       int i;
+
+       for (i = 1; i < ARRAY_SIZE(vcpu->arch.gprs); i++)
+               vcpu->arch.gprs[i] = regs->gpr[i];
+
+       vcpu->arch.gprs[0] = 0; /* zero is special, and cannot be set. */
+       vcpu->arch.pc = regs->pc;
+
+       return 0;
+}
+
+static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
+                                    struct kvm_enable_cap *cap)
+{
+       /* FPU is enabled by default, will support LSX/LASX later. */
+       return -EINVAL;
+}
+
+long kvm_arch_vcpu_ioctl(struct file *filp,
+                        unsigned int ioctl, unsigned long arg)
+{
+       long r;
+       void __user *argp = (void __user *)arg;
+       struct kvm_vcpu *vcpu = filp->private_data;
+
+       /*
+        * Only software CSR should be modified
+        *
+        * If any hardware CSR register is modified, vcpu_load/vcpu_put pair
+        * should be used. Since CSR registers owns by this vcpu, if switch
+        * to other vcpus, other vcpus need reload CSR registers.
+        *
+        * If software CSR is modified, bit KVM_LARCH_HWCSR_USABLE should
+        * be clear in vcpu->arch.aux_inuse, and vcpu_load will check
+        * aux_inuse flag and reload CSR registers form software.
+        */
+
+       switch (ioctl) {
+       case KVM_SET_ONE_REG:
+       case KVM_GET_ONE_REG: {
+               struct kvm_one_reg reg;
+
+               r = -EFAULT;
+               if (copy_from_user(&reg, argp, sizeof(reg)))
+                       break;
+               if (ioctl == KVM_SET_ONE_REG) {
+                       r = kvm_set_reg(vcpu, &reg);
+                       vcpu->arch.aux_inuse &= ~KVM_LARCH_HWCSR_USABLE;
+               } else
+                       r = kvm_get_reg(vcpu, &reg);
+               break;
+       }
+       case KVM_ENABLE_CAP: {
+               struct kvm_enable_cap cap;
+
+               r = -EFAULT;
+               if (copy_from_user(&cap, argp, sizeof(cap)))
+                       break;
+               r = kvm_vcpu_ioctl_enable_cap(vcpu, &cap);
+               break;
+       }
+       default:
+               r = -ENOIOCTLCMD;
+               break;
+       }
+
+       return r;
+}
+
+int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
+{
+       int i = 0;
+
+       fpu->fcc = vcpu->arch.fpu.fcc;
+       fpu->fcsr = vcpu->arch.fpu.fcsr;
+       for (i = 0; i < NUM_FPU_REGS; i++)
+               memcpy(&fpu->fpr[i], &vcpu->arch.fpu.fpr[i], FPU_REG_WIDTH / 64);
+
+       return 0;
+}
+
+int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
+{
+       int i = 0;
+
+       vcpu->arch.fpu.fcc = fpu->fcc;
+       vcpu->arch.fpu.fcsr = fpu->fcsr;
+       for (i = 0; i < NUM_FPU_REGS; i++)
+               memcpy(&vcpu->arch.fpu.fpr[i], &fpu->fpr[i], FPU_REG_WIDTH / 64);
+
+       return 0;
+}
+
+/* Enable FPU and restore context */
+void kvm_own_fpu(struct kvm_vcpu *vcpu)
+{
+       preempt_disable();
+
+       /* Enable FPU */
+       set_csr_euen(CSR_EUEN_FPEN);
+
+       kvm_restore_fpu(&vcpu->arch.fpu);
+       vcpu->arch.aux_inuse |= KVM_LARCH_FPU;
+       trace_kvm_aux(vcpu, KVM_TRACE_AUX_RESTORE, KVM_TRACE_AUX_FPU);
+
+       preempt_enable();
+}
+
+/* Save context and disable FPU */
+void kvm_lose_fpu(struct kvm_vcpu *vcpu)
+{
+       preempt_disable();
+
+       if (vcpu->arch.aux_inuse & KVM_LARCH_FPU) {
+               kvm_save_fpu(&vcpu->arch.fpu);
+               vcpu->arch.aux_inuse &= ~KVM_LARCH_FPU;
+               trace_kvm_aux(vcpu, KVM_TRACE_AUX_SAVE, KVM_TRACE_AUX_FPU);
+
+               /* Disable FPU */
+               clear_csr_euen(CSR_EUEN_FPEN);
+       }
+
+       preempt_enable();
+}
+
+int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq)
+{
+       int intr = (int)irq->irq;
+
+       if (intr > 0)
+               kvm_queue_irq(vcpu, intr);
+       else if (intr < 0)
+               kvm_dequeue_irq(vcpu, -intr);
+       else {
+               kvm_err("%s: invalid interrupt ioctl %d\n", __func__, irq->irq);
+               return -EINVAL;
+       }
+
+       kvm_vcpu_kick(vcpu);
+
+       return 0;
+}
+
+long kvm_arch_vcpu_async_ioctl(struct file *filp,
+                              unsigned int ioctl, unsigned long arg)
+{
+       void __user *argp = (void __user *)arg;
+       struct kvm_vcpu *vcpu = filp->private_data;
+
+       if (ioctl == KVM_INTERRUPT) {
+               struct kvm_interrupt irq;
+
+               if (copy_from_user(&irq, argp, sizeof(irq)))
+                       return -EFAULT;
+
+               kvm_debug("[%d] %s: irq: %d\n", vcpu->vcpu_id, __func__, irq.irq);
+
+               return kvm_vcpu_ioctl_interrupt(vcpu, &irq);
+       }
+
+       return -ENOIOCTLCMD;
+}
+
+int kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id)
+{
+       return 0;
+}
+
+int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
+{
+       unsigned long timer_hz;
+       struct loongarch_csrs *csr;
+
+       vcpu->arch.vpid = 0;
+
+       hrtimer_init(&vcpu->arch.swtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_PINNED);
+       vcpu->arch.swtimer.function = kvm_swtimer_wakeup;
+
+       vcpu->arch.handle_exit = kvm_handle_exit;
+       vcpu->arch.guest_eentry = (unsigned long)kvm_loongarch_ops->exc_entry;
+       vcpu->arch.csr = kzalloc(sizeof(struct loongarch_csrs), GFP_KERNEL);
+       if (!vcpu->arch.csr)
+               return -ENOMEM;
+
+       /*
+        * All kvm exceptions share one exception entry, and host <-> guest
+        * switch also switch ECFG.VS field, keep host ECFG.VS info here.
+        */
+       vcpu->arch.host_ecfg = (read_csr_ecfg() & CSR_ECFG_VS);
+
+       /* Init */
+       vcpu->arch.last_sched_cpu = -1;
+
+       /*
+        * Initialize guest register state to valid architectural reset state.
+        */
+       timer_hz = calc_const_freq();
+       kvm_init_timer(vcpu, timer_hz);
+
+       /* Set Initialize mode for guest */
+       csr = vcpu->arch.csr;
+       kvm_write_sw_gcsr(csr, LOONGARCH_CSR_CRMD, CSR_CRMD_DA);
+
+       /* Set cpuid */
+       kvm_write_sw_gcsr(csr, LOONGARCH_CSR_TMID, vcpu->vcpu_id);
+
+       /* Start with no pending virtual guest interrupts */
+       csr->csrs[LOONGARCH_CSR_GINTC] = 0;
+
+       return 0;
+}
+
+void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
+{
+}
+
+void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
+{
+       int cpu;
+       struct kvm_context *context;
+
+       hrtimer_cancel(&vcpu->arch.swtimer);
+       kvm_mmu_free_memory_cache(&vcpu->arch.mmu_page_cache);
+       kfree(vcpu->arch.csr);
+
+       /*
+        * If the vCPU is freed and reused as another vCPU, we don't want the
+        * matching pointer wrongly hanging around in last_vcpu.
+        */
+       for_each_possible_cpu(cpu) {
+               context = per_cpu_ptr(vcpu->kvm->arch.vmcs, cpu);
+               if (context->last_vcpu == vcpu)
+                       context->last_vcpu = NULL;
+       }
+}
+
+static int _kvm_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
+{
+       bool migrated;
+       struct kvm_context *context;
+       struct loongarch_csrs *csr = vcpu->arch.csr;
+
+       /*
+        * Have we migrated to a different CPU?
+        * If so, any old guest TLB state may be stale.
+        */
+       migrated = (vcpu->arch.last_sched_cpu != cpu);
+
+       /*
+        * Was this the last vCPU to run on this CPU?
+        * If not, any old guest state from this vCPU will have been clobbered.
+        */
+       context = per_cpu_ptr(vcpu->kvm->arch.vmcs, cpu);
+       if (migrated || (context->last_vcpu != vcpu))
+               vcpu->arch.aux_inuse &= ~KVM_LARCH_HWCSR_USABLE;
+       context->last_vcpu = vcpu;
+
+       /* Restore timer state regardless */
+       kvm_restore_timer(vcpu);
+
+       /* Control guest page CCA attribute */
+       change_csr_gcfg(CSR_GCFG_MATC_MASK, CSR_GCFG_MATC_ROOT);
+
+       /* Don't bother restoring registers multiple times unless necessary */
+       if (vcpu->arch.aux_inuse & KVM_LARCH_HWCSR_USABLE)
+               return 0;
+
+       write_csr_gcntc((ulong)vcpu->kvm->arch.time_offset);
+
+       /* Restore guest CSR registers */
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_CRMD);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_PRMD);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_EUEN);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_MISC);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_ECFG);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_ERA);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_BADV);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_BADI);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_EENTRY);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TLBIDX);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TLBEHI);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TLBELO0);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TLBELO1);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_ASID);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_PGDL);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_PGDH);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_PWCTL0);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_PWCTL1);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_STLBPGSIZE);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_RVACFG);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_CPUID);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_KS0);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_KS1);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_KS2);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_KS3);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_KS4);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_KS5);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_KS6);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_KS7);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TMID);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_CNTC);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TLBRENTRY);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TLBRBADV);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TLBRERA);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TLBRSAVE);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TLBRELO0);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TLBRELO1);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TLBREHI);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TLBRPRMD);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_DMWIN0);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_DMWIN1);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_DMWIN2);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_DMWIN3);
+       kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_LLBCTL);
+
+       /* Restore Root.GINTC from unused Guest.GINTC register */
+       write_csr_gintc(csr->csrs[LOONGARCH_CSR_GINTC]);
+
+       /*
+        * We should clear linked load bit to break interrupted atomics. This
+        * prevents a SC on the next vCPU from succeeding by matching a LL on
+        * the previous vCPU.
+        */
+       if (vcpu->kvm->created_vcpus > 1)
+               set_gcsr_llbctl(CSR_LLBCTL_WCLLB);
+
+       vcpu->arch.aux_inuse |= KVM_LARCH_HWCSR_USABLE;
+
+       return 0;
+}
+
+void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       if (vcpu->arch.last_sched_cpu != cpu) {
+               kvm_debug("[%d->%d]KVM vCPU[%d] switch\n",
+                               vcpu->arch.last_sched_cpu, cpu, vcpu->vcpu_id);
+               /*
+                * Migrate the timer interrupt to the current CPU so that it
+                * always interrupts the guest and synchronously triggers a
+                * guest timer interrupt.
+                */
+               kvm_migrate_count(vcpu);
+       }
+
+       /* Restore guest state to registers */
+       _kvm_vcpu_load(vcpu, cpu);
+       local_irq_restore(flags);
+}
+
+static int _kvm_vcpu_put(struct kvm_vcpu *vcpu, int cpu)
+{
+       struct loongarch_csrs *csr = vcpu->arch.csr;
+
+       kvm_lose_fpu(vcpu);
+
+       /*
+        * Update CSR state from hardware if software CSR state is stale,
+        * most CSR registers are kept unchanged during process context
+        * switch except CSR registers like remaining timer tick value and
+        * injected interrupt state.
+        */
+       if (vcpu->arch.aux_inuse & KVM_LARCH_SWCSR_LATEST)
+               goto out;
+
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_CRMD);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_PRMD);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_EUEN);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_MISC);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_ECFG);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_ERA);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_BADV);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_BADI);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_EENTRY);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TLBIDX);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TLBEHI);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TLBELO0);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TLBELO1);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_ASID);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_PGDL);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_PGDH);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_PWCTL0);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_PWCTL1);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_STLBPGSIZE);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_RVACFG);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_CPUID);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_PRCFG1);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_PRCFG2);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_PRCFG3);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_KS0);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_KS1);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_KS2);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_KS3);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_KS4);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_KS5);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_KS6);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_KS7);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TMID);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_CNTC);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_LLBCTL);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TLBRENTRY);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TLBRBADV);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TLBRERA);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TLBRSAVE);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TLBRELO0);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TLBRELO1);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TLBREHI);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TLBRPRMD);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_DMWIN0);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_DMWIN1);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_DMWIN2);
+       kvm_save_hw_gcsr(csr, LOONGARCH_CSR_DMWIN3);
+
+       vcpu->arch.aux_inuse |= KVM_LARCH_SWCSR_LATEST;
+
+out:
+       kvm_save_timer(vcpu);
+       /* Save Root.GINTC into unused Guest.GINTC register */
+       csr->csrs[LOONGARCH_CSR_GINTC] = read_csr_gintc();
+
+       return 0;
+}
+
+void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
+{
+       int cpu;
+       unsigned long flags;
+
+       local_irq_save(flags);
+       cpu = smp_processor_id();
+       vcpu->arch.last_sched_cpu = cpu;
+
+       /* Save guest state in registers */
+       _kvm_vcpu_put(vcpu, cpu);
+       local_irq_restore(flags);
+}
+
+int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
+{
+       int r = -EINTR;
+       struct kvm_run *run = vcpu->run;
+
+       if (vcpu->mmio_needed) {
+               if (!vcpu->mmio_is_write)
+                       kvm_complete_mmio_read(vcpu, run);
+               vcpu->mmio_needed = 0;
+       }
+
+       if (run->exit_reason == KVM_EXIT_LOONGARCH_IOCSR) {
+               if (!run->iocsr_io.is_write)
+                       kvm_complete_iocsr_read(vcpu, run);
+       }
+
+       if (run->immediate_exit)
+               return r;
+
+       /* Clear exit_reason */
+       run->exit_reason = KVM_EXIT_UNKNOWN;
+       lose_fpu(1);
+       vcpu_load(vcpu);
+       kvm_sigset_activate(vcpu);
+       r = kvm_pre_enter_guest(vcpu);
+       if (r != RESUME_GUEST)
+               goto out;
+
+       guest_timing_enter_irqoff();
+       guest_state_enter_irqoff();
+       trace_kvm_enter(vcpu);
+       r = kvm_loongarch_ops->enter_guest(run, vcpu);
+
+       trace_kvm_out(vcpu);
+       /*
+        * Guest exit is already recorded at kvm_handle_exit()
+        * return value must not be RESUME_GUEST
+        */
+       local_irq_enable();
+out:
+       kvm_sigset_deactivate(vcpu);
+       vcpu_put(vcpu);
+
+       return r;
+}
diff --git a/arch/loongarch/kvm/vm.c b/arch/loongarch/kvm/vm.c
new file mode 100644 (file)
index 0000000..0a37f6f
--- /dev/null
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
+ */
+
+#include <linux/kvm_host.h>
+#include <asm/kvm_mmu.h>
+
+const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
+       KVM_GENERIC_VM_STATS(),
+       STATS_DESC_ICOUNTER(VM, pages),
+       STATS_DESC_ICOUNTER(VM, hugepages),
+};
+
+const struct kvm_stats_header kvm_vm_stats_header = {
+       .name_size = KVM_STATS_NAME_SIZE,
+       .num_desc = ARRAY_SIZE(kvm_vm_stats_desc),
+       .id_offset =  sizeof(struct kvm_stats_header),
+       .desc_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE,
+       .data_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE +
+                                       sizeof(kvm_vm_stats_desc),
+};
+
+int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
+{
+       int i;
+
+       /* Allocate page table to map GPA -> RPA */
+       kvm->arch.pgd = kvm_pgd_alloc();
+       if (!kvm->arch.pgd)
+               return -ENOMEM;
+
+       kvm_init_vmcs(kvm);
+       kvm->arch.gpa_size = BIT(cpu_vabits - 1);
+       kvm->arch.root_level = CONFIG_PGTABLE_LEVELS - 1;
+       kvm->arch.invalid_ptes[0] = 0;
+       kvm->arch.invalid_ptes[1] = (unsigned long)invalid_pte_table;
+#if CONFIG_PGTABLE_LEVELS > 2
+       kvm->arch.invalid_ptes[2] = (unsigned long)invalid_pmd_table;
+#endif
+#if CONFIG_PGTABLE_LEVELS > 3
+       kvm->arch.invalid_ptes[3] = (unsigned long)invalid_pud_table;
+#endif
+       for (i = 0; i <= kvm->arch.root_level; i++)
+               kvm->arch.pte_shifts[i] = PAGE_SHIFT + i * (PAGE_SHIFT - 3);
+
+       return 0;
+}
+
+void kvm_arch_destroy_vm(struct kvm *kvm)
+{
+       kvm_destroy_vcpus(kvm);
+       free_page((unsigned long)kvm->arch.pgd);
+       kvm->arch.pgd = NULL;
+}
+
+int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
+{
+       int r;
+
+       switch (ext) {
+       case KVM_CAP_ONE_REG:
+       case KVM_CAP_ENABLE_CAP:
+       case KVM_CAP_READONLY_MEM:
+       case KVM_CAP_SYNC_MMU:
+       case KVM_CAP_IMMEDIATE_EXIT:
+       case KVM_CAP_IOEVENTFD:
+       case KVM_CAP_MP_STATE:
+               r = 1;
+               break;
+       case KVM_CAP_NR_VCPUS:
+               r = num_online_cpus();
+               break;
+       case KVM_CAP_MAX_VCPUS:
+               r = KVM_MAX_VCPUS;
+               break;
+       case KVM_CAP_MAX_VCPU_ID:
+               r = KVM_MAX_VCPU_IDS;
+               break;
+       case KVM_CAP_NR_MEMSLOTS:
+               r = KVM_USER_MEM_SLOTS;
+               break;
+       default:
+               r = 0;
+               break;
+       }
+
+       return r;
+}
+
+int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
+{
+       return -ENOIOCTLCMD;
+}
index e6376e3dce862ff83d5995154ab48331a59d4586..1fc2f6813ea027d43ccf24af8aade31f1093df62 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 ba138117b1247e450431b54c4afe562a56acb312..1e76fcb83093dd6892801200e6027e92d9c68d37 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 f3fe8c06ba4db352ca373824254b782dc9893226..4dd53427f6578531910e197503fc0ec9d7f82f5c 100644 (file)
@@ -43,11 +43,11 @@ void copy_user_highpage(struct page *to, struct page *from,
 {
        void *vfrom, *vto;
 
-       vto = kmap_atomic(to);
-       vfrom = kmap_atomic(from);
+       vfrom = kmap_local_page(from);
+       vto = kmap_local_page(to);
        copy_page(vto, vfrom);
-       kunmap_atomic(vfrom);
-       kunmap_atomic(vto);
+       kunmap_local(vfrom);
+       kunmap_local(vto);
        /* Make sure this page is cleared on other CPU's too before using it */
        smp_wmb();
 }
@@ -240,6 +240,7 @@ pgd_t swapper_pg_dir[_PTRS_PER_PGD] __section(".bss..swapper_pg_dir");
 pgd_t invalid_pg_dir[_PTRS_PER_PGD] __page_aligned_bss;
 #ifndef __PAGETABLE_PUD_FOLDED
 pud_t invalid_pud_table[PTRS_PER_PUD] __page_aligned_bss;
+EXPORT_SYMBOL(invalid_pud_table);
 #endif
 #ifndef __PAGETABLE_PMD_FOLDED
 pmd_t invalid_pmd_table[PTRS_PER_PMD] __page_aligned_bss;
index 73b0980ab6f5e716650ade71b1a729bd7e892050..70ca7301981106b680bbc506b2ef340d01e73911 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 da68bc1a464348affc033b559759a784a6080b2b..cc3e81fe0186f4f0fa8de9cedfc75138583ce23f 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 eb8572e201ea075d5e28a359f65ae8e3d117ebf4..2c0a411f23aa778bb62160bd511252736fc987be 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 ca17dd3a19153c10583f04f8bc24daf7fbd7eb3e..d5d682f3d29f3a808f37e1d23f2887d0ffece071 100644 (file)
@@ -17,7 +17,7 @@
 #define PTRS_PER_PTE_BITS      (PAGE_SHIFT - 3)
 
        .macro tlb_do_page_fault, write
-       SYM_FUNC_START(tlb_do_page_fault_\write)
+       SYM_CODE_START(tlb_do_page_fault_\write)
        SAVE_ALL
        csrrd           a2, LOONGARCH_CSR_BADV
        move            a0, sp
        li.w            a1, \write
        bl              do_page_fault
        RESTORE_ALL_AND_RET
-       SYM_FUNC_END(tlb_do_page_fault_\write)
+       SYM_CODE_END(tlb_do_page_fault_\write)
        .endm
 
        tlb_do_page_fault 0
        tlb_do_page_fault 1
 
-SYM_FUNC_START(handle_tlb_protect)
+SYM_CODE_START(handle_tlb_protect)
        BACKUP_T0T1
        SAVE_ALL
        move            a0, sp
@@ -41,9 +41,9 @@ SYM_FUNC_START(handle_tlb_protect)
        la_abs          t0, do_page_fault
        jirl            ra, t0, 0
        RESTORE_ALL_AND_RET
-SYM_FUNC_END(handle_tlb_protect)
+SYM_CODE_END(handle_tlb_protect)
 
-SYM_FUNC_START(handle_tlb_load)
+SYM_CODE_START(handle_tlb_load)
        csrwr           t0, EXCEPTION_KS0
        csrwr           t1, EXCEPTION_KS1
        csrwr           ra, EXCEPTION_KS2
@@ -187,16 +187,16 @@ nopage_tlb_load:
        csrrd           ra, EXCEPTION_KS2
        la_abs          t0, tlb_do_page_fault_0
        jr              t0
-SYM_FUNC_END(handle_tlb_load)
+SYM_CODE_END(handle_tlb_load)
 
-SYM_FUNC_START(handle_tlb_load_ptw)
+SYM_CODE_START(handle_tlb_load_ptw)
        csrwr           t0, LOONGARCH_CSR_KS0
        csrwr           t1, LOONGARCH_CSR_KS1
        la_abs          t0, tlb_do_page_fault_0
        jr              t0
-SYM_FUNC_END(handle_tlb_load_ptw)
+SYM_CODE_END(handle_tlb_load_ptw)
 
-SYM_FUNC_START(handle_tlb_store)
+SYM_CODE_START(handle_tlb_store)
        csrwr           t0, EXCEPTION_KS0
        csrwr           t1, EXCEPTION_KS1
        csrwr           ra, EXCEPTION_KS2
@@ -343,16 +343,16 @@ nopage_tlb_store:
        csrrd           ra, EXCEPTION_KS2
        la_abs          t0, tlb_do_page_fault_1
        jr              t0
-SYM_FUNC_END(handle_tlb_store)
+SYM_CODE_END(handle_tlb_store)
 
-SYM_FUNC_START(handle_tlb_store_ptw)
+SYM_CODE_START(handle_tlb_store_ptw)
        csrwr           t0, LOONGARCH_CSR_KS0
        csrwr           t1, LOONGARCH_CSR_KS1
        la_abs          t0, tlb_do_page_fault_1
        jr              t0
-SYM_FUNC_END(handle_tlb_store_ptw)
+SYM_CODE_END(handle_tlb_store_ptw)
 
-SYM_FUNC_START(handle_tlb_modify)
+SYM_CODE_START(handle_tlb_modify)
        csrwr           t0, EXCEPTION_KS0
        csrwr           t1, EXCEPTION_KS1
        csrwr           ra, EXCEPTION_KS2
@@ -497,16 +497,16 @@ nopage_tlb_modify:
        csrrd           ra, EXCEPTION_KS2
        la_abs          t0, tlb_do_page_fault_1
        jr              t0
-SYM_FUNC_END(handle_tlb_modify)
+SYM_CODE_END(handle_tlb_modify)
 
-SYM_FUNC_START(handle_tlb_modify_ptw)
+SYM_CODE_START(handle_tlb_modify_ptw)
        csrwr           t0, LOONGARCH_CSR_KS0
        csrwr           t1, LOONGARCH_CSR_KS1
        la_abs          t0, tlb_do_page_fault_1
        jr              t0
-SYM_FUNC_END(handle_tlb_modify_ptw)
+SYM_CODE_END(handle_tlb_modify_ptw)
 
-SYM_FUNC_START(handle_tlb_refill)
+SYM_CODE_START(handle_tlb_refill)
        csrwr           t0, LOONGARCH_CSR_TLBRSAVE
        csrrd           t0, LOONGARCH_CSR_PGD
        lddir           t0, t0, 3
@@ -521,4 +521,4 @@ SYM_FUNC_START(handle_tlb_refill)
        tlbfill
        csrrd           t0, LOONGARCH_CSR_TLBRSAVE
        ertn
-SYM_FUNC_END(handle_tlb_refill)
+SYM_CODE_END(handle_tlb_refill)
index 012da042d0a4f749a307f312ed46a2abdd2f10a6..7b9f91db227f2d4538dde233a5cc96306501c622 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 76080c71a2a7b6c15cd32675f270ca1356a534e0..f521874ebb07b22495b01972ca92828491311779 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 ff61901329c62696cfdaf585944dd07d57e72707..d377e043b49f86539b88fd6f79c5395f1a42278d 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 7b2ac1319d70acafd68cfe6b30680abc7bd04234..467ee6b95ae1c6c9e795f3446886797aa51b7372 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 f7f078c2872c439307783fd81961e1b2faf577da..72daacc472a0a305772d7473aa8601a5316fbbe4 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 6d28b5514699afd2b537fdd10156dc961056f0a8..ee9e071859b2f44c2f4138436204a44a909ff7c0 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 efd06a897c6a3b10b6adb7a2e1b4b14abbef930a..7b986b09dba84edece72b56eb4dfe54fff191816 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 4098f9a0964b9b8741c533acce88cb018b844c6a..2019c1f04bd037af0d346f4c4e03f42c769eb16f 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 a8a1a7c1e16eb4ef1b751144377a943be3eecaa9..a9f7e21f66567aad1d7244a47664c356346097aa 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 54b9387c3691643ae486248d60e5482e011cc060..d5d5388973ac7612fd8bbc5467d37ecf805b3f46 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)
@@ -910,7 +910,7 @@ config ARCH_FORCE_MAX_ORDER
        default "6" if PPC32 && PPC_64K_PAGES
        range 4 10 if PPC32 && PPC_256K_PAGES
        default "4" if PPC32 && PPC_256K_PAGES
-       range 10 10
+       range 10 12
        default "10"
        help
          The kernel page allocator limits the size of maximal physically
index de092b04ee1a1292b6352c74888291e179f5b0ae..92df40c6cc6b5e0b4015192aff3c74f9f0537ac8 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 21f681ee535a23906bc021a9357d3b41e8b17e2c..e6fe1d5731f2c5bb1813c34959c46c740ec6428a 100644 (file)
@@ -94,6 +94,13 @@ static inline pte_t pte_wrprotect(pte_t pte)
 
 #define pte_wrprotect pte_wrprotect
 
+static inline int pte_read(pte_t pte)
+{
+       return (pte_val(pte) & _PAGE_RO) != _PAGE_NA;
+}
+
+#define pte_read pte_read
+
 static inline int pte_write(pte_t pte)
 {
        return !(pte_val(pte) & _PAGE_RO);
index 5cd9acf58a7db92945dab1dff92e90e9c0196821..eb6891e34cbde4ee5a2daf337b931e25d333a546 100644 (file)
@@ -197,7 +197,7 @@ static inline int __ptep_test_and_clear_young(struct mm_struct *mm,
 {
        unsigned long old;
 
-       if (pte_young(*ptep))
+       if (!pte_young(*ptep))
                return 0;
        old = pte_update(mm, addr, ptep, _PAGE_ACCESSED, 0, 0);
        return (old & _PAGE_ACCESSED) != 0;
index 56ea48276356c67dcc5e36bf1a054a8c34e00af6..c721478c5934726b1cb8eaadd4dfb046974044e0 100644 (file)
@@ -25,7 +25,9 @@ static inline int pte_write(pte_t pte)
        return pte_val(pte) & _PAGE_RW;
 }
 #endif
+#ifndef pte_read
 static inline int pte_read(pte_t pte)          { return 1; }
+#endif
 static inline int pte_dirty(pte_t pte)         { return pte_val(pte) & _PAGE_DIRTY; }
 static inline int pte_special(pte_t pte)       { return pte_val(pte) & _PAGE_SPECIAL; }
 static inline int pte_none(pte_t pte)          { return (pte_val(pte) & ~_PTE_NONE_MASK) == 0; }
index 9692acb0361fbf56bb96bfb320b5d4b73f67a431..7eda33a24bb45edb42fda7d669c77bf2af7314b6 100644 (file)
@@ -137,8 +137,9 @@ ret_from_syscall:
        lis     r4,icache_44x_need_flush@ha
        lwz     r5,icache_44x_need_flush@l(r4)
        cmplwi  cr0,r5,0
-       bne-    2f
+       bne-    .L44x_icache_flush
 #endif /* CONFIG_PPC_47x */
+.L44x_icache_flush_return:
        kuep_unlock
        lwz     r4,_LINK(r1)
        lwz     r5,_CCR(r1)
@@ -172,10 +173,11 @@ syscall_exit_finish:
        b       1b
 
 #ifdef CONFIG_44x
-2:     li      r7,0
+.L44x_icache_flush:
+       li      r7,0
        iccci   r0,r0
        stw     r7,icache_44x_need_flush@l(r4)
-       b       1b
+       b       .L44x_icache_flush_return
 #endif  /* CONFIG_44x */
 
        .globl  ret_from_fork
index 97e9ea0c729793574d69d87625ff870568481521..0f1641a31250ddd863bf0ddce41601ccea231bd9 100644 (file)
@@ -395,7 +395,7 @@ interrupt_base:
 #ifdef CONFIG_PPC_FPU
        FP_UNAVAILABLE_EXCEPTION
 #else
-       EXCEPTION(0x0800, FP_UNAVAIL, FloatingPointUnavailable, unknown_exception)
+       EXCEPTION(0x0800, FP_UNAVAIL, FloatingPointUnavailable, emulation_assist_interrupt)
 #endif
 
        /* System Call Interrupt */
index b8513dc3e53ac8cb654177591b1513b5a1f17c49..a1318ce18d0e61b34f49869b12ae4dcfd3cc5f95 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 a74623025f3ab87b5a3375bab26e19c25b1ae173..9e51801c49152e32236b4ef5aa8a89ee05501445 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 2f1026fba00d5a10b90a8d05447c2f3b87af444f..20f72cd1d8138d7de79ed8fc034454ebf4ef5453 100644 (file)
@@ -948,6 +948,8 @@ void __init setup_arch(char **cmdline_p)
 
        /* Parse memory topology */
        mem_topology_setup();
+       /* Set max_mapnr before paging_init() */
+       set_max_mapnr(max_pfn);
 
        /*
         * Release secondary cpus out of their spinloops at 0x60 now that
index b15f15dcacb5c42a5b26645460c45e1e5f29340f..e6a958a5da2763deca47037b1246e2d5a83576d5 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 eeff136b83d97b22343cf1b7ce8b3b0144f5943c..64ff37721fd06f4914ba8bf6b80abc19f1b2cc32 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 253620979d0cd849a53d5853d2e995fa4fb6fc69..6dd2f46bd3ef643949511461f1f637e4817f2ade 100644 (file)
@@ -406,6 +406,9 @@ static __always_inline bool yield_to_prev(struct qspinlock *lock, struct qnode *
        if ((yield_count & 1) == 0)
                goto yield_prev; /* owner vcpu is running */
 
+       if (get_owner_cpu(READ_ONCE(lock->val)) != yield_cpu)
+               goto yield_prev; /* re-sample lock owner */
+
        spin_end();
 
        preempted = true;
index 3bc0eb21b2a005538a7493cf8ebc7c34a6332801..5a2e512e96db6b310dde8b7c9a25dd1199acf31e 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 17075c78d4bc3dfef9c662f98cbfc3429dbc6d41..35fd2a95be24c662e0ac1514d6ec51daa9402a14 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 39acc2cbab4cde82037eb50d82d7a4384d0678e0..9e1f6558d0262c1c9e1055a7949431389d13f0c9 100644 (file)
@@ -1212,14 +1212,7 @@ void radix__tlb_flush(struct mmu_gather *tlb)
 
                        smp_mb(); /* see radix__flush_tlb_mm */
                        exit_flush_lazy_tlbs(mm);
-                       _tlbiel_pid(mm->context.id, RIC_FLUSH_ALL);
-
-                       /*
-                        * It should not be possible to have coprocessors still
-                        * attached here.
-                        */
-                       if (WARN_ON_ONCE(atomic_read(&mm->context.copros) > 0))
-                               __flush_all_mm(mm, true);
+                       __flush_all_mm(mm, true);
 
                        preempt_enable();
                } else {
index 8b121df7b08f8677d72c08fa0d63b1d7509fef96..07e8f4f1e07f899fea07ed4c4ecbcd4cc5559dcf 100644 (file)
@@ -288,7 +288,6 @@ void __init mem_init(void)
 #endif
 
        high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
-       set_max_mapnr(max_pfn);
 
        kasan_late_init();
 
index dbbfe897455dc443e1c804aa2d8ff8ad1a2aab28..a642a79298929dda334d712678e2930f83375bcd 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 3f86fd217690be96e6868f7f9670e6a570ef240b..4d69bfb9bc111e2d235aa745f7e517883c36945d 100644 (file)
@@ -104,6 +104,8 @@ static pte_t set_pte_filter_hash(pte_t pte) { return pte; }
 /* Embedded type MMU with HW exec support. This is a bit more complicated
  * as we don't have two bits to spare for _PAGE_EXEC and _PAGE_HWEXEC so
  * instead we "filter out" the exec permission for non clean pages.
+ *
+ * This is also called once for the folio. So only work with folio->flags here.
  */
 static inline pte_t set_pte_filter(pte_t pte)
 {
@@ -190,29 +192,39 @@ static pte_t set_access_flags_filter(pte_t pte, struct vm_area_struct *vma,
 void set_ptes(struct mm_struct *mm, unsigned long addr, pte_t *ptep,
                pte_t pte, unsigned int nr)
 {
-       /*
-        * Make sure hardware valid bit is not set. We don't do
-        * tlb flush for this update.
-        */
-       VM_WARN_ON(pte_hw_valid(*ptep) && !pte_protnone(*ptep));
 
        /* Note: mm->context.id might not yet have been assigned as
         * this context might not have been activated yet when this
-        * is called.
+        * is called. Filter the pte value and use the filtered value
+        * to setup all the ptes in the range.
         */
        pte = set_pte_filter(pte);
 
-       /* Perform the setting of the PTE */
-       arch_enter_lazy_mmu_mode();
+       /*
+        * We don't need to call arch_enter/leave_lazy_mmu_mode()
+        * because we expect set_ptes to be only be used on not present
+        * and not hw_valid ptes. Hence there is no translation cache flush
+        * involved that need to be batched.
+        */
        for (;;) {
+
+               /*
+                * Make sure hardware valid bit is not set. We don't do
+                * tlb flush for this update.
+                */
+               VM_WARN_ON(pte_hw_valid(*ptep) && !pte_protnone(*ptep));
+
+               /* Perform the setting of the PTE */
                __set_pte_at(mm, addr, ptep, pte, 0);
                if (--nr == 0)
                        break;
                ptep++;
-               pte = __pte(pte_val(pte) + (1UL << PTE_RPN_SHIFT));
                addr += PAGE_SIZE;
+               /*
+                * increment the pfn.
+                */
+               pte = pfn_pte(pte_pfn(pte) + 1, pte_pgprot((pte)));
        }
-       arch_leave_lazy_mmu_mode();
 }
 
 void unmap_kernel_page(unsigned long va)
@@ -288,7 +300,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 317175791d23c34912bf7b7d9ac8a40e30648e41..3449be7c0d51f7e9e62112523a0f182891f4bf8d 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 d9f1a2a83158aa47b6763e6fe7180617096ac73f..1824536cf6f21f80d6ececef62697be5ed3396de 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 bae45b358a094ad984572235293f3c7c2e0c5631..2b0cac6fb61f87d513e9d2f969c9c0322490cfec 100644 (file)
@@ -184,9 +184,6 @@ _GLOBAL_TOC(plpar_hcall)
 plpar_hcall_trace:
        HCALL_INST_PRECALL(R5)
 
-       std     r4,STK_PARAM(R4)(r1)
-       mr      r0,r4
-
        mr      r4,r5
        mr      r5,r6
        mr      r6,r7
@@ -196,7 +193,7 @@ plpar_hcall_trace:
 
        HVSC
 
-       ld      r12,STK_PARAM(R4)(r1)
+       ld      r12,STACK_FRAME_MIN_SIZE+STK_PARAM(R4)(r1)
        std     r4,0(r12)
        std     r5,8(r12)
        std     r6,16(r12)
@@ -296,9 +293,6 @@ _GLOBAL_TOC(plpar_hcall9)
 plpar_hcall9_trace:
        HCALL_INST_PRECALL(R5)
 
-       std     r4,STK_PARAM(R4)(r1)
-       mr      r0,r4
-
        mr      r4,r5
        mr      r5,r6
        mr      r6,r7
index d607ab0f7c6dafa4f754f34a910ef66464e5a06d..9c48fecc671918ed7c77eda92f333e03dbf9f4e3 100644 (file)
@@ -273,11 +273,9 @@ config RISCV_DMA_NONCOHERENT
        select ARCH_HAS_SYNC_DMA_FOR_CPU
        select ARCH_HAS_SYNC_DMA_FOR_DEVICE
        select DMA_BOUNCE_UNALIGNED_KMALLOC if SWIOTLB
-       select DMA_DIRECT_REMAP if MMU
 
 config RISCV_NONSTANDARD_CACHE_OPS
        bool
-       depends on RISCV_DMA_NONCOHERENT
        help
          This enables function pointer support for non-standard noncoherent
          systems to handle cache management.
@@ -550,6 +548,7 @@ config RISCV_ISA_ZICBOM
        depends on RISCV_ALTERNATIVE
        default y
        select RISCV_DMA_NONCOHERENT
+       select DMA_DIRECT_REMAP
        help
           Adds support to dynamically detect the presence of the ZICBOM
           extension (Cache Block Management Operations) and enable its
index 566bcefeab502c45f69b332c43857ea657abef57..e2c731cfed8cc6e878a6fed176cc82ae79b2fbfb 100644 (file)
@@ -77,6 +77,7 @@ config ERRATA_THEAD_PBMT
 config ERRATA_THEAD_CMO
        bool "Apply T-Head cache management errata"
        depends on ERRATA_THEAD && MMU
+       select DMA_DIRECT_REMAP
        select RISCV_DMA_NONCOHERENT
        default y
        help
index 1329e060c5482dd4ac7f8c3eeff17b4d00215d33..b43a6bb7e4dcb6984edcd45f4adbcec4250aa77b 100644 (file)
@@ -6,7 +6,6 @@
 # for more details.
 #
 
-OBJCOPYFLAGS    := -O binary
 LDFLAGS_vmlinux := -z norelro
 ifeq ($(CONFIG_RELOCATABLE),y)
        LDFLAGS_vmlinux += -shared -Bsymbolic -z notext --emit-relocs
index d79f94432b279b1cc2328825ff6f84a9b5367e7a..2c02358abd711a3d05374cd5cccdba1fe208d0e3 100644 (file)
                                reg = <0x100000 0x400000>;
                        };
                        reserved-data@600000 {
-                               reg = <0x600000 0x1000000>;
+                               reg = <0x600000 0xa00000>;
                        };
                };
        };
                };
 
                ss-pins {
-                       pinmux = <GPIOMUX(48, GPOUT_SYS_SPI0_FSS,
+                       pinmux = <GPIOMUX(49, GPOUT_SYS_SPI0_FSS,
                                              GPOEN_ENABLE,
                                              GPI_SYS_SPI0_FSS)>;
                        bias-disable;
                };
        };
 
-       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 ce708183b6f655c74e6cd55515b6d68d72526e29..ff364709a6dfafd8393d3ff12dcaac2081700868 100644 (file)
                interrupt-parent = <&plic>;
                #address-cells = <2>;
                #size-cells = <2>;
+               dma-noncoherent;
                ranges;
 
                plic: interrupt-controller@ffd8000000 {
index 2d644e19caefcb1b5fa8b2aff4a9e456199dc72c..6278c389b801ee6e54e808c80e6e236c026329c7 100644 (file)
@@ -1 +1,5 @@
+ifdef CONFIG_RISCV_ALTERNATIVE_EARLY
+CFLAGS_errata.o := -mcmodel=medany
+endif
+
 obj-y += errata.o
index 777cb8299551ca3a33147471f032d319cdbcfb35..306a19a5509c10e63663330b04e1118abb054b74 100644 (file)
 #define ENVCFG_CBIE_INV                        _AC(0x3, UL)
 #define ENVCFG_FIOM                    _AC(0x1, UL)
 
+/* Smstateen bits */
+#define SMSTATEEN0_AIA_IMSIC_SHIFT     58
+#define SMSTATEEN0_AIA_IMSIC           (_ULL(1) << SMSTATEEN0_AIA_IMSIC_SHIFT)
+#define SMSTATEEN0_AIA_SHIFT           59
+#define SMSTATEEN0_AIA                 (_ULL(1) << SMSTATEEN0_AIA_SHIFT)
+#define SMSTATEEN0_AIA_ISEL_SHIFT      60
+#define SMSTATEEN0_AIA_ISEL            (_ULL(1) << SMSTATEEN0_AIA_ISEL_SHIFT)
+#define SMSTATEEN0_HSENVCFG_SHIFT      62
+#define SMSTATEEN0_HSENVCFG            (_ULL(1) << SMSTATEEN0_HSENVCFG_SHIFT)
+#define SMSTATEEN0_SSTATEEN0_SHIFT     63
+#define SMSTATEEN0_SSTATEEN0           (_ULL(1) << SMSTATEEN0_SSTATEEN0_SHIFT)
+
 /* symbolic CSR names: */
 #define CSR_CYCLE              0xc00
 #define CSR_TIME               0xc01
 #define CSR_SIE                        0x104
 #define CSR_STVEC              0x105
 #define CSR_SCOUNTEREN         0x106
+#define CSR_SENVCFG            0x10a
+#define CSR_SSTATEEN0          0x10c
 #define CSR_SSCRATCH           0x140
 #define CSR_SEPC               0x141
 #define CSR_SCAUSE             0x142
 #define CSR_VSIEH              0x214
 #define CSR_VSIPH              0x254
 
+/* Hypervisor stateen CSRs */
+#define CSR_HSTATEEN0          0x60c
+#define CSR_HSTATEEN0H         0x61c
+
 #define CSR_MSTATUS            0x300
 #define CSR_MISA               0x301
 #define CSR_MIDELEG            0x303
index 740a979171e565173036191f95c424662c84deec..2b2f5df7ef2c7de42216b4166ae3d1f4a789731f 100644 (file)
@@ -31,6 +31,27 @@ static inline unsigned long ftrace_call_adjust(unsigned long addr)
        return addr;
 }
 
+/*
+ * Let's do like x86/arm64 and ignore the compat syscalls.
+ */
+#define ARCH_TRACE_IGNORE_COMPAT_SYSCALLS
+static inline bool arch_trace_is_compat_syscall(struct pt_regs *regs)
+{
+       return is_compat_task();
+}
+
+#define ARCH_HAS_SYSCALL_MATCH_SYM_NAME
+static inline bool arch_syscall_match_sym_name(const char *sym,
+                                              const char *name)
+{
+       /*
+        * Since all syscall functions have __riscv_ prefix, we must skip it.
+        * However, as we described above, we decided to ignore compat
+        * syscalls, so we don't care about __riscv_compat_ prefix here.
+        */
+       return !strcmp(sym + 8, name);
+}
+
 struct dyn_arch_ftrace {
 };
 #endif
index 34e24f078cc1b3e00cdc9655269e55d90f906e9a..4c5b0e929890fadcebb3caace0afe97dfa46d8bf 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 b7b58258f6c7c0ec611768e6e624113d72c6df2b..6fc51c1b34cf7097b449c1893968ab473eed9e90 100644 (file)
@@ -58,6 +58,8 @@
 #define RISCV_ISA_EXT_ZICSR            40
 #define RISCV_ISA_EXT_ZIFENCEI         41
 #define RISCV_ISA_EXT_ZIHPM            42
+#define RISCV_ISA_EXT_SMSTATEEN                43
+#define RISCV_ISA_EXT_ZICOND           44
 
 #define RISCV_ISA_EXT_MAX              64
 
index e7882ccb0fd46a67da4e9e1d287066b121c5f188..78ea44f767189214c9c3263c93e10c4c1db91bb8 100644 (file)
@@ -40,6 +40,15 @@ void arch_remove_kprobe(struct kprobe *p);
 int kprobe_fault_handler(struct pt_regs *regs, unsigned int trapnr);
 bool kprobe_breakpoint_handler(struct pt_regs *regs);
 bool kprobe_single_step_handler(struct pt_regs *regs);
-
+#else
+static inline bool kprobe_breakpoint_handler(struct pt_regs *regs)
+{
+       return false;
+}
+
+static inline bool kprobe_single_step_handler(struct pt_regs *regs)
+{
+       return false;
+}
 #endif /* CONFIG_KPROBES */
 #endif /* _ASM_RISCV_KPROBES_H */
index 1ebf20dfbaa6982c32777af62ad30fba7581a223..0eefd9c991ae24e99ea946ac11615075aefbf085 100644 (file)
@@ -162,6 +162,16 @@ struct kvm_vcpu_csr {
        unsigned long hvip;
        unsigned long vsatp;
        unsigned long scounteren;
+       unsigned long senvcfg;
+};
+
+struct kvm_vcpu_config {
+       u64 henvcfg;
+       u64 hstateen0;
+};
+
+struct kvm_vcpu_smstateen_csr {
+       unsigned long sstateen0;
 };
 
 struct kvm_vcpu_arch {
@@ -183,6 +193,8 @@ struct kvm_vcpu_arch {
        unsigned long host_sscratch;
        unsigned long host_stvec;
        unsigned long host_scounteren;
+       unsigned long host_senvcfg;
+       unsigned long host_sstateen0;
 
        /* CPU context of Host */
        struct kvm_cpu_context host_context;
@@ -193,6 +205,9 @@ struct kvm_vcpu_arch {
        /* CPU CSR context of Guest VCPU */
        struct kvm_vcpu_csr guest_csr;
 
+       /* CPU Smstateen CSR context of Guest VCPU */
+       struct kvm_vcpu_smstateen_csr smstateen_csr;
+
        /* CPU context upon Guest VCPU reset */
        struct kvm_cpu_context guest_reset_context;
 
@@ -244,6 +259,9 @@ struct kvm_vcpu_arch {
 
        /* Performance monitoring context */
        struct kvm_pmu pmu_context;
+
+       /* 'static' configurations which are set only once */
+       struct kvm_vcpu_config cfg;
 };
 
 static inline void kvm_arch_sync_events(struct kvm *kvm) {}
index cdcf0ff07be7b54d947d1a6afc53798066afd6a2..6a453f7f8b562639dc1d767648364f68fa6e49ae 100644 (file)
@@ -11,7 +11,7 @@
 
 #define KVM_SBI_IMPID 3
 
-#define KVM_SBI_VERSION_MAJOR 1
+#define KVM_SBI_VERSION_MAJOR 2
 #define KVM_SBI_VERSION_MINOR 0
 
 enum kvm_riscv_sbi_ext_status {
@@ -35,6 +35,9 @@ struct kvm_vcpu_sbi_return {
 struct kvm_vcpu_sbi_extension {
        unsigned long extid_start;
        unsigned long extid_end;
+
+       bool default_unavail;
+
        /**
         * SBI extension handler. It can be defined for a given extension or group of
         * extension. But it should always return linux error codes rather than SBI
@@ -59,6 +62,7 @@ int kvm_riscv_vcpu_get_reg_sbi_ext(struct kvm_vcpu *vcpu,
 const struct kvm_vcpu_sbi_extension *kvm_vcpu_sbi_find_ext(
                                struct kvm_vcpu *vcpu, unsigned long extid);
 int kvm_riscv_vcpu_sbi_ecall(struct kvm_vcpu *vcpu, struct kvm_run *run);
+void kvm_riscv_vcpu_sbi_init(struct kvm_vcpu *vcpu);
 
 #ifdef CONFIG_RISCV_SBI_V01
 extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_v01;
@@ -69,6 +73,7 @@ extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_ipi;
 extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_rfence;
 extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_srst;
 extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_hsm;
+extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_dbcn;
 extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_experimental;
 extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_vendor;
 
index 5b4a1bf5f4395ca62c952c2b5502d7877459fca0..12dfda6bb9242f402c729e1c08184e04a2f96eec 100644 (file)
@@ -30,6 +30,7 @@ enum sbi_ext_id {
        SBI_EXT_HSM = 0x48534D,
        SBI_EXT_SRST = 0x53525354,
        SBI_EXT_PMU = 0x504D55,
+       SBI_EXT_DBCN = 0x4442434E,
 
        /* Experimentals extensions must lie within this range */
        SBI_EXT_EXPERIMENTAL_START = 0x08000000,
@@ -236,6 +237,12 @@ enum sbi_pmu_ctr_type {
 /* Flags defined for counter stop function */
 #define SBI_PMU_STOP_FLAG_RESET (1 << 0)
 
+enum sbi_ext_dbcn_fid {
+       SBI_EXT_DBCN_CONSOLE_WRITE = 0,
+       SBI_EXT_DBCN_CONSOLE_READ = 1,
+       SBI_EXT_DBCN_CONSOLE_WRITE_BYTE = 2,
+};
+
 #define SBI_SPEC_VERSION_DEFAULT       0x1
 #define SBI_SPEC_VERSION_MAJOR_SHIFT   24
 #define SBI_SPEC_VERSION_MAJOR_MASK    0x7f
index f2183e00fdd20946052009f05d857e99191bcb40..3fc7deda9190251510f96d952c5276a900912676 100644 (file)
@@ -34,7 +34,18 @@ struct arch_uprobe {
        bool simulate;
 };
 
+#ifdef CONFIG_UPROBES
 bool uprobe_breakpoint_handler(struct pt_regs *regs);
 bool uprobe_single_step_handler(struct pt_regs *regs);
-
+#else
+static inline bool uprobe_breakpoint_handler(struct pt_regs *regs)
+{
+       return false;
+}
+
+static inline bool uprobe_single_step_handler(struct pt_regs *regs)
+{
+       return false;
+}
+#endif /* CONFIG_UPROBES */
 #endif /* _ASM_RISCV_UPROBES_H */
index 992c5e407104958532d7ba930d50447ebe56fa25..60d3b21dead7d8846050d20a96ef1a0b3ad1ba20 100644 (file)
@@ -80,6 +80,7 @@ struct kvm_riscv_csr {
        unsigned long sip;
        unsigned long satp;
        unsigned long scounteren;
+       unsigned long senvcfg;
 };
 
 /* AIA CSR registers for KVM_GET_ONE_REG and KVM_SET_ONE_REG */
@@ -93,6 +94,11 @@ struct kvm_riscv_aia_csr {
        unsigned long iprio2h;
 };
 
+/* Smstateen CSR for KVM_GET_ONE_REG and KVM_SET_ONE_REG */
+struct kvm_riscv_smstateen_csr {
+       unsigned long sstateen0;
+};
+
 /* TIMER registers for KVM_GET_ONE_REG and KVM_SET_ONE_REG */
 struct kvm_riscv_timer {
        __u64 frequency;
@@ -131,6 +137,8 @@ enum KVM_RISCV_ISA_EXT_ID {
        KVM_RISCV_ISA_EXT_ZICSR,
        KVM_RISCV_ISA_EXT_ZIFENCEI,
        KVM_RISCV_ISA_EXT_ZIHPM,
+       KVM_RISCV_ISA_EXT_SMSTATEEN,
+       KVM_RISCV_ISA_EXT_ZICOND,
        KVM_RISCV_ISA_EXT_MAX,
 };
 
@@ -148,6 +156,7 @@ enum KVM_RISCV_SBI_EXT_ID {
        KVM_RISCV_SBI_EXT_PMU,
        KVM_RISCV_SBI_EXT_EXPERIMENTAL,
        KVM_RISCV_SBI_EXT_VENDOR,
+       KVM_RISCV_SBI_EXT_DBCN,
        KVM_RISCV_SBI_EXT_MAX,
 };
 
@@ -178,10 +187,13 @@ enum KVM_RISCV_SBI_EXT_ID {
 #define KVM_REG_RISCV_CSR              (0x03 << KVM_REG_RISCV_TYPE_SHIFT)
 #define KVM_REG_RISCV_CSR_GENERAL      (0x0 << KVM_REG_RISCV_SUBTYPE_SHIFT)
 #define KVM_REG_RISCV_CSR_AIA          (0x1 << KVM_REG_RISCV_SUBTYPE_SHIFT)
+#define KVM_REG_RISCV_CSR_SMSTATEEN    (0x2 << KVM_REG_RISCV_SUBTYPE_SHIFT)
 #define KVM_REG_RISCV_CSR_REG(name)    \
                (offsetof(struct kvm_riscv_csr, name) / sizeof(unsigned long))
 #define KVM_REG_RISCV_CSR_AIA_REG(name)        \
        (offsetof(struct kvm_riscv_aia_csr, name) / sizeof(unsigned long))
+#define KVM_REG_RISCV_CSR_SMSTATEEN_REG(name)  \
+       (offsetof(struct kvm_riscv_smstateen_csr, name) / sizeof(unsigned long))
 
 /* Timer registers are mapped as type 4 */
 #define KVM_REG_RISCV_TIMER            (0x04 << KVM_REG_RISCV_TYPE_SHIFT)
index 1cfbba65d11ae311d54729966e57fb3c9386d61c..e3803822ab5a3a0ee36852cd9b08f9db8ee76fdc 100644 (file)
@@ -167,6 +167,7 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
        __RISCV_ISA_EXT_DATA(zicbom, RISCV_ISA_EXT_ZICBOM),
        __RISCV_ISA_EXT_DATA(zicboz, RISCV_ISA_EXT_ZICBOZ),
        __RISCV_ISA_EXT_DATA(zicntr, RISCV_ISA_EXT_ZICNTR),
+       __RISCV_ISA_EXT_DATA(zicond, RISCV_ISA_EXT_ZICOND),
        __RISCV_ISA_EXT_DATA(zicsr, RISCV_ISA_EXT_ZICSR),
        __RISCV_ISA_EXT_DATA(zifencei, RISCV_ISA_EXT_ZIFENCEI),
        __RISCV_ISA_EXT_DATA(zihintpause, RISCV_ISA_EXT_ZIHINTPAUSE),
@@ -175,6 +176,7 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
        __RISCV_ISA_EXT_DATA(zbb, RISCV_ISA_EXT_ZBB),
        __RISCV_ISA_EXT_DATA(zbs, RISCV_ISA_EXT_ZBS),
        __RISCV_ISA_EXT_DATA(smaia, RISCV_ISA_EXT_SMAIA),
+       __RISCV_ISA_EXT_DATA(smstateen, RISCV_ISA_EXT_SMSTATEEN),
        __RISCV_ISA_EXT_DATA(ssaia, RISCV_ISA_EXT_SSAIA),
        __RISCV_ISA_EXT_DATA(sscofpmf, RISCV_ISA_EXT_SSCOFPMF),
        __RISCV_ISA_EXT_DATA(sstc, RISCV_ISA_EXT_SSTC),
index a8efa053c4a524c830982f9df12453c40b960340..9cc0a76692715ea6ff2ec56630f7b60ed0a37f92 100644 (file)
@@ -60,7 +60,7 @@ static void init_irq_stacks(void)
 }
 #endif /* CONFIG_VMAP_STACK */
 
-#ifdef CONFIG_HAVE_SOFTIRQ_ON_OWN_STACK
+#ifdef CONFIG_SOFTIRQ_ON_OWN_STACK
 void do_softirq_own_stack(void)
 {
 #ifdef CONFIG_IRQ_STACKS
@@ -92,7 +92,7 @@ void do_softirq_own_stack(void)
 #endif
                __do_softirq();
 }
-#endif /* CONFIG_HAVE_SOFTIRQ_ON_OWN_STACK */
+#endif /* CONFIG_SOFTIRQ_ON_OWN_STACK */
 
 #else
 static void init_irq_stacks(void) {}
index e600aab116a4093a5a45285f3e14e32e917f54ba..aac853ae4eb74e8e228551eb94720611e241c32c 100644 (file)
@@ -173,19 +173,6 @@ static void __init init_resources(void)
        if (ret < 0)
                goto error;
 
-#ifdef CONFIG_KEXEC_CORE
-       if (crashk_res.start != crashk_res.end) {
-               ret = add_resource(&iomem_resource, &crashk_res);
-               if (ret < 0)
-                       goto error;
-       }
-       if (crashk_low_res.start != crashk_low_res.end) {
-               ret = add_resource(&iomem_resource, &crashk_low_res);
-               if (ret < 0)
-                       goto error;
-       }
-#endif
-
 #ifdef CONFIG_CRASH_DUMP
        if (elfcorehdr_size > 0) {
                elfcorehdr_res.start = elfcorehdr_addr;
index 180d951d362418ee00ab1361fa15eb407446c1f7..21a4d0e111bc5f151f9ef4a6205e7da17a87ec10 100644 (file)
@@ -311,13 +311,6 @@ static inline void __user *get_sigframe(struct ksignal *ksig,
        /* Align the stack frame. */
        sp &= ~0xfUL;
 
-       /*
-        * Fail if the size of the altstack is not large enough for the
-        * sigframe construction.
-        */
-       if (current->sas_ss_size && sp < current->sas_ss_sp)
-               return (void __user __force *)-1UL;
-
        return (void __user *)sp;
 }
 
index 19807c4d3805d4d6b308b5a74cada73a5ef0dbf3..fae8f610d867fd7f34ec19ed24e7cb3da06b968e 100644 (file)
@@ -13,6 +13,8 @@
 #include <linux/kdebug.h>
 #include <linux/uaccess.h>
 #include <linux/kprobes.h>
+#include <linux/uprobes.h>
+#include <asm/uprobes.h>
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/irq.h>
@@ -247,22 +249,28 @@ static inline unsigned long get_break_insn_length(unsigned long pc)
        return GET_INSN_LENGTH(insn);
 }
 
+static bool probe_single_step_handler(struct pt_regs *regs)
+{
+       bool user = user_mode(regs);
+
+       return user ? uprobe_single_step_handler(regs) : kprobe_single_step_handler(regs);
+}
+
+static bool probe_breakpoint_handler(struct pt_regs *regs)
+{
+       bool user = user_mode(regs);
+
+       return user ? uprobe_breakpoint_handler(regs) : kprobe_breakpoint_handler(regs);
+}
+
 void handle_break(struct pt_regs *regs)
 {
-#ifdef CONFIG_KPROBES
-       if (kprobe_single_step_handler(regs))
+       if (probe_single_step_handler(regs))
                return;
 
-       if (kprobe_breakpoint_handler(regs))
-               return;
-#endif
-#ifdef CONFIG_UPROBES
-       if (uprobe_single_step_handler(regs))
+       if (probe_breakpoint_handler(regs))
                return;
 
-       if (uprobe_breakpoint_handler(regs))
-               return;
-#endif
        current->thread.bad_cause = regs->cause;
 
        if (user_mode(regs))
index 82229db1ce73f3b42de478e2af6cbc9a0756fca1..e087c809073c1bbb12956a1f5e4774d3c1db48ed 100644 (file)
@@ -141,6 +141,12 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
        if (rc)
                return rc;
 
+       /*
+        * Setup SBI extensions
+        * NOTE: This must be the last thing to be initialized.
+        */
+       kvm_riscv_vcpu_sbi_init(vcpu);
+
        /* Reset VCPU */
        kvm_riscv_reset_vcpu(vcpu);
 
@@ -471,31 +477,38 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
        return -EINVAL;
 }
 
-static void kvm_riscv_vcpu_update_config(const unsigned long *isa)
+static void kvm_riscv_vcpu_setup_config(struct kvm_vcpu *vcpu)
 {
-       u64 henvcfg = 0;
+       const unsigned long *isa = vcpu->arch.isa;
+       struct kvm_vcpu_config *cfg = &vcpu->arch.cfg;
 
        if (riscv_isa_extension_available(isa, SVPBMT))
-               henvcfg |= ENVCFG_PBMTE;
+               cfg->henvcfg |= ENVCFG_PBMTE;
 
        if (riscv_isa_extension_available(isa, SSTC))
-               henvcfg |= ENVCFG_STCE;
+               cfg->henvcfg |= ENVCFG_STCE;
 
        if (riscv_isa_extension_available(isa, ZICBOM))
-               henvcfg |= (ENVCFG_CBIE | ENVCFG_CBCFE);
+               cfg->henvcfg |= (ENVCFG_CBIE | ENVCFG_CBCFE);
 
        if (riscv_isa_extension_available(isa, ZICBOZ))
-               henvcfg |= ENVCFG_CBZE;
-
-       csr_write(CSR_HENVCFG, henvcfg);
-#ifdef CONFIG_32BIT
-       csr_write(CSR_HENVCFGH, henvcfg >> 32);
-#endif
+               cfg->henvcfg |= ENVCFG_CBZE;
+
+       if (riscv_has_extension_unlikely(RISCV_ISA_EXT_SMSTATEEN)) {
+               cfg->hstateen0 |= SMSTATEEN0_HSENVCFG;
+               if (riscv_isa_extension_available(isa, SSAIA))
+                       cfg->hstateen0 |= SMSTATEEN0_AIA_IMSIC |
+                                         SMSTATEEN0_AIA |
+                                         SMSTATEEN0_AIA_ISEL;
+               if (riscv_isa_extension_available(isa, SMSTATEEN))
+                       cfg->hstateen0 |= SMSTATEEN0_SSTATEEN0;
+       }
 }
 
 void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 {
        struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
+       struct kvm_vcpu_config *cfg = &vcpu->arch.cfg;
 
        csr_write(CSR_VSSTATUS, csr->vsstatus);
        csr_write(CSR_VSIE, csr->vsie);
@@ -506,8 +519,14 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
        csr_write(CSR_VSTVAL, csr->vstval);
        csr_write(CSR_HVIP, csr->hvip);
        csr_write(CSR_VSATP, csr->vsatp);
-
-       kvm_riscv_vcpu_update_config(vcpu->arch.isa);
+       csr_write(CSR_HENVCFG, cfg->henvcfg);
+       if (IS_ENABLED(CONFIG_32BIT))
+               csr_write(CSR_HENVCFGH, cfg->henvcfg >> 32);
+       if (riscv_has_extension_unlikely(RISCV_ISA_EXT_SMSTATEEN)) {
+               csr_write(CSR_HSTATEEN0, cfg->hstateen0);
+               if (IS_ENABLED(CONFIG_32BIT))
+                       csr_write(CSR_HSTATEEN0H, cfg->hstateen0 >> 32);
+       }
 
        kvm_riscv_gstage_update_hgatp(vcpu);
 
@@ -606,6 +625,32 @@ static void kvm_riscv_update_hvip(struct kvm_vcpu *vcpu)
        kvm_riscv_vcpu_aia_update_hvip(vcpu);
 }
 
+static __always_inline void kvm_riscv_vcpu_swap_in_guest_state(struct kvm_vcpu *vcpu)
+{
+       struct kvm_vcpu_smstateen_csr *smcsr = &vcpu->arch.smstateen_csr;
+       struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
+       struct kvm_vcpu_config *cfg = &vcpu->arch.cfg;
+
+       vcpu->arch.host_senvcfg = csr_swap(CSR_SENVCFG, csr->senvcfg);
+       if (riscv_has_extension_unlikely(RISCV_ISA_EXT_SMSTATEEN) &&
+           (cfg->hstateen0 & SMSTATEEN0_SSTATEEN0))
+               vcpu->arch.host_sstateen0 = csr_swap(CSR_SSTATEEN0,
+                                                    smcsr->sstateen0);
+}
+
+static __always_inline void kvm_riscv_vcpu_swap_in_host_state(struct kvm_vcpu *vcpu)
+{
+       struct kvm_vcpu_smstateen_csr *smcsr = &vcpu->arch.smstateen_csr;
+       struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
+       struct kvm_vcpu_config *cfg = &vcpu->arch.cfg;
+
+       csr->senvcfg = csr_swap(CSR_SENVCFG, vcpu->arch.host_senvcfg);
+       if (riscv_has_extension_unlikely(RISCV_ISA_EXT_SMSTATEEN) &&
+           (cfg->hstateen0 & SMSTATEEN0_SSTATEEN0))
+               smcsr->sstateen0 = csr_swap(CSR_SSTATEEN0,
+                                           vcpu->arch.host_sstateen0);
+}
+
 /*
  * Actually run the vCPU, entering an RCU extended quiescent state (EQS) while
  * the vCPU is running.
@@ -615,10 +660,12 @@ static void kvm_riscv_update_hvip(struct kvm_vcpu *vcpu)
  */
 static void noinstr kvm_riscv_vcpu_enter_exit(struct kvm_vcpu *vcpu)
 {
+       kvm_riscv_vcpu_swap_in_guest_state(vcpu);
        guest_state_enter_irqoff();
        __kvm_riscv_switch_to(&vcpu->arch);
        vcpu->arch.last_exit_cpu = vcpu->cpu;
        guest_state_exit_irqoff();
+       kvm_riscv_vcpu_swap_in_host_state(vcpu);
 }
 
 int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
@@ -627,6 +674,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
        struct kvm_cpu_trap trap;
        struct kvm_run *run = vcpu->run;
 
+       if (!vcpu->arch.ran_atleast_once)
+               kvm_riscv_vcpu_setup_config(vcpu);
+
        /* Mark this VCPU ran at least once */
        vcpu->arch.ran_atleast_once = true;
 
index b7e0e03c69b1e50c7fa937ca513129259678aad3..c6ebce6126b55006a2714a43d5cd3f123636d654 100644 (file)
@@ -34,6 +34,7 @@ static const unsigned long kvm_isa_ext_arr[] = {
        [KVM_RISCV_ISA_EXT_M] = RISCV_ISA_EXT_m,
        [KVM_RISCV_ISA_EXT_V] = RISCV_ISA_EXT_v,
        /* Multi letter extensions (alphabetically sorted) */
+       KVM_ISA_EXT_ARR(SMSTATEEN),
        KVM_ISA_EXT_ARR(SSAIA),
        KVM_ISA_EXT_ARR(SSTC),
        KVM_ISA_EXT_ARR(SVINVAL),
@@ -45,6 +46,7 @@ static const unsigned long kvm_isa_ext_arr[] = {
        KVM_ISA_EXT_ARR(ZICBOM),
        KVM_ISA_EXT_ARR(ZICBOZ),
        KVM_ISA_EXT_ARR(ZICNTR),
+       KVM_ISA_EXT_ARR(ZICOND),
        KVM_ISA_EXT_ARR(ZICSR),
        KVM_ISA_EXT_ARR(ZIFENCEI),
        KVM_ISA_EXT_ARR(ZIHINTPAUSE),
@@ -80,11 +82,11 @@ static bool kvm_riscv_vcpu_isa_enable_allowed(unsigned long ext)
 static bool kvm_riscv_vcpu_isa_disable_allowed(unsigned long ext)
 {
        switch (ext) {
+       /* Extensions which don't have any mechanism to disable */
        case KVM_RISCV_ISA_EXT_A:
        case KVM_RISCV_ISA_EXT_C:
        case KVM_RISCV_ISA_EXT_I:
        case KVM_RISCV_ISA_EXT_M:
-       case KVM_RISCV_ISA_EXT_SSAIA:
        case KVM_RISCV_ISA_EXT_SSTC:
        case KVM_RISCV_ISA_EXT_SVINVAL:
        case KVM_RISCV_ISA_EXT_SVNAPOT:
@@ -92,11 +94,15 @@ static bool kvm_riscv_vcpu_isa_disable_allowed(unsigned long ext)
        case KVM_RISCV_ISA_EXT_ZBB:
        case KVM_RISCV_ISA_EXT_ZBS:
        case KVM_RISCV_ISA_EXT_ZICNTR:
+       case KVM_RISCV_ISA_EXT_ZICOND:
        case KVM_RISCV_ISA_EXT_ZICSR:
        case KVM_RISCV_ISA_EXT_ZIFENCEI:
        case KVM_RISCV_ISA_EXT_ZIHINTPAUSE:
        case KVM_RISCV_ISA_EXT_ZIHPM:
                return false;
+       /* Extensions which can be disabled using Smstateen */
+       case KVM_RISCV_ISA_EXT_SSAIA:
+               return riscv_has_extension_unlikely(RISCV_ISA_EXT_SMSTATEEN);
        default:
                break;
        }
@@ -378,6 +384,34 @@ static int kvm_riscv_vcpu_general_set_csr(struct kvm_vcpu *vcpu,
        return 0;
 }
 
+static inline int kvm_riscv_vcpu_smstateen_set_csr(struct kvm_vcpu *vcpu,
+                                                  unsigned long reg_num,
+                                                  unsigned long reg_val)
+{
+       struct kvm_vcpu_smstateen_csr *csr = &vcpu->arch.smstateen_csr;
+
+       if (reg_num >= sizeof(struct kvm_riscv_smstateen_csr) /
+               sizeof(unsigned long))
+               return -EINVAL;
+
+       ((unsigned long *)csr)[reg_num] = reg_val;
+       return 0;
+}
+
+static int kvm_riscv_vcpu_smstateen_get_csr(struct kvm_vcpu *vcpu,
+                                           unsigned long reg_num,
+                                           unsigned long *out_val)
+{
+       struct kvm_vcpu_smstateen_csr *csr = &vcpu->arch.smstateen_csr;
+
+       if (reg_num >= sizeof(struct kvm_riscv_smstateen_csr) /
+               sizeof(unsigned long))
+               return -EINVAL;
+
+       *out_val = ((unsigned long *)csr)[reg_num];
+       return 0;
+}
+
 static int kvm_riscv_vcpu_get_reg_csr(struct kvm_vcpu *vcpu,
                                      const struct kvm_one_reg *reg)
 {
@@ -401,6 +435,12 @@ static int kvm_riscv_vcpu_get_reg_csr(struct kvm_vcpu *vcpu,
        case KVM_REG_RISCV_CSR_AIA:
                rc = kvm_riscv_vcpu_aia_get_csr(vcpu, reg_num, &reg_val);
                break;
+       case KVM_REG_RISCV_CSR_SMSTATEEN:
+               rc = -EINVAL;
+               if (riscv_has_extension_unlikely(RISCV_ISA_EXT_SMSTATEEN))
+                       rc = kvm_riscv_vcpu_smstateen_get_csr(vcpu, reg_num,
+                                                             &reg_val);
+               break;
        default:
                rc = -ENOENT;
                break;
@@ -440,6 +480,12 @@ static int kvm_riscv_vcpu_set_reg_csr(struct kvm_vcpu *vcpu,
        case KVM_REG_RISCV_CSR_AIA:
                rc = kvm_riscv_vcpu_aia_set_csr(vcpu, reg_num, reg_val);
                break;
+       case KVM_REG_RISCV_CSR_SMSTATEEN:
+               rc = -EINVAL;
+               if (riscv_has_extension_unlikely(RISCV_ISA_EXT_SMSTATEEN))
+                       rc = kvm_riscv_vcpu_smstateen_set_csr(vcpu, reg_num,
+                                                             reg_val);
+break;
        default:
                rc = -ENOENT;
                break;
@@ -696,6 +742,8 @@ static inline unsigned long num_csr_regs(const struct kvm_vcpu *vcpu)
 
        if (riscv_isa_extension_available(vcpu->arch.isa, SSAIA))
                n += sizeof(struct kvm_riscv_aia_csr) / sizeof(unsigned long);
+       if (riscv_isa_extension_available(vcpu->arch.isa, SMSTATEEN))
+               n += sizeof(struct kvm_riscv_smstateen_csr) / sizeof(unsigned long);
 
        return n;
 }
@@ -704,7 +752,7 @@ static int copy_csr_reg_indices(const struct kvm_vcpu *vcpu,
                                u64 __user *uindices)
 {
        int n1 = sizeof(struct kvm_riscv_csr) / sizeof(unsigned long);
-       int n2 = 0;
+       int n2 = 0, n3 = 0;
 
        /* copy general csr regs */
        for (int i = 0; i < n1; i++) {
@@ -738,7 +786,25 @@ static int copy_csr_reg_indices(const struct kvm_vcpu *vcpu,
                }
        }
 
-       return n1 + n2;
+       /* copy Smstateen csr regs */
+       if (riscv_isa_extension_available(vcpu->arch.isa, SMSTATEEN)) {
+               n3 = sizeof(struct kvm_riscv_smstateen_csr) / sizeof(unsigned long);
+
+               for (int i = 0; i < n3; i++) {
+                       u64 size = IS_ENABLED(CONFIG_32BIT) ?
+                                  KVM_REG_SIZE_U32 : KVM_REG_SIZE_U64;
+                       u64 reg = KVM_REG_RISCV | size | KVM_REG_RISCV_CSR |
+                                         KVM_REG_RISCV_CSR_SMSTATEEN | i;
+
+                       if (uindices) {
+                               if (put_user(reg, uindices))
+                                       return -EFAULT;
+                               uindices++;
+                       }
+               }
+       }
+
+       return n1 + n2 + n3;
 }
 
 static inline unsigned long num_timer_regs(void)
index 9cd97091c7233089ff71207c6da8280f2bcba0c6..a04ff98085d93936a70a2ff1aec7ad3e305f7aaa 100644 (file)
@@ -66,6 +66,10 @@ static const struct kvm_riscv_sbi_extension_entry sbi_ext[] = {
                .ext_idx = KVM_RISCV_SBI_EXT_PMU,
                .ext_ptr = &vcpu_sbi_ext_pmu,
        },
+       {
+               .ext_idx = KVM_RISCV_SBI_EXT_DBCN,
+               .ext_ptr = &vcpu_sbi_ext_dbcn,
+       },
        {
                .ext_idx = KVM_RISCV_SBI_EXT_EXPERIMENTAL,
                .ext_ptr = &vcpu_sbi_ext_experimental,
@@ -155,14 +159,8 @@ static int riscv_vcpu_set_sbi_ext_single(struct kvm_vcpu *vcpu,
        if (!sext)
                return -ENOENT;
 
-       /*
-        * We can't set the extension status to available here, since it may
-        * have a probe() function which needs to confirm availability first,
-        * but it may be too early to call that here. We can set the status to
-        * unavailable, though.
-        */
-       if (!reg_val)
-               scontext->ext_status[sext->ext_idx] =
+       scontext->ext_status[sext->ext_idx] = (reg_val) ?
+                       KVM_RISCV_SBI_EXT_AVAILABLE :
                        KVM_RISCV_SBI_EXT_UNAVAILABLE;
 
        return 0;
@@ -188,16 +186,8 @@ static int riscv_vcpu_get_sbi_ext_single(struct kvm_vcpu *vcpu,
        if (!sext)
                return -ENOENT;
 
-       /*
-        * If the extension status is still uninitialized, then we should probe
-        * to determine if it's available, but it may be too early to do that
-        * here. The best we can do is report that the extension has not been
-        * disabled, i.e. we return 1 when the extension is available and also
-        * when it only may be available.
-        */
-       *reg_val = scontext->ext_status[sext->ext_idx] !=
-                               KVM_RISCV_SBI_EXT_UNAVAILABLE;
-
+       *reg_val = scontext->ext_status[sext->ext_idx] ==
+                               KVM_RISCV_SBI_EXT_AVAILABLE;
        return 0;
 }
 
@@ -337,18 +327,8 @@ const struct kvm_vcpu_sbi_extension *kvm_vcpu_sbi_find_ext(
                            scontext->ext_status[entry->ext_idx] ==
                                                KVM_RISCV_SBI_EXT_AVAILABLE)
                                return ext;
-                       if (scontext->ext_status[entry->ext_idx] ==
-                                               KVM_RISCV_SBI_EXT_UNAVAILABLE)
-                               return NULL;
-                       if (ext->probe && !ext->probe(vcpu)) {
-                               scontext->ext_status[entry->ext_idx] =
-                                       KVM_RISCV_SBI_EXT_UNAVAILABLE;
-                               return NULL;
-                       }
 
-                       scontext->ext_status[entry->ext_idx] =
-                               KVM_RISCV_SBI_EXT_AVAILABLE;
-                       return ext;
+                       return NULL;
                }
        }
 
@@ -419,3 +399,26 @@ ecall_done:
 
        return ret;
 }
+
+void kvm_riscv_vcpu_sbi_init(struct kvm_vcpu *vcpu)
+{
+       struct kvm_vcpu_sbi_context *scontext = &vcpu->arch.sbi_context;
+       const struct kvm_riscv_sbi_extension_entry *entry;
+       const struct kvm_vcpu_sbi_extension *ext;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(sbi_ext); i++) {
+               entry = &sbi_ext[i];
+               ext = entry->ext_ptr;
+
+               if (ext->probe && !ext->probe(vcpu)) {
+                       scontext->ext_status[entry->ext_idx] =
+                               KVM_RISCV_SBI_EXT_UNAVAILABLE;
+                       continue;
+               }
+
+               scontext->ext_status[entry->ext_idx] = ext->default_unavail ?
+                                       KVM_RISCV_SBI_EXT_UNAVAILABLE :
+                                       KVM_RISCV_SBI_EXT_AVAILABLE;
+       }
+}
index 7c4d5d38a33908891b7c7371dee0d121ea05f5fb..23b57c931b1522777ff4631abb8f24193a0bcd3f 100644 (file)
@@ -175,3 +175,35 @@ const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_srst = {
        .extid_end = SBI_EXT_SRST,
        .handler = kvm_sbi_ext_srst_handler,
 };
+
+static int kvm_sbi_ext_dbcn_handler(struct kvm_vcpu *vcpu,
+                                   struct kvm_run *run,
+                                   struct kvm_vcpu_sbi_return *retdata)
+{
+       struct kvm_cpu_context *cp = &vcpu->arch.guest_context;
+       unsigned long funcid = cp->a6;
+
+       switch (funcid) {
+       case SBI_EXT_DBCN_CONSOLE_WRITE:
+       case SBI_EXT_DBCN_CONSOLE_READ:
+       case SBI_EXT_DBCN_CONSOLE_WRITE_BYTE:
+               /*
+                * The SBI debug console functions are unconditionally
+                * forwarded to the userspace.
+                */
+               kvm_riscv_vcpu_sbi_forward(vcpu, run);
+               retdata->uexit = true;
+               break;
+       default:
+               retdata->err_val = SBI_ERR_NOT_SUPPORTED;
+       }
+
+       return 0;
+}
+
+const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_dbcn = {
+       .extid_start = SBI_EXT_DBCN,
+       .extid_end = SBI_EXT_DBCN,
+       .default_unavail = true,
+       .handler = kvm_sbi_ext_dbcn_handler,
+};
index 6115d751497200adabf9f639284fe4a794c48627..90d4ba36d1d0629e7b17aaf7cd9a23922b127d37 100644 (file)
@@ -72,7 +72,7 @@ static inline void mm_fault_error(struct pt_regs *regs, unsigned long addr, vm_f
                }
                pagefault_out_of_memory();
                return;
-       } else if (fault & VM_FAULT_SIGBUS) {
+       } else if (fault & (VM_FAULT_SIGBUS | VM_FAULT_HWPOISON | VM_FAULT_HWPOISON_LARGE)) {
                /* Kernel mode? Handle exceptions or die */
                if (!user_mode(regs)) {
                        no_context(regs, addr);
index 96225a8533ad8002e39518f87c6bab9d0e8ffb5a..b52f0210481facd89623a5f4730421064a0748b8 100644 (file)
@@ -180,17 +180,25 @@ 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)
 {
+       unsigned long hugepage_shift;
        int i, pte_num;
 
-       if (!pte_napot(pte)) {
-               set_pte_at(mm, addr, ptep, pte);
-               return;
-       }
+       if (sz >= PGDIR_SIZE)
+               hugepage_shift = PGDIR_SHIFT;
+       else if (sz >= P4D_SIZE)
+               hugepage_shift = P4D_SHIFT;
+       else if (sz >= PUD_SIZE)
+               hugepage_shift = PUD_SHIFT;
+       else if (sz >= PMD_SIZE)
+               hugepage_shift = PMD_SHIFT;
+       else
+               hugepage_shift = PAGE_SHIFT;
 
-       pte_num = napot_pte_num(napot_cont_order(pte));
-       for (i = 0; i < pte_num; i++, ptep++, addr += PAGE_SIZE)
+       pte_num = sz >> hugepage_shift;
+       for (i = 0; i < pte_num; i++, ptep++, addr += (1 << hugepage_shift))
                set_pte_at(mm, addr, ptep, pte);
 }
 
index ecd3ae6f411679b454963a4f68611c9b38064fbf..8581693e62d39645f814857fb18cd54485e2d132 100644 (file)
@@ -245,7 +245,7 @@ static void __build_epilogue(bool is_tail_call, struct rv_jit_context *ctx)
        emit_addi(RV_REG_SP, RV_REG_SP, stack_adjust, ctx);
        /* Set return value. */
        if (!is_tail_call)
-               emit_mv(RV_REG_A0, RV_REG_A5, ctx);
+               emit_addiw(RV_REG_A0, RV_REG_A5, 0, ctx);
        emit_jalr(RV_REG_ZERO, is_tail_call ? RV_REG_T3 : RV_REG_RA,
                  is_tail_call ? (RV_FENTRY_NINSNS + 1) * 4 : 0, /* skip reserved nops and TCC init */
                  ctx);
@@ -759,8 +759,10 @@ static int invoke_bpf_prog(struct bpf_tramp_link *l, int args_off, int retval_of
        if (ret)
                return ret;
 
-       if (save_ret)
-               emit_sd(RV_REG_FP, -retval_off, regmap[BPF_REG_0], ctx);
+       if (save_ret) {
+               emit_sd(RV_REG_FP, -retval_off, RV_REG_A0, ctx);
+               emit_sd(RV_REG_FP, -(retval_off - 8), regmap[BPF_REG_0], ctx);
+       }
 
        /* update branch with beqz */
        if (ctx->insns) {
@@ -853,7 +855,7 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
 
        save_ret = flags & (BPF_TRAMP_F_CALL_ORIG | BPF_TRAMP_F_RET_FENTRY_RET);
        if (save_ret) {
-               stack_size += 8;
+               stack_size += 16; /* Save both A5 (BPF R0) and A0 */
                retval_off = stack_size;
        }
 
@@ -957,6 +959,7 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
                if (ret)
                        goto out;
                emit_sd(RV_REG_FP, -retval_off, RV_REG_A0, ctx);
+               emit_sd(RV_REG_FP, -(retval_off - 8), regmap[BPF_REG_0], ctx);
                im->ip_after_call = ctx->insns + ctx->ninsns;
                /* 2 nops reserved for auipc+jalr pair */
                emit(rv_nop(), ctx);
@@ -988,8 +991,10 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
        if (flags & BPF_TRAMP_F_RESTORE_REGS)
                restore_args(nregs, args_off, ctx);
 
-       if (save_ret)
+       if (save_ret) {
                emit_ld(RV_REG_A0, -retval_off, RV_REG_FP, ctx);
+               emit_ld(regmap[BPF_REG_0], -(retval_off - 8), RV_REG_FP, ctx);
+       }
 
        emit_ld(RV_REG_S1, -sreg_off, RV_REG_FP, ctx);
 
@@ -1515,7 +1520,8 @@ out_be:
                if (ret)
                        return ret;
 
-               emit_mv(bpf_to_rv_reg(BPF_REG_0, ctx), RV_REG_A0, ctx);
+               if (insn->src_reg != BPF_PSEUDO_CALL)
+                       emit_mv(bpf_to_rv_reg(BPF_REG_0, ctx), RV_REG_A0, ctx);
                break;
        }
        /* tail call */
index 01257ce3b89c00f6fc124e2d4c3d7a331ee4250c..442a74f113cbfdbafdff3bb98ee24c7dbef20ed7 100644 (file)
@@ -57,6 +57,7 @@ static void kasan_populate_shadow(void)
        pmd_t pmd_z = __pmd(__pa(kasan_early_shadow_pte) | _SEGMENT_ENTRY);
        pud_t pud_z = __pud(__pa(kasan_early_shadow_pmd) | _REGION3_ENTRY);
        p4d_t p4d_z = __p4d(__pa(kasan_early_shadow_pud) | _REGION2_ENTRY);
+       unsigned long memgap_start = 0;
        unsigned long untracked_end;
        unsigned long start, end;
        int i;
@@ -101,8 +102,12 @@ static void kasan_populate_shadow(void)
         * +- shadow end ----+---------+- shadow end ---+
         */
 
-       for_each_physmem_usable_range(i, &start, &end)
+       for_each_physmem_usable_range(i, &start, &end) {
                kasan_populate(start, end, POPULATE_KASAN_MAP_SHADOW);
+               if (memgap_start && physmem_info.info_source == MEM_DETECT_DIAG260)
+                       kasan_populate(memgap_start, start, POPULATE_KASAN_ZERO_SHADOW);
+               memgap_start = end;
+       }
        if (IS_ENABLED(CONFIG_KASAN_VMALLOC)) {
                untracked_end = VMALLOC_START;
                /* shallowly populate kasan shadow for vmalloc and modules */
index af2fbe48e16cd9fc22eecdc1be964c8fae4cbb5c..438cd92e60801bd3c12cd1f891c5a9009fe115f8 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 3f263b767a4c4198f098a017dd83db427ecbcc37..1b8150e50f6a65a9d0dadbbf6bb1ee7e2785f8d3 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 e62fb20151028fd53cbf28b065694ee81b778f01..b831083b4edd8b796b949333b5ca279c96eda237 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 f07267875a198760adfb149721c3497044fe478a..deb198a610395bc410bd09a30bdddbfb33b41d65 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 427f9528a7b694820b7f0697940f6d7d06934dfe..67a298b6cf6e9f316ea6178ce64efc837e5caac9 100644 (file)
@@ -777,6 +777,13 @@ struct kvm_vm_stat {
        u64 inject_service_signal;
        u64 inject_virtio;
        u64 aen_forward;
+       u64 gmap_shadow_create;
+       u64 gmap_shadow_reuse;
+       u64 gmap_shadow_r1_entry;
+       u64 gmap_shadow_r2_entry;
+       u64 gmap_shadow_r3_entry;
+       u64 gmap_shadow_sg_entry;
+       u64 gmap_shadow_pg_entry;
 };
 
 struct kvm_arch_memory_slot {
index 3986a044eb367f5ab08f3f8b0e9ac58f834e1236..554447768bddc7d0d27aa16ddbf0727c6ef95d4e 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 6d6bc19b37dcbd25610df55a4e0b06a152187a96..ff8349d17b331a4222d57f826335bd209f359f6e 100644 (file)
@@ -1382,6 +1382,7 @@ static int kvm_s390_shadow_tables(struct gmap *sg, unsigned long saddr,
                                  unsigned long *pgt, int *dat_protection,
                                  int *fake)
 {
+       struct kvm *kvm;
        struct gmap *parent;
        union asce asce;
        union vaddress vaddr;
@@ -1390,6 +1391,7 @@ static int kvm_s390_shadow_tables(struct gmap *sg, unsigned long saddr,
 
        *fake = 0;
        *dat_protection = 0;
+       kvm = sg->private;
        parent = sg->parent;
        vaddr.addr = saddr;
        asce.val = sg->orig_asce;
@@ -1450,6 +1452,7 @@ shadow_r2t:
                rc = gmap_shadow_r2t(sg, saddr, rfte.val, *fake);
                if (rc)
                        return rc;
+               kvm->stat.gmap_shadow_r1_entry++;
        }
                fallthrough;
        case ASCE_TYPE_REGION2: {
@@ -1478,6 +1481,7 @@ shadow_r3t:
                rc = gmap_shadow_r3t(sg, saddr, rste.val, *fake);
                if (rc)
                        return rc;
+               kvm->stat.gmap_shadow_r2_entry++;
        }
                fallthrough;
        case ASCE_TYPE_REGION3: {
@@ -1515,6 +1519,7 @@ shadow_sgt:
                rc = gmap_shadow_sgt(sg, saddr, rtte.val, *fake);
                if (rc)
                        return rc;
+               kvm->stat.gmap_shadow_r3_entry++;
        }
                fallthrough;
        case ASCE_TYPE_SEGMENT: {
@@ -1548,6 +1553,7 @@ shadow_pgt:
                rc = gmap_shadow_pgt(sg, saddr, ste.val, *fake);
                if (rc)
                        return rc;
+               kvm->stat.gmap_shadow_sg_entry++;
        }
        }
        /* Return the parent address of the page table */
@@ -1618,6 +1624,7 @@ shadow_page:
        pte.p |= dat_protection;
        if (!rc)
                rc = gmap_shadow_page(sg, saddr, __pte(pte.val));
+       vcpu->kvm->stat.gmap_shadow_pg_entry++;
        ipte_unlock(vcpu->kvm);
        mmap_read_unlock(sg->mm);
        return rc;
index c1b47d608a2b206debef90c4f59e293ca33011e4..efaebba5ee19c74da0a9d46dd636ab8fc28e50a1 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 b3f17e014cab5d3d912c5393eac5498f3e135591..11676b81e6bf57a03a01bdddf1f6df6175cd36a9 100644 (file)
@@ -66,7 +66,14 @@ const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
        STATS_DESC_COUNTER(VM, inject_pfault_done),
        STATS_DESC_COUNTER(VM, inject_service_signal),
        STATS_DESC_COUNTER(VM, inject_virtio),
-       STATS_DESC_COUNTER(VM, aen_forward)
+       STATS_DESC_COUNTER(VM, aen_forward),
+       STATS_DESC_COUNTER(VM, gmap_shadow_reuse),
+       STATS_DESC_COUNTER(VM, gmap_shadow_create),
+       STATS_DESC_COUNTER(VM, gmap_shadow_r1_entry),
+       STATS_DESC_COUNTER(VM, gmap_shadow_r2_entry),
+       STATS_DESC_COUNTER(VM, gmap_shadow_r3_entry),
+       STATS_DESC_COUNTER(VM, gmap_shadow_sg_entry),
+       STATS_DESC_COUNTER(VM, gmap_shadow_pg_entry),
 };
 
 const struct kvm_stats_header kvm_vm_stats_header = {
@@ -4053,6 +4060,8 @@ static void kvm_gmap_notifier(struct gmap *gmap, unsigned long start,
        unsigned long prefix;
        unsigned long i;
 
+       trace_kvm_s390_gmap_notifier(start, end, gmap_is_shadow(gmap));
+
        if (gmap_is_shadow(gmap))
                return;
        if (start >= 1UL << 31)
index 6f0209d45164f0a6793288a883742f6b52f037d2..9ac92dbf680dbbe7703dd63945968b1cda46cf13 100644 (file)
@@ -333,6 +333,29 @@ TRACE_EVENT(kvm_s390_airq_suppressed,
                      __entry->id, __entry->isc)
        );
 
+/*
+ * Trace point for gmap notifier calls.
+ */
+TRACE_EVENT(kvm_s390_gmap_notifier,
+           TP_PROTO(unsigned long start, unsigned long end, unsigned int shadow),
+           TP_ARGS(start, end, shadow),
+
+           TP_STRUCT__entry(
+                   __field(unsigned long, start)
+                   __field(unsigned long, end)
+                   __field(unsigned int, shadow)
+                   ),
+
+           TP_fast_assign(
+                   __entry->start = start;
+                   __entry->end = end;
+                   __entry->shadow = shadow;
+                   ),
+
+           TP_printk("gmap notified (start:0x%lx end:0x%lx shadow:%d)",
+                     __entry->start, __entry->end, __entry->shadow)
+       );
+
 
 #endif /* _TRACE_KVMS390_H */
 
index 61499293c2ac3b955a7de66a366f955d144ae3b5..02dcbe82a8e512af4bd0f09f974d67d89f938d80 100644 (file)
@@ -1214,8 +1214,10 @@ static int acquire_gmap_shadow(struct kvm_vcpu *vcpu,
         * we're holding has been unshadowed. If the gmap is still valid,
         * we can safely reuse it.
         */
-       if (vsie_page->gmap && gmap_shadow_valid(vsie_page->gmap, asce, edat))
+       if (vsie_page->gmap && gmap_shadow_valid(vsie_page->gmap, asce, edat)) {
+               vcpu->kvm->stat.gmap_shadow_reuse++;
                return 0;
+       }
 
        /* release the old shadow - if any, and mark the prefix as unmapped */
        release_gmap_shadow(vsie_page);
@@ -1223,6 +1225,7 @@ static int acquire_gmap_shadow(struct kvm_vcpu *vcpu,
        if (IS_ERR(gmap))
                return PTR_ERR(gmap);
        gmap->private = vcpu->kvm;
+       vcpu->kvm->stat.gmap_shadow_create++;
        WRITE_ONCE(vsie_page->gmap, gmap);
        return 0;
 }
index c718f2a0de9485ecb695b972509e99dd2eb0fbfa..297a6d897d5a0c0e2e00f271ae23d918c4c6862a 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 de2fb12120d2ed85c330c19bf8d8f3c735e5ecec..e507692e51e71e418545ded2350ca9a2c9ee9a43 100644 (file)
@@ -2066,6 +2066,7 @@ struct bpf_tramp_jit {
                                 * func_addr's original caller
                                 */
        int stack_size;         /* Trampoline stack size */
+       int backchain_off;      /* Offset of backchain */
        int stack_args_off;     /* Offset of stack arguments for calling
                                 * func_addr, has to be at the top
                                 */
@@ -2086,9 +2087,10 @@ struct bpf_tramp_jit {
                                 * for __bpf_prog_enter() return value and
                                 * func_addr respectively
                                 */
-       int r14_off;            /* Offset of saved %r14 */
        int run_ctx_off;        /* Offset of struct bpf_tramp_run_ctx */
        int tccnt_off;          /* Offset of saved tailcall counter */
+       int r14_off;            /* Offset of saved %r14, has to be at the
+                                * bottom */
        int do_fexit;           /* do_fexit: label */
 };
 
@@ -2247,8 +2249,12 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
         * Calculate the stack layout.
         */
 
-       /* Reserve STACK_FRAME_OVERHEAD bytes for the callees. */
+       /*
+        * Allocate STACK_FRAME_OVERHEAD bytes for the callees. As the s390x
+        * ABI requires, put our backchain at the end of the allocated memory.
+        */
        tjit->stack_size = STACK_FRAME_OVERHEAD;
+       tjit->backchain_off = tjit->stack_size - sizeof(u64);
        tjit->stack_args_off = alloc_stack(tjit, nr_stack_args * sizeof(u64));
        tjit->reg_args_off = alloc_stack(tjit, nr_reg_args * sizeof(u64));
        tjit->ip_off = alloc_stack(tjit, sizeof(u64));
@@ -2256,16 +2262,25 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
        tjit->bpf_args_off = alloc_stack(tjit, nr_bpf_args * sizeof(u64));
        tjit->retval_off = alloc_stack(tjit, sizeof(u64));
        tjit->r7_r8_off = alloc_stack(tjit, 2 * sizeof(u64));
-       tjit->r14_off = alloc_stack(tjit, sizeof(u64));
        tjit->run_ctx_off = alloc_stack(tjit,
                                        sizeof(struct bpf_tramp_run_ctx));
        tjit->tccnt_off = alloc_stack(tjit, sizeof(u64));
-       /* The caller has already reserved STACK_FRAME_OVERHEAD bytes. */
-       tjit->stack_size -= STACK_FRAME_OVERHEAD;
+       tjit->r14_off = alloc_stack(tjit, sizeof(u64) * 2);
+       /*
+        * In accordance with the s390x ABI, the caller has allocated
+        * STACK_FRAME_OVERHEAD bytes for us. 8 of them contain the caller's
+        * backchain, and the rest we can use.
+        */
+       tjit->stack_size -= STACK_FRAME_OVERHEAD - sizeof(u64);
        tjit->orig_stack_args_off = tjit->stack_size + STACK_FRAME_OVERHEAD;
 
+       /* lgr %r1,%r15 */
+       EMIT4(0xb9040000, REG_1, REG_15);
        /* aghi %r15,-stack_size */
        EMIT4_IMM(0xa70b0000, REG_15, -tjit->stack_size);
+       /* stg %r1,backchain_off(%r15) */
+       EMIT6_DISP_LH(0xe3000000, 0x0024, REG_1, REG_0, REG_15,
+                     tjit->backchain_off);
        /* mvc tccnt_off(4,%r15),stack_size+STK_OFF_TCCNT(%r15) */
        _EMIT6(0xd203f000 | tjit->tccnt_off,
               0xf000 | (tjit->stack_size + STK_OFF_TCCNT));
@@ -2513,7 +2528,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 2d9b01d7ca4c5c5333fdbe711e2655909655529d..99209085c75bcb8b2a9f81687924aae83fceb78e 100644 (file)
@@ -564,6 +564,17 @@ static void s390_dma_unmap_sg(struct device *dev, struct scatterlist *sg,
                s->dma_length = 0;
        }
 }
+
+static unsigned long *bitmap_vzalloc(size_t bits, gfp_t flags)
+{
+       size_t n = BITS_TO_LONGS(bits);
+       size_t bytes;
+
+       if (unlikely(check_mul_overflow(n, sizeof(unsigned long), &bytes)))
+               return NULL;
+
+       return vzalloc(bytes);
+}
        
 int zpci_dma_init_device(struct zpci_dev *zdev)
 {
@@ -604,13 +615,13 @@ int zpci_dma_init_device(struct zpci_dev *zdev)
                                zdev->end_dma - zdev->start_dma + 1);
        zdev->end_dma = zdev->start_dma + zdev->iommu_size - 1;
        zdev->iommu_pages = zdev->iommu_size >> PAGE_SHIFT;
-       zdev->iommu_bitmap = vzalloc(zdev->iommu_pages / 8);
+       zdev->iommu_bitmap = bitmap_vzalloc(zdev->iommu_pages, GFP_KERNEL);
        if (!zdev->iommu_bitmap) {
                rc = -ENOMEM;
                goto free_dma_table;
        }
        if (!s390_iommu_strict) {
-               zdev->lazy_bitmap = vzalloc(zdev->iommu_pages / 8);
+               zdev->lazy_bitmap = bitmap_vzalloc(zdev->iommu_pages, GFP_KERNEL);
                if (!zdev->lazy_bitmap) {
                        rc = -ENOMEM;
                        goto free_bitmap;
index c33b3daa4ad1a3e6db7e319e229fe08db204dfe8..33d20f34560fd5cb5d69dfe09ba08a16c9e0b496 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 0a26cca24232c0811a0bda5c347c9db8dd206fa3..c714ca6a05aa04b154d0b64f52cb3f7d4c20452b 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 84ad709cbecb4459c50ee9ea279585613c92c0bd..66eda40fce3602e41a9c5004068b7b600ee78a33 100644 (file)
@@ -453,5 +453,5 @@ ccslow:     cmp     %g1, 0
  * we only bother with faults on loads... */
 
 cc_fault:
-       ret
+       retl
         clr    %o0
index d7018823206c13647fa5ddde4103fa9ff18f5cd7..b432500c13a5d8794b2296dec7ac45973b33dbad 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 dc8c876fbd8f8f51c53a26237094dfd6580c8fe2..80d76aea1f7bf19864252287ac7c1a8b4c08fbcd 100644 (file)
@@ -103,6 +103,16 @@ static enum es_result vc_read_mem(struct es_em_ctxt *ctxt,
        return ES_OK;
 }
 
+static enum es_result vc_ioio_check(struct es_em_ctxt *ctxt, u16 port, size_t size)
+{
+       return ES_OK;
+}
+
+static bool fault_in_kernel_space(unsigned long address)
+{
+       return false;
+}
+
 #undef __init
 #define __init
 
index 6c2826417b3376cb70d53df8006f5998a0e33d9c..93c60c0c9d4a7a25d91aef2d948d648e08006abe 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 abadd5f234254ce053c08d49381eb3ec9410958e..e24976593a298a5600dda460c9e81275928343e0 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 76b1f8bb0fd5f1898a837278813f66258399274d..dab4ed199227fe2d5bf0ed2f4d1158288035043e 100644 (file)
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <asm/insn.h>
+#include <linux/mm.h>
 
 #include "perf_event.h"
 
@@ -132,9 +133,9 @@ static int get_branch_type(unsigned long from, unsigned long to, int abort,
                 * The LBR logs any address in the IP, even if the IP just
                 * faulted. This means userspace can control the from address.
                 * Ensure we don't blindly read any address by validating it is
-                * a known text address.
+                * a known text address and not a vsyscall address.
                 */
-               if (kernel_text_address(from)) {
+               if (kernel_text_address(from) && !in_gate_area_no_mm(from)) {
                        addr = (void *)from;
                        /*
                         * Assume we can get the maximum possible size
index 783ed339f3415c09bf83830b0bd854d92e5f31dc..21556ad87f4ba86a076c828b2a88daf76a02c038 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 36a5622180104f29e9c3ab5fc99c8d1bca7a3c6a..999f5ac82fe900d73d319c562319ce9bd77cde98 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 3a233ebff7129c2cf8363527722cef099d5e8550..25050d953eee02d71cb50f585f2f7dcc7482c011 100644 (file)
@@ -28,8 +28,6 @@ struct x86_cpu {
 };
 
 #ifdef CONFIG_HOTPLUG_CPU
-extern int arch_register_cpu(int num);
-extern void arch_unregister_cpu(int);
 extern void soft_restart_cpu(void);
 #endif
 
index 58cb9495e40f426323cd65569cd53145e7b2f9e7..4af140cf5719e6d75f5206d614002210bed782ca 100644 (file)
 
 /* AMD-defined Extended Feature 2 EAX, CPUID level 0x80000021 (EAX), word 20 */
 #define X86_FEATURE_NO_NESTED_DATA_BP  (20*32+ 0) /* "" No Nested Data Breakpoints */
+#define X86_FEATURE_WRMSR_XX_BASE_NS   (20*32+ 1) /* "" WRMSR to {FS,GS,KERNEL_GS}_BASE is non-serializing */
 #define X86_FEATURE_LFENCE_RDTSC       (20*32+ 2) /* "" LFENCE always serializing / synchronizes RDTSC */
 #define X86_FEATURE_NULL_SEL_CLR_BASE  (20*32+ 6) /* "" Null Selector Clears Base */
 #define X86_FEATURE_AUTOIBRS           (20*32+ 8) /* "" Automatic IBRS */
index 31089b851c4f2a8aa39490a08829f4f924931ffa..a2be3aefff9f8974131d08d04830b1e2c8582210 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 637fa1df351246ac16895151e333119281d17890..c715097e92fd2d740860a2c50e78bc762005c716 100644 (file)
@@ -69,6 +69,8 @@ struct legacy_pic {
        void (*make_irq)(unsigned int irq);
 };
 
+void legacy_pic_pcat_compat(void);
+
 extern struct legacy_pic *legacy_pic;
 extern struct legacy_pic null_legacy_pic;
 
index 5fcd85fd64fd8ffab118f0ba0d435490b05c9d10..197316121f04e154dad9ba4d9a7169674c623dd5 100644 (file)
@@ -27,6 +27,7 @@
  *             _X      - regular server parts
  *             _D      - micro server parts
  *             _N,_P   - other mobile parts
+ *             _H      - premium mobile parts
  *             _S      - other client parts
  *
  *             Historical OPTDIFFs:
 #define INTEL_FAM6_METEORLAKE          0xAC
 #define INTEL_FAM6_METEORLAKE_L                0xAA
 
+#define INTEL_FAM6_ARROWLAKE_H         0xC5
 #define INTEL_FAM6_ARROWLAKE           0xC6
 
 #define INTEL_FAM6_LUNARLAKE_M         0xBD
index e3054e3e46d52deaa70480901862b287e2200ee2..9b419f0de713cc720ad348598ac3c5a615426c58 100644 (file)
@@ -108,6 +108,7 @@ KVM_X86_OP_OPTIONAL(vcpu_blocking)
 KVM_X86_OP_OPTIONAL(vcpu_unblocking)
 KVM_X86_OP_OPTIONAL(pi_update_irte)
 KVM_X86_OP_OPTIONAL(pi_start_assignment)
+KVM_X86_OP_OPTIONAL(apicv_pre_state_restore)
 KVM_X86_OP_OPTIONAL(apicv_post_state_restore)
 KVM_X86_OP_OPTIONAL_RET0(dy_apicv_has_pending_interrupt)
 KVM_X86_OP_OPTIONAL(set_hv_timer)
index 17715cb8731d5d2c7d60caeebf6e340158888ef5..db02305eb9e3d4932dfef07248af33709e0f66d5 100644 (file)
 
 #define __KVM_HAVE_ARCH_VCPU_DEBUGFS
 
+/*
+ * CONFIG_KVM_MAX_NR_VCPUS is defined iff CONFIG_KVM!=n, provide a dummy max if
+ * KVM is disabled (arbitrarily use the default from CONFIG_KVM_MAX_NR_VCPUS).
+ */
+#ifdef CONFIG_KVM_MAX_NR_VCPUS
+#define KVM_MAX_VCPUS CONFIG_KVM_MAX_NR_VCPUS
+#else
 #define KVM_MAX_VCPUS 1024
+#endif
 
 /*
  * In x86, the VCPU ID corresponds to the APIC ID, and APIC IDs
@@ -528,7 +536,6 @@ struct kvm_pmu {
        u64 raw_event_mask;
        struct kvm_pmc gp_counters[KVM_INTEL_PMC_MAX_GENERIC];
        struct kvm_pmc fixed_counters[KVM_PMC_MAX_FIXED];
-       struct irq_work irq_work;
 
        /*
         * Overlay the bitmap with a 64-bit atomic so that all bits can be
@@ -1276,7 +1283,6 @@ struct kvm_arch {
         */
        spinlock_t mmu_unsync_pages_lock;
 
-       struct list_head assigned_dev_head;
        struct iommu_domain *iommu_domain;
        bool iommu_noncoherent;
 #define __KVM_HAVE_ARCH_NONCOHERENT_DMA
@@ -1324,6 +1330,7 @@ struct kvm_arch {
        int nr_vcpus_matched_tsc;
 
        u32 default_tsc_khz;
+       bool user_set_tsc;
 
        seqcount_raw_spinlock_t pvclock_sc;
        bool use_master_clock;
@@ -1692,7 +1699,7 @@ struct kvm_x86_ops {
 
        void (*request_immediate_exit)(struct kvm_vcpu *vcpu);
 
-       void (*sched_in)(struct kvm_vcpu *kvm, int cpu);
+       void (*sched_in)(struct kvm_vcpu *vcpu, int cpu);
 
        /*
         * Size of the CPU's dirty log buffer, i.e. VMX's PML buffer.  A zero
@@ -1709,6 +1716,7 @@ struct kvm_x86_ops {
        int (*pi_update_irte)(struct kvm *kvm, unsigned int host_irq,
                              uint32_t guest_irq, bool set);
        void (*pi_start_assignment)(struct kvm *kvm);
+       void (*apicv_pre_state_restore)(struct kvm_vcpu *vcpu);
        void (*apicv_post_state_restore)(struct kvm_vcpu *vcpu);
        bool (*dy_apicv_has_pending_interrupt)(struct kvm_vcpu *vcpu);
 
index 5ff49fd67732e9d9ffbb4152e4a0bbd984e32f99..571fe4d2d2328c3b4899faf8085e0181403ed003 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 416901d406f8a09d98580315759782a6c559d68e..8dac45a2c7fcf236708272ac7379d3d706c13493 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 033b53f993c6e8697e5e14fbc96b0e5d77b931f3..896445edc6a8e924910bd2b04e43e7fee248ee52 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 1d111350197f3169a8eec402d77980dd617c6b95..389f9594746ef58903c59d31a88c2d1e56bd1e25 100644 (file)
 #define MSR_AMD64_CPUID_FN_1           0xc0011004
 #define MSR_AMD64_LS_CFG               0xc0011020
 #define MSR_AMD64_DC_CFG               0xc0011022
+#define MSR_AMD64_TW_CFG               0xc0011023
 
 #define MSR_AMD64_DE_CFG               0xc0011029
 #define MSR_AMD64_DE_CFG_LFENCE_SERIALIZE_BIT   1
 /* AMD Last Branch Record MSRs */
 #define MSR_AMD64_LBR_SELECT                   0xc000010e
 
-/* Fam 17h MSRs */
-#define MSR_F17H_IRPERF                        0xc00000e9
+/* Zen4 */
+#define MSR_ZEN4_BP_CFG                        0xc001102e
+#define MSR_ZEN4_BP_CFG_SHARED_BTB_FIX_BIT 5
 
+/* Zen 2 */
 #define MSR_ZEN2_SPECTRAL_CHICKEN      0xc00110e3
 #define MSR_ZEN2_SPECTRAL_CHICKEN_BIT  BIT_ULL(1)
 
+/* Fam 17h MSRs */
+#define MSR_F17H_IRPERF                        0xc00000e9
+
 /* Fam 16h MSRs */
 #define MSR_F16H_L2I_PERF_CTL          0xc0010230
 #define MSR_F16H_L2I_PERF_CTR          0xc0010231
index 4acbcddddc29f21fc9f21117b653c842430d943c..772d03487520e595ba458ae9032f8a0a2dc00101 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 d6ad98ca1288d22f7b69c05382a404b47427e611..e02b179ec6598900d56dec3196287f46b7818a5a 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 0086920cda061f83f2050822646bfadbc0f474bc..a3669a7774edbbb9f622f2e882b9089ce39f2202 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 ad98dd1d9cfb9f95ac30a67405b52dcd9eddf192..c31c633419fe57c4e4580821dd0f8d96b01cd65b 100644 (file)
@@ -129,7 +129,6 @@ void native_smp_send_reschedule(int cpu);
 void native_send_call_func_ipi(const struct cpumask *mask);
 void native_send_call_func_single_ipi(int cpu);
 
-bool smp_park_other_cpus_in_init(void);
 void smp_store_cpu_info(int id);
 
 asmlinkage __visible void smp_reboot_interrupt(void);
index 19bf955b67e0da097aa7e4187c0feecbf10268e4..3ac0ffc4f3e202b18fab10ee6ecacb6b1ea11a91 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 5fc35f889cd1a29d86f245da3c7e1f993f3cdf4d..7048dfacc04b2413acba1054fb4412c7048b8249 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 2a0ea38955dff0edc5935c890ca878a78ccfac20..c55c0ef47a187eb961616ea6af6eac8e246b1fe0 100644 (file)
@@ -148,6 +148,9 @@ static int __init acpi_parse_madt(struct acpi_table_header *table)
                pr_debug("Local APIC address 0x%08x\n", madt->address);
        }
 
+       if (madt->flags & ACPI_MADT_PCAT_COMPAT)
+               legacy_pic_pcat_compat();
+
        /* ACPI 6.3 and newer support the online capable bit. */
        if (acpi_gbl_FADT.header.revision > 6 ||
            (acpi_gbl_FADT.header.revision == 6 &&
index a5ead6a6d233b2ef4223d5ba54579a69f3042f6f..73be3931e4f0608315093495259100e915702be7 100644 (file)
@@ -403,6 +403,17 @@ void __init_or_module noinline apply_alternatives(struct alt_instr *start,
        u8 insn_buff[MAX_PATCH_LEN];
 
        DPRINTK(ALT, "alt table %px, -> %px", start, end);
+
+       /*
+        * In the case CONFIG_X86_5LEVEL=y, KASAN_SHADOW_START is defined using
+        * cpu_feature_enabled(X86_FEATURE_LA57) and is therefore patched here.
+        * During the process, KASAN becomes confused seeing partial LA57
+        * conversion and triggers a false-positive out-of-bound report.
+        *
+        * Disable KASAN until the patching is complete.
+        */
+       kasan_disable_current();
+
        /*
         * The scan order should be from start to end. A later scanned
         * alternative code can overwrite previously scanned alternative code.
@@ -452,6 +463,8 @@ void __init_or_module noinline apply_alternatives(struct alt_instr *start,
 
                text_poke_early(instr, insn_buff, insn_buff_sz);
        }
+
+       kasan_enable_current();
 }
 
 static inline bool is_jcc32(struct insn *insn)
@@ -720,13 +733,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 c06bfc086565dff236c72c0ab9758c3239c63bcc..faa9f22998488758c5513091b491e99932cd6980 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 dd8379d844452b17dceaa37ff2c6c45e65e1f0e1..ece2b5b7b0fe4ef46eb47828ad3b7d9402749246 100644 (file)
@@ -80,6 +80,10 @@ static const int amd_div0[] =
        AMD_LEGACY_ERRATUM(AMD_MODEL_RANGE(0x17, 0x00, 0x0, 0x2f, 0xf),
                           AMD_MODEL_RANGE(0x17, 0x50, 0x0, 0x5f, 0xf));
 
+static const int amd_erratum_1485[] =
+       AMD_LEGACY_ERRATUM(AMD_MODEL_RANGE(0x19, 0x10, 0x0, 0x1f, 0xf),
+                          AMD_MODEL_RANGE(0x19, 0x60, 0x0, 0xaf, 0xf));
+
 static bool cpu_has_amd_erratum(struct cpuinfo_x86 *cpu, const int *erratum)
 {
        int osvw_id = *erratum++;
@@ -766,6 +770,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)
@@ -1140,6 +1153,10 @@ static void init_amd(struct cpuinfo_x86 *c)
                pr_notice_once("AMD Zen1 DIV0 bug detected. Disable SMT for full protection.\n");
                setup_force_cpu_bug(X86_BUG_DIV0);
        }
+
+       if (!cpu_has(c, X86_FEATURE_HYPERVISOR) &&
+            cpu_has_amd_erratum(c, amd_erratum_1485))
+               msr_set_bit(MSR_ZEN4_BP_CFG, MSR_ZEN4_BP_CFG_SHARED_BTB_FIX_BIT);
 }
 
 #ifdef CONFIG_X86_32
@@ -1301,25 +1318,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 f081d26616ac1ce9aebf720ce3430bece3a02025..10499bcd4e39624827e9641df81eda074bc3cfdc 100644 (file)
@@ -2404,26 +2404,15 @@ 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 382d4e6b848d20f1d927f8687d1e8806acf8ea3d..4e5ffc8b0e469d142c28667359a1f4719f942fd7 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 ded1fc7cb7cb25db65eed339c99bd1638a380122..f136ac046851c87339386968e56301d70069e20c 100644 (file)
@@ -30,15 +30,15 @@ struct rmid_entry {
        struct list_head                list;
 };
 
-/**
- * @rmid_free_lru    A least recently used list of free RMIDs
+/*
+ * @rmid_free_lru - A least recently used list of free RMIDs
  *     These RMIDs are guaranteed to have an occupancy less than the
  *     threshold occupancy
  */
 static LIST_HEAD(rmid_free_lru);
 
-/**
- * @rmid_limbo_count     count of currently unused but (potentially)
+/*
+ * @rmid_limbo_count - count of currently unused but (potentially)
  *     dirty RMIDs.
  *     This counts RMIDs that no one is currently using but that
  *     may have a occupancy value > resctrl_rmid_realloc_threshold. User can
@@ -46,7 +46,7 @@ static LIST_HEAD(rmid_free_lru);
  */
 static unsigned int rmid_limbo_count;
 
-/**
+/*
  * @rmid_entry - The entry in the limbo and free lists.
  */
 static struct rmid_entry       *rmid_ptrs;
index 91fa70e5100413655b4b99629ad72b2843a4836b..279148e7245965dc59198fa3c2705b26aff23f92 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 a86d37052a64810fdbffdc986170490751c069e3..a21a4d0ecc345ba4888865f07a140168f0c3cdda 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 cadf68737e6bc78f12c1c3a444528895d1eba2f9..ef6906107c541d6639cd31bacfdb0bcfb5fb51dc 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 a4ecb04d8d64678030311df00642f4a957f8f70c..3518fb26d06b021144a4f8c1427ad8ee620cb78d 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 30a55207c000139338c5fe305ae38b7f6a9b8524..c20d1832c4812be34dbec593101a088d3351c1f8 100644 (file)
@@ -32,6 +32,7 @@
  */
 static void init_8259A(int auto_eoi);
 
+static bool pcat_compat __ro_after_init;
 static int i8259A_auto_eoi;
 DEFINE_RAW_SPINLOCK(i8259A_lock);
 
@@ -299,15 +300,32 @@ static void unmask_8259A(void)
 
 static int probe_8259A(void)
 {
+       unsigned char new_val, probe_val = ~(1 << PIC_CASCADE_IR);
        unsigned long flags;
-       unsigned char probe_val = ~(1 << PIC_CASCADE_IR);
-       unsigned char new_val;
+
+       /*
+        * If MADT has the PCAT_COMPAT flag set, then do not bother probing
+        * for the PIC. Some BIOSes leave the PIC uninitialized and probing
+        * fails.
+        *
+        * Right now this causes problems as quite some code depends on
+        * nr_legacy_irqs() > 0 or has_legacy_pic() == true. This is silly
+        * when the system has an IO/APIC because then PIC is not required
+        * at all, except for really old machines where the timer interrupt
+        * must be routed through the PIC. So just pretend that the PIC is
+        * there and let legacy_pic->init() initialize it for nothing.
+        *
+        * Alternatively this could just try to initialize the PIC and
+        * repeat the probe, but for cases where there is no PIC that's
+        * just pointless.
+        */
+       if (pcat_compat)
+               return nr_legacy_irqs();
+
        /*
-        * Check to see if we have a PIC.
-        * Mask all except the cascade and read
-        * back the value we just wrote. If we don't
-        * have a PIC, we will read 0xff as opposed to the
-        * value we wrote.
+        * Check to see if we have a PIC.  Mask all except the cascade and
+        * read back the value we just wrote. If we don't have a PIC, we
+        * will read 0xff as opposed to the value we wrote.
         */
        raw_spin_lock_irqsave(&i8259A_lock, flags);
 
@@ -429,5 +447,9 @@ static int __init i8259A_init_ops(void)
 
        return 0;
 }
-
 device_initcall(i8259A_init_ops);
+
+void __init legacy_pic_pcat_compat(void)
+{
+       pcat_compat = true;
+}
index 3a43a2dee658189764c440240c0621225e75c4fb..9c9faa1634fb9ab50907a27f25c6766de8bdd5b8 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 975f98d5eee5dcf46d0b40d63199eb21c5c39c7a..97f1436c1a20348a567ea439aeaa41881448d625 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 9f0909142a0ae38e322b31d7e124589e408f21a0..b6f4e8399fca20ddae6b147fa4209a97b188ec25 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 b9145a63da77d83586eb6fe608bfa0ff617ddd9b..b098b1fa2470816a35d7784d93c0e7ae0fc83f6d 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 2eabccde94fb31b77b738e4b32d614fd35b5b5c8..ccb0915e84e10c025a0320607ae4f90ce76465de 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:
@@ -592,6 +632,23 @@ fail:
        sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SEV_ES_GEN_REQ);
 }
 
+static enum es_result vc_insn_string_check(struct es_em_ctxt *ctxt,
+                                          unsigned long address,
+                                          bool write)
+{
+       if (user_mode(ctxt->regs) && fault_in_kernel_space(address)) {
+               ctxt->fi.vector     = X86_TRAP_PF;
+               ctxt->fi.error_code = X86_PF_USER;
+               ctxt->fi.cr2        = address;
+               if (write)
+                       ctxt->fi.error_code |= X86_PF_WRITE;
+
+               return ES_EXCEPTION;
+       }
+
+       return ES_OK;
+}
+
 static enum es_result vc_insn_string_read(struct es_em_ctxt *ctxt,
                                          void *src, char *buf,
                                          unsigned int data_size,
@@ -599,7 +656,12 @@ static enum es_result vc_insn_string_read(struct es_em_ctxt *ctxt,
                                          bool backwards)
 {
        int i, b = backwards ? -1 : 1;
-       enum es_result ret = ES_OK;
+       unsigned long address = (unsigned long)src;
+       enum es_result ret;
+
+       ret = vc_insn_string_check(ctxt, address, false);
+       if (ret != ES_OK)
+               return ret;
 
        for (i = 0; i < count; i++) {
                void *s = src + (i * data_size * b);
@@ -620,7 +682,12 @@ static enum es_result vc_insn_string_write(struct es_em_ctxt *ctxt,
                                           bool backwards)
 {
        int i, s = backwards ? -1 : 1;
-       enum es_result ret = ES_OK;
+       unsigned long address = (unsigned long)dst;
+       enum es_result ret;
+
+       ret = vc_insn_string_check(ctxt, address, true);
+       if (ret != ES_OK)
+               return ret;
 
        for (i = 0; i < count; i++) {
                void *d = dst + (i * data_size * s);
@@ -656,6 +723,9 @@ static enum es_result vc_insn_string_write(struct es_em_ctxt *ctxt,
 static enum es_result vc_ioio_exitinfo(struct es_em_ctxt *ctxt, u64 *exitinfo)
 {
        struct insn *insn = &ctxt->insn;
+       size_t size;
+       u64 port;
+
        *exitinfo = 0;
 
        switch (insn->opcode.bytes[0]) {
@@ -664,7 +734,7 @@ static enum es_result vc_ioio_exitinfo(struct es_em_ctxt *ctxt, u64 *exitinfo)
        case 0x6d:
                *exitinfo |= IOIO_TYPE_INS;
                *exitinfo |= IOIO_SEG_ES;
-               *exitinfo |= (ctxt->regs->dx & 0xffff) << 16;
+               port       = ctxt->regs->dx & 0xffff;
                break;
 
        /* OUTS opcodes */
@@ -672,41 +742,43 @@ static enum es_result vc_ioio_exitinfo(struct es_em_ctxt *ctxt, u64 *exitinfo)
        case 0x6f:
                *exitinfo |= IOIO_TYPE_OUTS;
                *exitinfo |= IOIO_SEG_DS;
-               *exitinfo |= (ctxt->regs->dx & 0xffff) << 16;
+               port       = ctxt->regs->dx & 0xffff;
                break;
 
        /* IN immediate opcodes */
        case 0xe4:
        case 0xe5:
                *exitinfo |= IOIO_TYPE_IN;
-               *exitinfo |= (u8)insn->immediate.value << 16;
+               port       = (u8)insn->immediate.value & 0xffff;
                break;
 
        /* OUT immediate opcodes */
        case 0xe6:
        case 0xe7:
                *exitinfo |= IOIO_TYPE_OUT;
-               *exitinfo |= (u8)insn->immediate.value << 16;
+               port       = (u8)insn->immediate.value & 0xffff;
                break;
 
        /* IN register opcodes */
        case 0xec:
        case 0xed:
                *exitinfo |= IOIO_TYPE_IN;
-               *exitinfo |= (ctxt->regs->dx & 0xffff) << 16;
+               port       = ctxt->regs->dx & 0xffff;
                break;
 
        /* OUT register opcodes */
        case 0xee:
        case 0xef:
                *exitinfo |= IOIO_TYPE_OUT;
-               *exitinfo |= (ctxt->regs->dx & 0xffff) << 16;
+               port       = ctxt->regs->dx & 0xffff;
                break;
 
        default:
                return ES_DECODE_FAILED;
        }
 
+       *exitinfo |= port << 16;
+
        switch (insn->opcode.bytes[0]) {
        case 0x6c:
        case 0x6e:
@@ -716,12 +788,15 @@ static enum es_result vc_ioio_exitinfo(struct es_em_ctxt *ctxt, u64 *exitinfo)
        case 0xee:
                /* Single byte opcodes */
                *exitinfo |= IOIO_DATA_8;
+               size       = 1;
                break;
        default:
                /* Length determined by instruction parsing */
                *exitinfo |= (insn->opnd_bytes == 2) ? IOIO_DATA_16
                                                     : IOIO_DATA_32;
+               size       = (insn->opnd_bytes == 2) ? 2 : 4;
        }
+
        switch (insn->addr_bytes) {
        case 2:
                *exitinfo |= IOIO_ADDR_16;
@@ -737,7 +812,7 @@ static enum es_result vc_ioio_exitinfo(struct es_em_ctxt *ctxt, u64 *exitinfo)
        if (insn_has_rep_prefix(insn))
                *exitinfo |= IOIO_REP;
 
-       return ES_OK;
+       return vc_ioio_check(ctxt, (u16)port, size);
 }
 
 static enum es_result vc_handle_ioio(struct ghcb *ghcb, struct es_em_ctxt *ctxt)
@@ -848,14 +923,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 +950,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 2787826d9f607798da1d2b2fca4d8550a601eb0c..6395bfd87b68b5948d4096c989e5edfac483e8fb 100644 (file)
@@ -524,6 +524,33 @@ static enum es_result vc_slow_virt_to_phys(struct ghcb *ghcb, struct es_em_ctxt
        return ES_OK;
 }
 
+static enum es_result vc_ioio_check(struct es_em_ctxt *ctxt, u16 port, size_t size)
+{
+       BUG_ON(size > 4);
+
+       if (user_mode(ctxt->regs)) {
+               struct thread_struct *t = &current->thread;
+               struct io_bitmap *iobm = t->io_bitmap;
+               size_t idx;
+
+               if (!iobm)
+                       goto fault;
+
+               for (idx = port; idx < port + size; ++idx) {
+                       if (test_bit(idx, iobm->bitmap))
+                               goto fault;
+               }
+       }
+
+       return ES_OK;
+
+fault:
+       ctxt->fi.vector = X86_TRAP_GP;
+       ctxt->fi.error_code = 0;
+
+       return ES_EXCEPTION;
+}
+
 /* Include code shared with pre-decompression boot stage */
 #include "sev-shared.c"
 
@@ -868,8 +895,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;
@@ -1509,6 +1535,9 @@ static enum es_result vc_handle_mmio(struct ghcb *ghcb, struct es_em_ctxt *ctxt)
                        return ES_DECODE_FAILED;
        }
 
+       if (user_mode(ctxt->regs))
+               return ES_UNSUPPORTED;
+
        switch (mmio) {
        case INSN_MMIO_WRITE:
                memcpy(ghcb->shared_buffer, reg_data, bytes);
index fd689921a1dbad3c4036132d977d9b4bee438b98..59e15dd8d0f86665ef0949b1c7072b9d25205c5e 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 6eb06d001bcc648bc3cdbb71f6e5a9c896d6d1c8..96a771f9f930a6aba1b77967169808bce3b3eace 100644 (file)
@@ -131,7 +131,7 @@ static int smp_stop_nmi_callback(unsigned int val, struct pt_regs *regs)
 }
 
 /*
- * Disable virtualization, APIC etc. and park the CPU in a HLT loop
+ * this function calls the 'stop' function on all other CPUs in the system.
  */
 DEFINE_IDTENTRY_SYSVEC(sysvec_reboot)
 {
@@ -172,17 +172,13 @@ static void native_stop_other_cpus(int wait)
         * 2) Wait for all other CPUs to report that they reached the
         *    HLT loop in stop_this_cpu()
         *
-        * 3) If the system uses INIT/STARTUP for CPU bringup, then
-        *    send all present CPUs an INIT vector, which brings them
-        *    completely out of the way.
+        * 3) If #2 timed out send an NMI to the CPUs which did not
+        *    yet report
         *
-        * 4) If #3 is not possible and #2 timed out send an NMI to the
-        *    CPUs which did not yet report
-        *
-        * 5) Wait for all other CPUs to report that they reached the
+        * 4) Wait for all other CPUs to report that they reached the
         *    HLT loop in stop_this_cpu()
         *
-        * #4 can obviously race against a CPU reaching the HLT loop late.
+        * #3 can obviously race against a CPU reaching the HLT loop late.
         * That CPU will have reported already and the "have all CPUs
         * reached HLT" condition will be true despite the fact that the
         * other CPU is still handling the NMI. Again, there is no
@@ -198,7 +194,7 @@ static void native_stop_other_cpus(int wait)
                /*
                 * Don't wait longer than a second for IPI completion. The
                 * wait request is not checked here because that would
-                * prevent an NMI/INIT shutdown in case that not all
+                * prevent an NMI shutdown attempt in case that not all
                 * CPUs reach shutdown state.
                 */
                timeout = USEC_PER_SEC;
@@ -206,27 +202,7 @@ static void native_stop_other_cpus(int wait)
                        udelay(1);
        }
 
-       /*
-        * Park all other CPUs in INIT including "offline" CPUs, if
-        * possible. That's a safe place where they can't resume execution
-        * of HLT and then execute the HLT loop from overwritten text or
-        * page tables.
-        *
-        * The only downside is a broadcast MCE, but up to the point where
-        * the kexec() kernel brought all APs online again an MCE will just
-        * make HLT resume and handle the MCE. The machine crashes and burns
-        * due to overwritten text, page tables and data. So there is a
-        * choice between fire and frying pan. The result is pretty much
-        * the same. Chose frying pan until x86 provides a sane mechanism
-        * to park a CPU.
-        */
-       if (smp_park_other_cpus_in_init())
-               goto done;
-
-       /*
-        * If park with INIT was not possible and the REBOOT_VECTOR didn't
-        * take all secondary CPUs offline, try with the NMI.
-        */
+       /* if the REBOOT_VECTOR didn't work, try with the NMI */
        if (!cpumask_empty(&cpus_stop_mask)) {
                /*
                 * If NMI IPI is enabled, try to register the stop handler
@@ -249,7 +225,6 @@ static void native_stop_other_cpus(int wait)
                        udelay(1);
        }
 
-done:
        local_irq_save(flags);
        disable_local_APIC();
        mcheck_cpu_clear(this_cpu_ptr(&cpu_info));
index 48e0406187314f1342f6dcffa4552edf9f0291ec..2a187c0cbd5b11ac52f8a0f32d299624b6de0e17 100644 (file)
@@ -1240,33 +1240,6 @@ void arch_thaw_secondary_cpus_end(void)
        cache_aps_init();
 }
 
-bool smp_park_other_cpus_in_init(void)
-{
-       unsigned int cpu, this_cpu = smp_processor_id();
-       unsigned int apicid;
-
-       if (apic->wakeup_secondary_cpu_64 || apic->wakeup_secondary_cpu)
-               return false;
-
-       /*
-        * If this is a crash stop which does not execute on the boot CPU,
-        * then this cannot use the INIT mechanism because INIT to the boot
-        * CPU will reset the machine.
-        */
-       if (this_cpu)
-               return false;
-
-       for_each_cpu_and(cpu, &cpus_booted_once_mask, cpu_present_mask) {
-               if (cpu == this_cpu)
-                       continue;
-               apicid = apic->cpu_present_to_apicid(cpu);
-               if (apicid == BAD_APICID)
-                       continue;
-               send_init_sequence(apicid);
-       }
-       return true;
-}
-
 /*
  * Early setup to make printk work.
  */
index ca004e2e44699ee922998e4c51d891bd391feacb..0bab0313003362ef7549bb820bb8c2b6b59259f9 100644 (file)
@@ -54,7 +54,7 @@ void arch_unregister_cpu(int num)
 EXPORT_SYMBOL(arch_unregister_cpu);
 #else /* CONFIG_HOTPLUG_CPU */
 
-static int __init arch_register_cpu(int num)
+int __init arch_register_cpu(int num)
 {
        return register_cpu(&per_cpu(cpu_devices, num).cpu, num);
 }
index bbc440c93e0881e52c601af434d0c79d90a06fc5..1123ef3ccf9011f55f60d72fb78de75b947b0474 100644 (file)
@@ -15,6 +15,7 @@
  * ( The serial nature of the boot logic and the CPU hotplug lock
  *   protects against more than 2 CPUs entering this code. )
  */
+#include <linux/workqueue.h>
 #include <linux/topology.h>
 #include <linux/spinlock.h>
 #include <linux/kernel.h>
@@ -342,6 +343,13 @@ static inline unsigned int loop_timeout(int cpu)
        return (cpumask_weight(topology_core_cpumask(cpu)) > 1) ? 2 : 20;
 }
 
+static void tsc_sync_mark_tsc_unstable(struct work_struct *work)
+{
+       mark_tsc_unstable("check_tsc_sync_source failed");
+}
+
+static DECLARE_WORK(tsc_sync_work, tsc_sync_mark_tsc_unstable);
+
 /*
  * The freshly booted CPU initiates this via an async SMP function call.
  */
@@ -395,7 +403,7 @@ retry:
                        "turning off TSC clock.\n", max_warp);
                if (random_warps)
                        pr_warn("TSC warped randomly between CPUs\n");
-               mark_tsc_unstable("check_tsc_sync_source failed");
+               schedule_work(&tsc_sync_work);
        }
 
        /*
index ed90f148140dfe093bed15a033b6e322a3cb5f2a..950c12868d304004ff56e7bc95f7c5f395766a33 100644 (file)
@@ -154,4 +154,15 @@ config KVM_PROVE_MMU
 config KVM_EXTERNAL_WRITE_TRACKING
        bool
 
+config KVM_MAX_NR_VCPUS
+       int "Maximum number of vCPUs per KVM guest"
+       depends on KVM
+       range 1024 4096
+       default 4096 if MAXSMP
+       default 1024
+       help
+         Set the maximum number of vCPUs per KVM guest. Larger values will increase
+         the memory footprint of each KVM guest, regardless of how many vCPUs are
+         created for a given VM.
+
 endif # VIRTUALIZATION
index 0544e30b4946d1e5fb40f6737335ac00d58a84b2..6fb3249ae683be3cdb7b5916986482f4c34e3428 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);
@@ -761,11 +753,13 @@ void kvm_set_cpu_caps(void)
 
        kvm_cpu_cap_mask(CPUID_8000_0021_EAX,
                F(NO_NESTED_DATA_BP) | F(LFENCE_RDTSC) | 0 /* SmmPgCfgLock */ |
-               F(NULL_SEL_CLR_BASE) | F(AUTOIBRS) | 0 /* PrefetchCtlMsr */
+               F(NULL_SEL_CLR_BASE) | F(AUTOIBRS) | 0 /* PrefetchCtlMsr */ |
+               F(WRMSR_XX_BASE_NS)
        );
 
-       if (cpu_feature_enabled(X86_FEATURE_SRSO_NO))
-               kvm_cpu_cap_set(X86_FEATURE_SRSO_NO);
+       kvm_cpu_cap_check_and_set(X86_FEATURE_SBPB);
+       kvm_cpu_cap_check_and_set(X86_FEATURE_IBPB_BRTYPE);
+       kvm_cpu_cap_check_and_set(X86_FEATURE_SRSO_NO);
 
        kvm_cpu_cap_init_kvm_defined(CPUID_8000_0022_EAX,
                F(PERFMON_V2)
index 284fa4704553da1345731927225084e7daeeba4b..0b90532b6e261430c7997e933f59f5531312d627 100644 (file)
@@ -174,7 +174,8 @@ static inline bool guest_has_spec_ctrl_msr(struct kvm_vcpu *vcpu)
 static inline bool guest_has_pred_cmd_msr(struct kvm_vcpu *vcpu)
 {
        return (guest_cpuid_has(vcpu, X86_FEATURE_SPEC_CTRL) ||
-               guest_cpuid_has(vcpu, X86_FEATURE_AMD_IBPB));
+               guest_cpuid_has(vcpu, X86_FEATURE_AMD_IBPB) ||
+               guest_cpuid_has(vcpu, X86_FEATURE_SBPB));
 }
 
 static inline bool supports_cpuid_fault(struct kvm_vcpu *vcpu)
index 7c2dac6824e262e0e82f1ed1d7bd564598006713..238afd7335e46d7fcce8d8ad096136cf35bf70b1 100644 (file)
@@ -727,10 +727,12 @@ static int stimer_set_count(struct kvm_vcpu_hv_stimer *stimer, u64 count,
 
        stimer_cleanup(stimer);
        stimer->count = count;
-       if (stimer->count == 0)
-               stimer->config.enable = 0;
-       else if (stimer->config.auto_enable)
-               stimer->config.enable = 1;
+       if (!host) {
+               if (stimer->count == 0)
+                       stimer->config.enable = 0;
+               else if (stimer->config.auto_enable)
+                       stimer->config.enable = 1;
+       }
 
        if (stimer->config.enable)
                stimer_mark_pending(stimer, false);
index dcd60b39e794d95ab4b1b4046a69ec5cf1a9dffc..245b20973caee481055da37cd1ae01a78bbb335b 100644 (file)
@@ -2444,22 +2444,22 @@ EXPORT_SYMBOL_GPL(kvm_lapic_set_eoi);
 void kvm_apic_write_nodecode(struct kvm_vcpu *vcpu, u32 offset)
 {
        struct kvm_lapic *apic = vcpu->arch.apic;
-       u64 val;
 
        /*
-        * ICR is a single 64-bit register when x2APIC is enabled.  For legacy
-        * xAPIC, ICR writes need to go down the common (slightly slower) path
-        * to get the upper half from ICR2.
+        * ICR is a single 64-bit register when x2APIC is enabled, all others
+        * registers hold 32-bit values.  For legacy xAPIC, ICR writes need to
+        * go down the common path to get the upper half from ICR2.
+        *
+        * Note, using the write helpers may incur an unnecessary write to the
+        * virtual APIC state, but KVM needs to conditionally modify the value
+        * in certain cases, e.g. to clear the ICR busy bit.  The cost of extra
+        * conditional branches is likely a wash relative to the cost of the
+        * maybe-unecessary write, and both are in the noise anyways.
         */
-       if (apic_x2apic_mode(apic) && offset == APIC_ICR) {
-               val = kvm_lapic_get_reg64(apic, APIC_ICR);
-               kvm_apic_send_ipi(apic, (u32)val, (u32)(val >> 32));
-               trace_kvm_apic_write(APIC_ICR, val);
-       } else {
-               /* TODO: optimize to just emulate side effect w/o one more write */
-               val = kvm_lapic_get_reg(apic, offset);
-               kvm_lapic_reg_write(apic, offset, (u32)val);
-       }
+       if (apic_x2apic_mode(apic) && offset == APIC_ICR)
+               kvm_x2apic_icr_write(apic, kvm_lapic_get_reg64(apic, APIC_ICR));
+       else
+               kvm_lapic_reg_write(apic, offset, kvm_lapic_get_reg(apic, offset));
 }
 EXPORT_SYMBOL_GPL(kvm_apic_write_nodecode);
 
@@ -2670,6 +2670,8 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event)
        u64 msr_val;
        int i;
 
+       static_call_cond(kvm_x86_apicv_pre_state_restore)(vcpu);
+
        if (!init_event) {
                msr_val = APIC_DEFAULT_PHYS_BASE | MSR_IA32_APICBASE_ENABLE;
                if (kvm_vcpu_is_reset_bsp(vcpu))
@@ -2759,13 +2761,17 @@ int kvm_apic_local_deliver(struct kvm_lapic *apic, int lvt_type)
 {
        u32 reg = kvm_lapic_get_reg(apic, lvt_type);
        int vector, mode, trig_mode;
+       int r;
 
        if (kvm_apic_hw_enabled(apic) && !(reg & APIC_LVT_MASKED)) {
                vector = reg & APIC_VECTOR_MASK;
                mode = reg & APIC_MODE_MASK;
                trig_mode = reg & APIC_LVT_LEVEL_TRIGGER;
-               return __apic_accept_irq(apic, mode, vector, 1, trig_mode,
-                                       NULL);
+
+               r = __apic_accept_irq(apic, mode, vector, 1, trig_mode, NULL);
+               if (r && lvt_type == APIC_LVTPC)
+                       kvm_lapic_set_reg(apic, APIC_LVTPC, reg | APIC_LVT_MASKED);
+               return r;
        }
        return 0;
 }
@@ -2977,6 +2983,8 @@ int kvm_apic_set_state(struct kvm_vcpu *vcpu, struct kvm_lapic_state *s)
        struct kvm_lapic *apic = vcpu->arch.apic;
        int r;
 
+       static_call_cond(kvm_x86_apicv_pre_state_restore)(vcpu);
+
        kvm_lapic_set_base(vcpu, vcpu->arch.apic_base);
        /* set SPIV separately to get count of SW disabled APICs right */
        apic_set_spiv(apic, *((u32 *)(s->regs + APIC_SPIV)));
index edb89b51b3838155f8262431b06f89c2b8fcd6d1..9ae07db6f0f6481e060c260834050e5c5abfe14a 100644 (file)
@@ -93,14 +93,6 @@ void kvm_pmu_ops_update(const struct kvm_pmu_ops *pmu_ops)
 #undef __KVM_X86_PMU_OP
 }
 
-static void kvm_pmi_trigger_fn(struct irq_work *irq_work)
-{
-       struct kvm_pmu *pmu = container_of(irq_work, struct kvm_pmu, irq_work);
-       struct kvm_vcpu *vcpu = pmu_to_vcpu(pmu);
-
-       kvm_pmu_deliver_pmi(vcpu);
-}
-
 static inline void __kvm_perf_overflow(struct kvm_pmc *pmc, bool in_pmi)
 {
        struct kvm_pmu *pmu = pmc_to_pmu(pmc);
@@ -124,20 +116,7 @@ static inline void __kvm_perf_overflow(struct kvm_pmc *pmc, bool in_pmi)
                __set_bit(pmc->idx, (unsigned long *)&pmu->global_status);
        }
 
-       if (!pmc->intr || skip_pmi)
-               return;
-
-       /*
-        * Inject PMI. If vcpu was in a guest mode during NMI PMI
-        * can be ejected on a guest mode re-entry. Otherwise we can't
-        * be sure that vcpu wasn't executing hlt instruction at the
-        * time of vmexit and is not going to re-enter guest mode until
-        * woken up. So we should wake it, but this is impossible from
-        * NMI context. Do it from irq work instead.
-        */
-       if (in_pmi && !kvm_handling_nmi_from_guest(pmc->vcpu))
-               irq_work_queue(&pmc_to_pmu(pmc)->irq_work);
-       else
+       if (pmc->intr && !skip_pmi)
                kvm_make_request(KVM_REQ_PMI, pmc->vcpu);
 }
 
@@ -675,9 +654,6 @@ void kvm_pmu_refresh(struct kvm_vcpu *vcpu)
 
 void kvm_pmu_reset(struct kvm_vcpu *vcpu)
 {
-       struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
-
-       irq_work_sync(&pmu->irq_work);
        static_call(kvm_x86_pmu_reset)(vcpu);
 }
 
@@ -687,7 +663,6 @@ void kvm_pmu_init(struct kvm_vcpu *vcpu)
 
        memset(pmu, 0, sizeof(*pmu));
        static_call(kvm_x86_pmu_init)(vcpu);
-       init_irq_work(&pmu->irq_work, kvm_pmi_trigger_fn);
        pmu->event_count = 0;
        pmu->need_cleanup = false;
        kvm_pmu_refresh(vcpu);
index 7d9ba301c090624c7d69bdf616f3806175eb3ead..1d64113de4883ec77d4aa8c7c83f27a8c01a667d 100644 (file)
@@ -74,6 +74,12 @@ static inline u64 pmc_read_counter(struct kvm_pmc *pmc)
        return counter & pmc_bitmask(pmc);
 }
 
+static inline void pmc_write_counter(struct kvm_pmc *pmc, u64 val)
+{
+       pmc->counter += val - pmc_read_counter(pmc);
+       pmc->counter &= pmc_bitmask(pmc);
+}
+
 static inline void pmc_release_perf_event(struct kvm_pmc *pmc)
 {
        if (pmc->perf_event) {
index b42111a24cc28de2b680b9b495d6f3cb256541ef..dc3d95fdca7d337ef4305123b8f439d2103c8b30 100644 (file)
@@ -324,7 +324,6 @@ void enter_smm(struct kvm_vcpu *vcpu)
 
        cr0 = vcpu->arch.cr0 & ~(X86_CR0_PE | X86_CR0_EM | X86_CR0_TS | X86_CR0_PG);
        static_call(kvm_x86_set_cr0)(vcpu, cr0);
-       vcpu->arch.cr0 = cr0;
 
        static_call(kvm_x86_set_cr4)(vcpu, 0);
 
index 2092db892d7d052a6301396ca753de694c20d8a8..4b74ea91f4e6bb6ea3cea52be67eaeed049c506e 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 dd496c9e5f91f28519ebc27ff6135dbd00ebeada..3fea8c47679e6899742c6f5aa08046da041439a2 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 cef5a3d0abd09664fe58174689aa633221be948d..373ff6a6687b3a7fcb82cc75e1d8e96994161a4b 100644 (file)
@@ -160,7 +160,7 @@ static int amd_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
        /* MSR_PERFCTRn */
        pmc = get_gp_pmc_amd(pmu, msr, PMU_TYPE_COUNTER);
        if (pmc) {
-               pmc->counter += data - pmc_read_counter(pmc);
+               pmc_write_counter(pmc, data);
                pmc_update_sample_period(pmc);
                return 0;
        }
index 9507df93f410a631b1b06acd9937bea881e7b5c9..eb234cdd370b647d3186e6fac3f8758af057c12c 100644 (file)
@@ -199,7 +199,7 @@ module_param_named(npt, npt_enabled, bool, 0444);
 
 /* allow nested virtualization in KVM/SVM */
 static int nested = true;
-module_param(nested, int, S_IRUGO);
+module_param(nested, int, 0444);
 
 /* enable/disable Next RIP Save */
 int nrips = true;
@@ -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 f2efa0bf7ae8d4ce11670f3a05a6a50d6247d5bb..820d3e1f6b4f825fc653e745a4bb839ca2f57416 100644 (file)
@@ -436,11 +436,11 @@ static int intel_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
                        if (!msr_info->host_initiated &&
                            !(msr & MSR_PMC_FULL_WIDTH_BIT))
                                data = (s64)(s32)data;
-                       pmc->counter += data - pmc_read_counter(pmc);
+                       pmc_write_counter(pmc, data);
                        pmc_update_sample_period(pmc);
                        break;
                } else if ((pmc = get_fixed_pmc(pmu, msr))) {
-                       pmc->counter += data - pmc_read_counter(pmc);
+                       pmc_write_counter(pmc, data);
                        pmc_update_sample_period(pmc);
                        break;
                } else if ((pmc = get_gp_pmc(pmu, msr, MSR_P6_EVNTSEL0))) {
index 36724e839269543476d6c8e7855e4604559c94b9..610e37e215be598ea8432b2c018733126ddf0f0c 100644 (file)
@@ -82,28 +82,28 @@ bool __read_mostly enable_vpid = 1;
 module_param_named(vpid, enable_vpid, bool, 0444);
 
 static bool __read_mostly enable_vnmi = 1;
-module_param_named(vnmi, enable_vnmi, bool, S_IRUGO);
+module_param_named(vnmi, enable_vnmi, bool, 0444);
 
 bool __read_mostly flexpriority_enabled = 1;
-module_param_named(flexpriority, flexpriority_enabled, bool, S_IRUGO);
+module_param_named(flexpriority, flexpriority_enabled, bool, 0444);
 
 bool __read_mostly enable_ept = 1;
-module_param_named(ept, enable_ept, bool, S_IRUGO);
+module_param_named(ept, enable_ept, bool, 0444);
 
 bool __read_mostly enable_unrestricted_guest = 1;
 module_param_named(unrestricted_guest,
-                       enable_unrestricted_guest, bool, S_IRUGO);
+                       enable_unrestricted_guest, bool, 0444);
 
 bool __read_mostly enable_ept_ad_bits = 1;
-module_param_named(eptad, enable_ept_ad_bits, bool, S_IRUGO);
+module_param_named(eptad, enable_ept_ad_bits, bool, 0444);
 
 static bool __read_mostly emulate_invalid_guest_state = true;
-module_param(emulate_invalid_guest_state, bool, S_IRUGO);
+module_param(emulate_invalid_guest_state, bool, 0444);
 
 static bool __read_mostly fasteoi = 1;
-module_param(fasteoi, bool, S_IRUGO);
+module_param(fasteoi, bool, 0444);
 
-module_param(enable_apicv, bool, S_IRUGO);
+module_param(enable_apicv, bool, 0444);
 
 bool __read_mostly enable_ipiv = true;
 module_param(enable_ipiv, bool, 0444);
@@ -114,10 +114,10 @@ module_param(enable_ipiv, bool, 0444);
  * use VMX instructions.
  */
 static bool __read_mostly nested = 1;
-module_param(nested, bool, S_IRUGO);
+module_param(nested, bool, 0444);
 
 bool __read_mostly enable_pml = 1;
-module_param_named(pml, enable_pml, bool, S_IRUGO);
+module_param_named(pml, enable_pml, bool, 0444);
 
 static bool __read_mostly error_on_inconsistent_vmcs_config = true;
 module_param(error_on_inconsistent_vmcs_config, bool, 0444);
@@ -6912,7 +6912,7 @@ static void vmx_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
        vmcs_write64(EOI_EXIT_BITMAP3, eoi_exit_bitmap[3]);
 }
 
-static void vmx_apicv_post_state_restore(struct kvm_vcpu *vcpu)
+static void vmx_apicv_pre_state_restore(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
 
@@ -8283,7 +8283,7 @@ static struct kvm_x86_ops vmx_x86_ops __initdata = {
        .set_apic_access_page_addr = vmx_set_apic_access_page_addr,
        .refresh_apicv_exec_ctrl = vmx_refresh_apicv_exec_ctrl,
        .load_eoi_exitmap = vmx_load_eoi_exitmap,
-       .apicv_post_state_restore = vmx_apicv_post_state_restore,
+       .apicv_pre_state_restore = vmx_apicv_pre_state_restore,
        .required_apicv_inhibits = VMX_REQUIRED_APICV_INHIBITS,
        .hwapic_irr_update = vmx_hwapic_irr_update,
        .hwapic_isr_update = vmx_hwapic_isr_update,
index 76d1a6421d46a4a18097136afbde75caee4e623b..3584363b8fa6a50c509009eb9735bba8e442d552 100644 (file)
@@ -145,21 +145,21 @@ EXPORT_STATIC_CALL_GPL(kvm_x86_get_cs_db_l_bits);
 EXPORT_STATIC_CALL_GPL(kvm_x86_cache_reg);
 
 static bool __read_mostly ignore_msrs = 0;
-module_param(ignore_msrs, bool, S_IRUGO | S_IWUSR);
+module_param(ignore_msrs, bool, 0644);
 
 bool __read_mostly report_ignored_msrs = true;
-module_param(report_ignored_msrs, bool, S_IRUGO | S_IWUSR);
+module_param(report_ignored_msrs, bool, 0644);
 EXPORT_SYMBOL_GPL(report_ignored_msrs);
 
 unsigned int min_timer_period_us = 200;
-module_param(min_timer_period_us, uint, S_IRUGO | S_IWUSR);
+module_param(min_timer_period_us, uint, 0644);
 
 static bool __read_mostly kvmclock_periodic_sync = true;
-module_param(kvmclock_periodic_sync, bool, S_IRUGO);
+module_param(kvmclock_periodic_sync, bool, 0444);
 
 /* tsc tolerance in parts per million - default to 1/2 of the NTP threshold */
 static u32 __read_mostly tsc_tolerance_ppm = 250;
-module_param(tsc_tolerance_ppm, uint, S_IRUGO | S_IWUSR);
+module_param(tsc_tolerance_ppm, uint, 0644);
 
 /*
  * lapic timer advance (tscdeadline mode only) in nanoseconds.  '-1' enables
@@ -168,13 +168,13 @@ module_param(tsc_tolerance_ppm, uint, S_IRUGO | S_IWUSR);
  * tuning, i.e. allows privileged userspace to set an exact advancement time.
  */
 static int __read_mostly lapic_timer_advance_ns = -1;
-module_param(lapic_timer_advance_ns, int, S_IRUGO | S_IWUSR);
+module_param(lapic_timer_advance_ns, int, 0644);
 
 static bool __read_mostly vector_hashing = true;
-module_param(vector_hashing, bool, S_IRUGO);
+module_param(vector_hashing, bool, 0444);
 
 bool __read_mostly enable_vmware_backdoor = false;
-module_param(enable_vmware_backdoor, bool, S_IRUGO);
+module_param(enable_vmware_backdoor, bool, 0444);
 EXPORT_SYMBOL_GPL(enable_vmware_backdoor);
 
 /*
@@ -186,7 +186,7 @@ static int __read_mostly force_emulation_prefix;
 module_param(force_emulation_prefix, int, 0644);
 
 int __read_mostly pi_inject_timer = -1;
-module_param(pi_inject_timer, bint, S_IRUGO | S_IWUSR);
+module_param(pi_inject_timer, bint, 0644);
 
 /* Enable/disable PMU virtualization */
 bool __read_mostly enable_pmu = true;
@@ -2331,14 +2331,9 @@ static void kvm_write_wall_clock(struct kvm *kvm, gpa_t wall_clock, int sec_hi_o
        if (kvm_write_guest(kvm, wall_clock, &version, sizeof(version)))
                return;
 
-       /*
-        * The guest calculates current wall clock time by adding
-        * system time (updated by kvm_guest_time_update below) to the
-        * wall clock specified here.  We do the reverse here.
-        */
-       wall_nsec = ktime_get_real_ns() - get_kvmclock_ns(kvm);
+       wall_nsec = kvm_get_wall_clock_epoch(kvm);
 
-       wc.nsec = do_div(wall_nsec, 1000000000);
+       wc.nsec = do_div(wall_nsec, NSEC_PER_SEC);
        wc.sec = (u32)wall_nsec; /* overflow in 2106 guest time */
        wc.version = version;
 
@@ -2714,8 +2709,9 @@ static void __kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 offset, u64 tsc,
        kvm_track_tsc_matching(vcpu);
 }
 
-static void kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 data)
+static void kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 *user_value)
 {
+       u64 data = user_value ? *user_value : 0;
        struct kvm *kvm = vcpu->kvm;
        u64 offset, ns, elapsed;
        unsigned long flags;
@@ -2730,25 +2726,37 @@ static void kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 data)
        if (vcpu->arch.virtual_tsc_khz) {
                if (data == 0) {
                        /*
-                        * detection of vcpu initialization -- need to sync
-                        * with other vCPUs. This particularly helps to keep
-                        * kvm_clock stable after CPU hotplug
+                        * Force synchronization when creating a vCPU, or when
+                        * userspace explicitly writes a zero value.
                         */
                        synchronizing = true;
-               } else {
+               } else if (kvm->arch.user_set_tsc) {
                        u64 tsc_exp = kvm->arch.last_tsc_write +
                                                nsec_to_cycles(vcpu, elapsed);
                        u64 tsc_hz = vcpu->arch.virtual_tsc_khz * 1000LL;
                        /*
-                        * Special case: TSC write with a small delta (1 second)
-                        * of virtual cycle time against real time is
-                        * interpreted as an attempt to synchronize the CPU.
+                        * Here lies UAPI baggage: when a user-initiated TSC write has
+                        * a small delta (1 second) of virtual cycle time against the
+                        * previously set vCPU, we assume that they were intended to be
+                        * in sync and the delta was only due to the racy nature of the
+                        * legacy API.
+                        *
+                        * This trick falls down when restoring a guest which genuinely
+                        * has been running for less time than the 1 second of imprecision
+                        * which we allow for in the legacy API. In this case, the first
+                        * value written by userspace (on any vCPU) should not be subject
+                        * to this 'correction' to make it sync up with values that only
+                        * come from the kernel's default vCPU creation. Make the 1-second
+                        * slop hack only trigger if the user_set_tsc flag is already set.
                         */
                        synchronizing = data < tsc_exp + tsc_hz &&
                                        data + tsc_hz > tsc_exp;
                }
        }
 
+       if (user_value)
+               kvm->arch.user_set_tsc = true;
+
        /*
         * For a reliable TSC, we can match TSC offsets, and for an unstable
         * TSC, we add elapsed time in this computation.  We could let the
@@ -3241,6 +3249,82 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)
        return 0;
 }
 
+/*
+ * The pvclock_wall_clock ABI tells the guest the wall clock time at
+ * which it started (i.e. its epoch, when its kvmclock was zero).
+ *
+ * In fact those clocks are subtly different; wall clock frequency is
+ * adjusted by NTP and has leap seconds, while the kvmclock is a
+ * simple function of the TSC without any such adjustment.
+ *
+ * Perhaps the ABI should have exposed CLOCK_TAI and a ratio between
+ * that and kvmclock, but even that would be subject to change over
+ * time.
+ *
+ * Attempt to calculate the epoch at a given moment using the *same*
+ * TSC reading via kvm_get_walltime_and_clockread() to obtain both
+ * wallclock and kvmclock times, and subtracting one from the other.
+ *
+ * Fall back to using their values at slightly different moments by
+ * calling ktime_get_real_ns() and get_kvmclock_ns() separately.
+ */
+uint64_t kvm_get_wall_clock_epoch(struct kvm *kvm)
+{
+#ifdef CONFIG_X86_64
+       struct pvclock_vcpu_time_info hv_clock;
+       struct kvm_arch *ka = &kvm->arch;
+       unsigned long seq, local_tsc_khz;
+       struct timespec64 ts;
+       uint64_t host_tsc;
+
+       do {
+               seq = read_seqcount_begin(&ka->pvclock_sc);
+
+               local_tsc_khz = 0;
+               if (!ka->use_master_clock)
+                       break;
+
+               /*
+                * The TSC read and the call to get_cpu_tsc_khz() must happen
+                * on the same CPU.
+                */
+               get_cpu();
+
+               local_tsc_khz = get_cpu_tsc_khz();
+
+               if (local_tsc_khz &&
+                   !kvm_get_walltime_and_clockread(&ts, &host_tsc))
+                       local_tsc_khz = 0; /* Fall back to old method */
+
+               put_cpu();
+
+               /*
+                * These values must be snapshotted within the seqcount loop.
+                * After that, it's just mathematics which can happen on any
+                * CPU at any time.
+                */
+               hv_clock.tsc_timestamp = ka->master_cycle_now;
+               hv_clock.system_time = ka->master_kernel_ns + ka->kvmclock_offset;
+
+       } while (read_seqcount_retry(&ka->pvclock_sc, seq));
+
+       /*
+        * If the conditions were right, and obtaining the wallclock+TSC was
+        * successful, calculate the KVM clock at the corresponding time and
+        * subtract one from the other to get the guest's epoch in nanoseconds
+        * since 1970-01-01.
+        */
+       if (local_tsc_khz) {
+               kvm_get_time_scale(NSEC_PER_SEC, local_tsc_khz * NSEC_PER_USEC,
+                                  &hv_clock.tsc_shift,
+                                  &hv_clock.tsc_to_system_mul);
+               return ts.tv_nsec + NSEC_PER_SEC * ts.tv_sec -
+                       __pvclock_read_cycles(&hv_clock, host_tsc);
+       }
+#endif
+       return ktime_get_real_ns() - get_kvmclock_ns(kvm);
+}
+
 /*
  * kvmclock updates which are isolated to a given vcpu, such as
  * vcpu->cpu migration, should not allow system_timestamp from
@@ -3290,9 +3374,6 @@ static void kvmclock_sync_fn(struct work_struct *work)
                                           kvmclock_sync_work);
        struct kvm *kvm = container_of(ka, struct kvm, arch);
 
-       if (!kvmclock_periodic_sync)
-               return;
-
        schedule_delayed_work(&kvm->arch.kvmclock_update_work, 0);
        schedule_delayed_work(&kvm->arch.kvmclock_sync_work,
                                        KVMCLOCK_SYNC_PERIOD);
@@ -3641,6 +3722,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
        case MSR_AMD64_PATCH_LOADER:
        case MSR_AMD64_BU_CFG2:
        case MSR_AMD64_DC_CFG:
+       case MSR_AMD64_TW_CFG:
        case MSR_F15H_EX_CFG:
                break;
 
@@ -3670,17 +3752,36 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
                vcpu->arch.perf_capabilities = data;
                kvm_pmu_refresh(vcpu);
                break;
-       case MSR_IA32_PRED_CMD:
-               if (!msr_info->host_initiated && !guest_has_pred_cmd_msr(vcpu))
-                       return 1;
+       case MSR_IA32_PRED_CMD: {
+               u64 reserved_bits = ~(PRED_CMD_IBPB | PRED_CMD_SBPB);
+
+               if (!msr_info->host_initiated) {
+                       if ((!guest_has_pred_cmd_msr(vcpu)))
+                               return 1;
+
+                       if (!guest_cpuid_has(vcpu, X86_FEATURE_SPEC_CTRL) &&
+                           !guest_cpuid_has(vcpu, X86_FEATURE_AMD_IBPB))
+                               reserved_bits |= PRED_CMD_IBPB;
+
+                       if (!guest_cpuid_has(vcpu, X86_FEATURE_SBPB))
+                               reserved_bits |= PRED_CMD_SBPB;
+               }
+
+               if (!boot_cpu_has(X86_FEATURE_IBPB))
+                       reserved_bits |= PRED_CMD_IBPB;
 
-               if (!boot_cpu_has(X86_FEATURE_IBPB) || (data & ~PRED_CMD_IBPB))
+               if (!boot_cpu_has(X86_FEATURE_SBPB))
+                       reserved_bits |= PRED_CMD_SBPB;
+
+               if (data & reserved_bits)
                        return 1;
+
                if (!data)
                        break;
 
-               wrmsrl(MSR_IA32_PRED_CMD, PRED_CMD_IBPB);
+               wrmsrl(MSR_IA32_PRED_CMD, data);
                break;
+       }
        case MSR_IA32_FLUSH_CMD:
                if (!msr_info->host_initiated &&
                    !guest_cpuid_has(vcpu, X86_FEATURE_FLUSH_L1D))
@@ -3700,13 +3801,16 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
                data &= ~(u64)0x100;    /* ignore ignne emulation enable */
                data &= ~(u64)0x8;      /* ignore TLB cache disable */
 
-               /* Handle McStatusWrEn */
-               if (data == BIT_ULL(18)) {
-                       vcpu->arch.msr_hwcr = data;
-               } else if (data != 0) {
+               /*
+                * Allow McStatusWrEn and TscFreqSel. (Linux guests from v3.2
+                * through at least v6.6 whine if TscFreqSel is clear,
+                * depending on F/M/S.
+                */
+               if (data & ~(BIT_ULL(18) | BIT_ULL(24))) {
                        kvm_pr_unimpl_wrmsr(vcpu, msr, data);
                        return 1;
                }
+               vcpu->arch.msr_hwcr = data;
                break;
        case MSR_FAM10H_MMIO_CONF_BASE:
                if (data != 0) {
@@ -3777,7 +3881,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
                break;
        case MSR_IA32_TSC:
                if (msr_info->host_initiated) {
-                       kvm_synchronize_tsc(vcpu, data);
+                       kvm_synchronize_tsc(vcpu, &data);
                } else {
                        u64 adj = kvm_compute_l1_tsc_offset(vcpu, data) - vcpu->arch.l1_tsc_offset;
                        adjust_tsc_offset_guest(vcpu, adj);
@@ -4065,6 +4169,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
        case MSR_AMD64_BU_CFG2:
        case MSR_IA32_PERF_CTL:
        case MSR_AMD64_DC_CFG:
+       case MSR_AMD64_TW_CFG:
        case MSR_F15H_EX_CFG:
        /*
         * Intel Sandy Bridge CPUs must support the RAPL (running average power
@@ -5382,26 +5487,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,
@@ -5536,6 +5652,7 @@ static int kvm_arch_tsc_set_attr(struct kvm_vcpu *vcpu,
                tsc = kvm_scale_tsc(rdtsc(), vcpu->arch.l1_tsc_scaling_ratio) + offset;
                ns = get_kvmclock_base_ns();
 
+               kvm->arch.user_set_tsc = true;
                __kvm_synchronize_tsc(vcpu, offset, tsc, ns, matched);
                raw_spin_unlock_irqrestore(&kvm->arch.tsc_write_lock, flags);
 
@@ -6248,6 +6365,9 @@ void kvm_arch_sync_dirty_log(struct kvm *kvm, struct kvm_memory_slot *memslot)
        struct kvm_vcpu *vcpu;
        unsigned long i;
 
+       if (!kvm_x86_ops.cpu_dirty_log_size)
+               return;
+
        kvm_for_each_vcpu(i, vcpu, kvm)
                kvm_vcpu_kick(vcpu);
 }
@@ -11521,7 +11641,6 @@ static int __set_sregs_common(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs,
 
        *mmu_reset_needed |= kvm_read_cr0(vcpu) != sregs->cr0;
        static_call(kvm_x86_set_cr0)(vcpu, sregs->cr0);
-       vcpu->arch.cr0 = sregs->cr0;
 
        *mmu_reset_needed |= kvm_read_cr4(vcpu) != sregs->cr4;
        static_call(kvm_x86_set_cr4)(vcpu, sregs->cr4);
@@ -11565,8 +11684,10 @@ static int __set_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
        if (ret)
                return ret;
 
-       if (mmu_reset_needed)
+       if (mmu_reset_needed) {
                kvm_mmu_reset_context(vcpu);
+               kvm_make_request(KVM_REQ_TLB_FLUSH_GUEST, vcpu);
+       }
 
        max_bits = KVM_NR_INTERRUPTS;
        pending_vec = find_first_bit(
@@ -11607,8 +11728,10 @@ static int __set_sregs2(struct kvm_vcpu *vcpu, struct kvm_sregs2 *sregs2)
                mmu_reset_needed = 1;
                vcpu->arch.pdptrs_from_userspace = true;
        }
-       if (mmu_reset_needed)
+       if (mmu_reset_needed) {
                kvm_mmu_reset_context(vcpu);
+               kvm_make_request(KVM_REQ_TLB_FLUSH_GUEST, vcpu);
+       }
        return 0;
 }
 
@@ -11959,7 +12082,7 @@ void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
        if (mutex_lock_killable(&vcpu->mutex))
                return;
        vcpu_load(vcpu);
-       kvm_synchronize_tsc(vcpu, 0);
+       kvm_synchronize_tsc(vcpu, NULL);
        vcpu_put(vcpu);
 
        /* poll control enabled by default */
@@ -12315,7 +12438,6 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
                goto out_uninit_mmu;
 
        INIT_HLIST_HEAD(&kvm->arch.mask_notifier_list);
-       INIT_LIST_HEAD(&kvm->arch.assigned_dev_head);
        atomic_set(&kvm->arch.noncoherent_dma_count, 0);
 
        /* Reserve bit 0 of irq_sources_bitmap for userspace irq source */
@@ -12843,6 +12965,9 @@ static inline bool kvm_vcpu_has_events(struct kvm_vcpu *vcpu)
                return true;
 #endif
 
+       if (kvm_test_request(KVM_REQ_PMI, vcpu))
+               return true;
+
        if (kvm_arch_interrupt_allowed(vcpu) &&
            (kvm_cpu_has_interrupt(vcpu) ||
            kvm_guest_apic_has_interrupt(vcpu)))
index 1e7be1f6ab299d78a76e76385db159dee679220b..5184fde1dc541a90ca150f16d71eb2bd9506b4af 100644 (file)
@@ -293,6 +293,7 @@ static inline bool kvm_check_has_quirk(struct kvm *kvm, u64 quirk)
 void kvm_inject_realmode_interrupt(struct kvm_vcpu *vcpu, int irq, int inc_eip);
 
 u64 get_kvmclock_ns(struct kvm *kvm);
+uint64_t kvm_get_wall_clock_epoch(struct kvm *kvm);
 
 int kvm_read_guest_virt(struct kvm_vcpu *vcpu,
        gva_t addr, void *val, unsigned int bytes,
index 40edf4d1974c530336e9f9044fd3b18b18ea8de3..b946d9f280306724cf34091a65358fee6217639a 100644 (file)
@@ -59,7 +59,7 @@ static int kvm_xen_shared_info_init(struct kvm *kvm, gfn_t gfn)
                 * This code mirrors kvm_write_wall_clock() except that it writes
                 * directly through the pfn cache and doesn't mark the page dirty.
                 */
-               wall_nsec = ktime_get_real_ns() - get_kvmclock_ns(kvm);
+               wall_nsec = kvm_get_wall_clock_epoch(kvm);
 
                /* It could be invalid again already, so we need to check */
                read_lock_irq(&gpc->lock);
@@ -98,7 +98,7 @@ static int kvm_xen_shared_info_init(struct kvm *kvm, gfn_t gfn)
        wc_version = wc->version = (wc->version + 1) | 1;
        smp_wmb();
 
-       wc->nsec = do_div(wall_nsec,  1000000000);
+       wc->nsec = do_div(wall_nsec, NSEC_PER_SEC);
        wc->sec = (u32)wall_nsec;
        *wc_sec_hi = wall_nsec >> 32;
        smp_wmb();
index 8f95fb267caa7c91d066002838198106ef052199..76697df8dfd5bf912fae0c4983f269434151a834 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 0559b206fb1109c459d4a74b50dd6226f69a8153..ccdf3a597045e4c1a8df2146d7a4afdf0376bc3a 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 7c59a704c4584bf7ef3e6a50f2021c31e6f15029..3d818b849ec64b865e857a2cc0f3d99a1df9d1f1 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 863d0d6b3edc47e06346c378356b412ba2358707..7250d0e0e1a98cf8490e4b83e0ac13d44979772a 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 b8db2148c07d525a543ecdd1ed4be5da236fc81c..0337392a3121412f8afe2946f48ff03646f780fa 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 9a192f51f1b0216dd4e0f8cb101d49f58326fbeb..3f8c34707c50014d9364f0430728446e35059d8f 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 49352fad7d1de671094c98630426be11cd12e8d3..bbbfdd495ebd3ac590fd152e0504c6bedae611de 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 1652c39e3dfbd309278f887233c026736a96b9a2..b6830554ff6905633fc543fb39e1b5b4a024bb07 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 1c51b2c87f30a12dfb8d022c54de1f88046234ef..c3867b585e0d8d56419c5a6641f5c2eeb3a30a16 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 a65b7a9ebff281bd510139f93ae43b42837607ee..d8b0fadf429a97fc57b7ac06b76eee6e846018a0 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 e3ecd743c5153d3437e501280fa36b35177fb8a4..b89189355122a6a10ac1f39bdbd9e689d33cfe89 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 3f5ffae89b580e6980729340b3247c13b0a786b9..6f02f6f21890fd5a71ba291d799e12c0d1deac63 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 9f119c1ca0b5d8dac50613b3fa27f5a1cb303451..9ec86f440a48e8e0ba97a876fdae6c19d7983801 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 a6d09fe0483110e46aaa8c48333d52677e2c86c0..d008a153a2b9f7a9782b5874643f2d5a3741e995 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 308f209a4740790762dd6b2cbd9973bdf9259496..a270467556dc84df2c6ceb0786acee3669a059f8 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 5dc5bf8cdd77bdf51c1d915a9a662028d7493544..e446e6fc45579484cd549b7664681c7a17abb6c8 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 50889935138ad2170b1e4c57aaccbf9551fdf997..8c3ceb4270180bd2d747d7952754b3d5dab947b3 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 285fb2942b06593a585e154f32fa67d920afc295..1eeecd58eb0c822ab4d066aff411a31a211d8c96 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 42f106004400ca0b9047610052b79aad9717ca6c..b1e410f6b5ab8e043759b66693f86eae90b668fd 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 f29477162edefdff2bee2eeb3017f1b8e5947f55..9056cd1a8302cdcd8ca5b4ac3d4a8a3ac7ffdaef 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 5c01d7e70d90da4a0f495273180005cf235f4a7c..81f0b106cfc19144433fdaaf593f75d61a657383 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 07dd6baf18cf8d1b47510e012f3d2dc0ad9b1dfc..94a23f1007264af2f0f313786b3b92a4ddab641f 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 f643ea5e36dab50fd21fad55706118785247837a..831ffb648bda7e160408fd97530eddee760c27fc 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 427c125a137aae95b8635d860c609c60fa500883..38092d21acf8e4b285e649cbea6b3bc6920bfa7c 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 8c7a94a0c5d07937eeea538c5882e0854b79d3ca..5da501b57813646ef2cfa59b96bd9cd05fe0c52d 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 d1eb8d6c5b826702b87e289b5737310cb9695995..16e11b6f6f78ed1f2fbc33e460a607128aa7788a 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 0a11fc5f185b7f17380f648a0d2d2672915de4bb..4f974b74883caeb7960d8f825f0759ca3f40d16e 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 85c82cd42188aff4181210953ccded5729e136cf..e89f27f2bb18dabc13a7de5f3719cff77a2752c0 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 167be74df4eeca66c175a1e77f2a274cc6602ba8..dd7310c94713c954aac5d511147f6feb2d27663e 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 38a881cf97d0b4d4f8cd6b321ead22d055c46aa7..13e4377a8b2865f527019830074e0febbd7a766e 100644 (file)
@@ -723,6 +723,12 @@ static unsigned int calculate_io_allowed(u32 iops_limit,
 
 static u64 calculate_bytes_allowed(u64 bps_limit, unsigned long jiffy_elapsed)
 {
+       /*
+        * Can result be wider than 64 bits?
+        * We check against 62, not 64, due to ilog2 truncation.
+        */
+       if (ilog2(bps_limit) + ilog2(jiffy_elapsed) - ilog2(HZ) > 62)
+               return U64_MAX;
        return mul_u64_u64_div_u64(bps_limit, (u64)jiffy_elapsed, (u64)HZ);
 }
 
index 422db8292d0997972cc4c62516a7e312aae421b5..13c3372c465a395d32035a6cf32a93f2a886a6a7 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 acff3d5d22d461af733814b8ce841324e5c87c7c..73e42742543f6a62975f0f94c90a6d6f42e3eaff 100644 (file)
@@ -772,24 +772,35 @@ static long blkdev_fallocate(struct file *file, int mode, loff_t start,
 
        filemap_invalidate_lock(inode->i_mapping);
 
-       /* Invalidate the page cache, including dirty pages. */
-       error = truncate_bdev_range(bdev, file_to_blk_mode(file), start, end);
-       if (error)
-               goto fail;
-
+       /*
+        * Invalidate the page cache, including dirty pages, for valid
+        * de-allocate mode calls to fallocate().
+        */
        switch (mode) {
        case FALLOC_FL_ZERO_RANGE:
        case FALLOC_FL_ZERO_RANGE | FALLOC_FL_KEEP_SIZE:
+               error = truncate_bdev_range(bdev, file_to_blk_mode(file), start, end);
+               if (error)
+                       goto fail;
+
                error = blkdev_issue_zeroout(bdev, start >> SECTOR_SHIFT,
                                             len >> SECTOR_SHIFT, GFP_KERNEL,
                                             BLKDEV_ZERO_NOUNMAP);
                break;
        case FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE:
+               error = truncate_bdev_range(bdev, file_to_blk_mode(file), start, end);
+               if (error)
+                       goto fail;
+
                error = blkdev_issue_zeroout(bdev, start >> SECTOR_SHIFT,
                                             len >> SECTOR_SHIFT, GFP_KERNEL,
                                             BLKDEV_ZERO_NOFALLBACK);
                break;
        case FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE | FALLOC_FL_NO_HIDE_STALE:
+               error = truncate_bdev_range(bdev, file_to_blk_mode(file), start, end);
+               if (error)
+                       goto fail;
+
                error = blkdev_issue_discard(bdev, start >> SECTOR_SHIFT,
                                             len >> SECTOR_SHIFT, GFP_KERNEL);
                break;
index 6d7f25d1711ba7be464f8cf444426f9337181d52..04f38a3f5d9597927534e15d4dc3432fe12f9e3a 100644 (file)
@@ -2888,12 +2888,11 @@ static int opal_lock_unlock(struct opal_dev *dev,
        if (lk_unlk->session.who > OPAL_USER9)
                return -EINVAL;
 
-       ret = opal_get_key(dev, &lk_unlk->session.opal_key);
-       if (ret)
-               return ret;
        mutex_lock(&dev->dev_lock);
        opal_lock_check_for_saved_key(dev, lk_unlk);
-       ret = __opal_lock_unlock(dev, lk_unlk);
+       ret = opal_get_key(dev, &lk_unlk->session.opal_key);
+       if (!ret)
+               ret = __opal_lock_unlock(dev, lk_unlk);
        mutex_unlock(&dev->dev_lock);
 
        return ret;
index abeecb8329b3d5acc61348aebdb0329cedcf2369..1dcab27986a6a1b54b3957e08047f5c0ba05dfa6 100644 (file)
@@ -81,14 +81,13 @@ software_key_determine_akcipher(const struct public_key *pkey,
                 * RSA signatures usually use EMSA-PKCS1-1_5 [RFC3447 sec 8.2].
                 */
                if (strcmp(encoding, "pkcs1") == 0) {
+                       *sig = op == kernel_pkey_sign ||
+                              op == kernel_pkey_verify;
                        if (!hash_algo) {
-                               *sig = false;
                                n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME,
                                             "pkcs1pad(%s)",
                                             pkey->pkey_algo);
                        } else {
-                               *sig = op == kernel_pkey_sign ||
-                                      op == kernel_pkey_verify;
                                n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME,
                                             "pkcs1pad(%s,%s)",
                                             pkey->pkey_algo, hash_algo);
index 285b3cb7c0bc781b4c8be08b1c2c32a931ad0c3c..5ab120d74c592b77dd53c9a44a9c68ab9138f5dd 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 ba79f397c9e8ed92ba5240dac46737be75f00c18..7e9359611d69ca6fd93cc5c5731da797bc0d964c 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);
 
@@ -367,14 +367,19 @@ int ivpu_boot(struct ivpu_device *vdev)
        return 0;
 }
 
-int ivpu_shutdown(struct ivpu_device *vdev)
+void ivpu_prepare_for_reset(struct ivpu_device *vdev)
 {
-       int ret;
-
        ivpu_hw_irq_disable(vdev);
        disable_irq(vdev->irq);
        ivpu_ipc_disable(vdev);
        ivpu_mmu_disable(vdev);
+}
+
+int ivpu_shutdown(struct ivpu_device *vdev)
+{
+       int ret;
+
+       ivpu_prepare_for_reset(vdev);
 
        ret = ivpu_hw_power_down(vdev);
        if (ret)
@@ -634,6 +639,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 9e8c075fe9ef15c447a6705ae5845d9a7792bd2f..2adc349126bb6622b86e6bfbd5bc9df00b8d4c17 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
@@ -150,6 +151,7 @@ void ivpu_file_priv_put(struct ivpu_file_priv **link);
 
 int ivpu_boot(struct ivpu_device *vdev);
 int ivpu_shutdown(struct ivpu_device *vdev);
+void ivpu_prepare_for_reset(struct ivpu_device *vdev);
 
 static inline u8 ivpu_revision(struct ivpu_device *vdev)
 {
@@ -165,6 +167,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 9827ea4d7b83b46483a26fd2d9a0e622bc4fa9cf..a277bbae78fc45ab6e164ab3b705408833b97239 100644 (file)
@@ -432,6 +432,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;
+               wmb(); /* Flush WC buffers after writing save_restore_ret_address */
                return;
        }
 
index ab341237bcf97a45608d35f965e4d3e2895f91e5..1079e06255ba6dd33b375b2485611a012eeb6d6f 100644 (file)
@@ -13,6 +13,7 @@ struct ivpu_hw_ops {
        int (*power_up)(struct ivpu_device *vdev);
        int (*boot_fw)(struct ivpu_device *vdev);
        int (*power_down)(struct ivpu_device *vdev);
+       int (*reset)(struct ivpu_device *vdev);
        bool (*is_idle)(struct ivpu_device *vdev);
        void (*wdt_disable)(struct ivpu_device *vdev);
        void (*diagnose_failure)(struct ivpu_device *vdev);
@@ -91,6 +92,13 @@ static inline int ivpu_hw_power_down(struct ivpu_device *vdev)
        return vdev->hw->ops->power_down(vdev);
 };
 
+static inline int ivpu_hw_reset(struct ivpu_device *vdev)
+{
+       ivpu_dbg(vdev, PM, "HW reset\n");
+
+       return vdev->hw->ops->reset(vdev);
+};
+
 static inline void ivpu_hw_wdt_disable(struct ivpu_device *vdev)
 {
        vdev->hw->ops->wdt_disable(vdev);
index 9eae1c241bc0e51f86b394b7aabb05e7936a59aa..18be8b98e9a8b3efb370261622e6a8e12b455642 100644 (file)
@@ -940,9 +940,6 @@ static u32 ivpu_hw_37xx_irqb_handler(struct ivpu_device *vdev, int irq)
        if (status == 0)
                return 0;
 
-       /* Disable global interrupt before handling local buttress interrupts */
-       REGB_WR32(VPU_37XX_BUTTRESS_GLOBAL_INT_MASK, 0x1);
-
        if (REG_TEST_FLD(VPU_37XX_BUTTRESS_INTERRUPT_STAT, FREQ_CHANGE, status))
                ivpu_dbg(vdev, IRQ, "FREQ_CHANGE irq: %08x",
                         REGB_RD32(VPU_37XX_BUTTRESS_CURRENT_PLL));
@@ -974,9 +971,6 @@ static u32 ivpu_hw_37xx_irqb_handler(struct ivpu_device *vdev, int irq)
        else
                REGB_WR32(VPU_37XX_BUTTRESS_INTERRUPT_STAT, status);
 
-       /* Re-enable global interrupt */
-       REGB_WR32(VPU_37XX_BUTTRESS_GLOBAL_INT_MASK, 0x0);
-
        if (schedule_recovery)
                ivpu_pm_schedule_recovery(vdev);
 
@@ -988,9 +982,14 @@ static irqreturn_t ivpu_hw_37xx_irq_handler(int irq, void *ptr)
        struct ivpu_device *vdev = ptr;
        u32 ret_irqv, ret_irqb;
 
+       REGB_WR32(VPU_37XX_BUTTRESS_GLOBAL_INT_MASK, 0x1);
+
        ret_irqv = ivpu_hw_37xx_irqv_handler(vdev, irq);
        ret_irqb = ivpu_hw_37xx_irqb_handler(vdev, irq);
 
+       /* Re-enable global interrupts to re-trigger MSI for pending interrupts */
+       REGB_WR32(VPU_37XX_BUTTRESS_GLOBAL_INT_MASK, 0x0);
+
        return IRQ_RETVAL(ret_irqb | ret_irqv);
 }
 
@@ -1029,6 +1028,7 @@ const struct ivpu_hw_ops ivpu_hw_37xx_ops = {
        .power_up = ivpu_hw_37xx_power_up,
        .is_idle = ivpu_hw_37xx_is_idle,
        .power_down = ivpu_hw_37xx_power_down,
+       .reset = ivpu_hw_37xx_reset,
        .boot_fw = ivpu_hw_37xx_boot_fw,
        .wdt_disable = ivpu_hw_37xx_wdt_disable,
        .diagnose_failure = ivpu_hw_37xx_diagnose_failure,
index 34626d66fa10284263435dda3c62866ce6853d55..85171a408363fae483846bf86a0975a47bb28762 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;
 
@@ -1160,6 +1179,7 @@ const struct ivpu_hw_ops ivpu_hw_40xx_ops = {
        .power_up = ivpu_hw_40xx_power_up,
        .is_idle = ivpu_hw_40xx_is_idle,
        .power_down = ivpu_hw_40xx_power_down,
+       .reset = ivpu_hw_40xx_reset,
        .boot_fw = ivpu_hw_40xx_boot_fw,
        .wdt_disable = ivpu_hw_40xx_wdt_disable,
        .diagnose_failure = ivpu_hw_40xx_diagnose_failure,
index 5139cfe88532b9afd3e34c1ac13e63aeb547581f..ff4a5d4f58215f6a4cf9851d499c9bfeb0b38e0f 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 fa0af59e39ab66f0a0c20d8e4bfc4892c2ff7426..295c0d7b50398ede66f44b01e5aa31ab9f151ddf 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 1d2e554e2c4a071d6b6974051252762c9ee2e790..ce94f4029127138618b9bb548f3ded0f9a603178 100644 (file)
@@ -11,6 +11,7 @@
 #include "ivpu_mmu.h"
 #include "ivpu_mmu_context.h"
 
+#define IVPU_MMU_VPU_ADDRESS_MASK        GENMASK(47, 12)
 #define IVPU_MMU_PGD_INDEX_MASK          GENMASK(47, 39)
 #define IVPU_MMU_PUD_INDEX_MASK          GENMASK(38, 30)
 #define IVPU_MMU_PMD_INDEX_MASK          GENMASK(29, 21)
@@ -328,12 +329,8 @@ ivpu_mmu_context_map_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx,
 
        if (!IS_ALIGNED(vpu_addr, IVPU_MMU_PAGE_SIZE))
                return -EINVAL;
-       /*
-        * VPU is only 32 bit, but DMA engine is 38 bit
-        * Ranges < 2 GB are reserved for VPU internal registers
-        * Limit range to 8 GB
-        */
-       if (vpu_addr < SZ_2G || vpu_addr > SZ_8G)
+
+       if (vpu_addr & ~IVPU_MMU_VPU_ADDRESS_MASK)
                return -EINVAL;
 
        prot = IVPU_MMU_ENTRY_MAPPED;
index e6f27daf5560b691a8483ff7963f89aa69dbea65..ffff2496e8e8e3ed90bda27217ecbae386b52d04 100644 (file)
@@ -261,7 +261,8 @@ void ivpu_pm_reset_prepare_cb(struct pci_dev *pdev)
        ivpu_dbg(vdev, PM, "Pre-reset..\n");
        atomic_inc(&vdev->pm->reset_counter);
        atomic_set(&vdev->pm->in_reset, 1);
-       ivpu_shutdown(vdev);
+       ivpu_prepare_for_reset(vdev);
+       ivpu_hw_reset(vdev);
        ivpu_pm_prepare_cold_boot(vdev);
        ivpu_jobs_abort_all(vdev);
        ivpu_dbg(vdev, PM, "Pre-reset done.\n");
index c711db8a9c332843bc84482051d4d89ef977cd00..0f5218e361df5c2d8e05d9a5e6d7fa205c1e6376 100644 (file)
@@ -12,6 +12,7 @@
 #define pr_fmt(fmt) "ACPI: " fmt
 
 #include <linux/acpi.h>
+#include <linux/cpu.h>
 #include <linux/device.h>
 #include <linux/dmi.h>
 #include <linux/kernel.h>
index 948e31f7ce6e70918c9034989cb7d6dbddf4a70b..b411948594ff89ad2a9904a8681b02476a4bd13d 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 f41dda2d34933661ea2908e4b94b1663058d583a..a4aa53b7e2bb30789165145c4d1ccdea214809a3 100644 (file)
@@ -1410,10 +1410,10 @@ static int __init acpi_init(void)
        acpi_init_ffh();
 
        pci_mmcfg_late_init();
-       acpi_arm_init();
        acpi_viot_early_init();
        acpi_hest_init();
        acpi_ghes_init();
+       acpi_arm_init();
        acpi_scan_init();
        acpi_ec_init();
        acpi_debugfs_init();
index 660834a49c1f9ead66252f74685c2bbf8b90b2f4..c95d0edb0be9e5fd1884611773167b1b9595be57 100644 (file)
@@ -1913,6 +1913,17 @@ static const struct dmi_system_id ec_dmi_table[] __initconst = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "HP 15-cx0041ur"),
                },
        },
+       {
+               /*
+                * HP Pavilion Gaming Laptop 15-dk1xxx
+                * https://github.com/systemd/systemd/issues/28942
+                */
+               .callback = ec_honor_dsdt_gpe,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "HP"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion Gaming Laptop 15-dk1xxx"),
+               },
+       },
        {
                /*
                 * Samsung hardware
index c2c786eb95abc1fed2a773cee1ebf0080c8de6c8..1687483ff319e05f3d734996d4a60b36f9831778 100644 (file)
@@ -57,6 +57,7 @@ int acpi_register_gsi(struct device *dev, u32 gsi, int trigger,
                      int polarity)
 {
        struct irq_fwspec fwspec;
+       unsigned int irq;
 
        fwspec.fwnode = acpi_get_gsi_domain_id(gsi);
        if (WARN_ON(!fwspec.fwnode)) {
@@ -68,7 +69,11 @@ int acpi_register_gsi(struct device *dev, u32 gsi, int trigger,
        fwspec.param[1] = acpi_dev_get_irq_type(trigger, polarity);
        fwspec.param_count = 2;
 
-       return irq_create_fwspec_mapping(&fwspec);
+       irq = irq_create_fwspec_mapping(&fwspec);
+       if (!irq)
+               return -EINVAL;
+
+       return irq;
 }
 EXPORT_SYMBOL_GPL(acpi_register_gsi);
 
index f0e6738ae3c94146a3878f833f0406f3fedf44a0..7d88db451cfbfe17c5f8196fa90c5af3d5cc594e 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,
@@ -3339,6 +3339,16 @@ static int acpi_nfit_add(struct acpi_device *adev)
        acpi_size sz;
        int rc = 0;
 
+       rc = acpi_dev_install_notify_handler(adev, ACPI_DEVICE_NOTIFY,
+                                            acpi_nfit_notify);
+       if (rc)
+               return rc;
+
+       rc = devm_add_action_or_reset(dev, acpi_nfit_remove_notify_handler,
+                                       adev);
+       if (rc)
+               return rc;
+
        status = acpi_get_table(ACPI_SIG_NFIT, 0, &tbl);
        if (ACPI_FAILURE(status)) {
                /* The NVDIMM root device allows OS to trigger enumeration of
@@ -3386,17 +3396,7 @@ static int acpi_nfit_add(struct acpi_device *adev)
        if (rc)
                return rc;
 
-       rc = devm_add_action_or_reset(dev, acpi_nfit_shutdown, acpi_desc);
-       if (rc)
-               return rc;
-
-       rc = acpi_dev_install_notify_handler(adev, ACPI_DEVICE_NOTIFY,
-                                            acpi_nfit_notify);
-       if (rc)
-               return rc;
-
-       return devm_add_action_or_reset(dev, acpi_nfit_remove_notify_handler,
-                                       adev);
+       return devm_add_action_or_reset(dev, acpi_nfit_shutdown, acpi_desc);
 }
 
 static void acpi_nfit_update_notify(struct device *dev, acpi_handle handle)
index dc615ef6550a12b58592de70fddbd4a9f8f6304d..3a34a8c425fe4a673119d5ac7d9fef87ed145f38 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 1a8591e9a9bf1a215b058ee227e6b1ec8fe8c4d5..994091bd52de4027877638c66a02d41e100b4748 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 32cfa3f4efd3d290637dd0efe918eaf7ccc3ab99..297a88587031e6ebe297e2e4c231225d0f331679 100644 (file)
@@ -439,6 +439,13 @@ static const struct dmi_system_id asus_laptop[] = {
                        DMI_MATCH(DMI_BOARD_NAME, "S5602ZA"),
                },
        },
+       {
+               .ident = "Asus ExpertBook B1402CBA",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_BOARD_NAME, "B1402CBA"),
+               },
+       },
        {
                .ident = "Asus ExpertBook B1502CBA",
                .matches = {
@@ -500,16 +507,23 @@ static const struct dmi_system_id maingear_laptop[] = {
 
 static const struct dmi_system_id pcspecialist_laptop[] = {
        {
-               .ident = "PCSpecialist Elimina Pro 16 M",
-               /*
-                * Some models have product-name "Elimina Pro 16 M",
-                * others "GM6BGEQ". Match on board-name to match both.
-                */
+               /* TongFang GM6BGEQ / PCSpecialist Elimina Pro 16 M, RTX 3050 */
                .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "PCSpecialist"),
                        DMI_MATCH(DMI_BOARD_NAME, "GM6BGEQ"),
                },
        },
+       {
+               /* TongFang GM6BG5Q, RTX 4050 */
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_NAME, "GM6BG5Q"),
+               },
+       },
+       {
+               /* TongFang GM6BG0Q / PCSpecialist Elimina Pro 16 M, RTX 4060 */
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_NAME, "GM6BG0Q"),
+               },
+       },
        { }
 };
 
index 367afac5f1bffdeae9efda07ce7d790b36cf2374..92128aae2d0601ed9a7b08486d756bcd44016ace 100644 (file)
@@ -4812,6 +4812,8 @@ static void binder_release_work(struct binder_proc *proc,
                                "undelivered TRANSACTION_ERROR: %u\n",
                                e->cmd);
                } break;
+               case BINDER_WORK_TRANSACTION_PENDING:
+               case BINDER_WORK_TRANSACTION_ONEWAY_SPAM_SUSPECT:
                case BINDER_WORK_TRANSACTION_COMPLETE: {
                        binder_debug(BINDER_DEBUG_DEAD_TRANSACTION,
                                "undelivered TRANSACTION_COMPLETE\n");
index 0072e0f9ad391195368ae2e9c77e5e7fa4cc0195..d8cc1e27a125f0fbcadcd31fa146afc8868e2b6e 100644 (file)
@@ -1972,6 +1972,96 @@ retry:
        return rc;
 }
 
+/**
+ *     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
@@ -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 4cf4f57e57b8bdf06b5353e01ea4236c45f705e4..5686353e442cf41fb27174112617ae51f97fdfee 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 d3f28b82c97b9fa1f1fac8bd8c4d35567d9ce8ac..3a957c4da409271000812c51cd5d5fd96ff22407 100644 (file)
@@ -1050,14 +1050,14 @@ 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 and shutdown 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;
+               sdev->manage_shutdown = true;
        }
 
        /*
@@ -1089,6 +1089,42 @@ int ata_scsi_dev_config(struct scsi_device *sdev, struct ata_device *dev)
        return 0;
 }
 
+/**
+ *     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 +1141,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 +1169,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 +1230,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 +1246,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 +1256,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 +1870,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 +4350,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 +4760,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 +4769,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 e4fb9d1b9b39803a624ce8bf0185193a84d61d00..3e49a877500e124ec36fedb95ae122ca793afec6 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 6e7d352803bd4abb105046bc9c83ef4cf574c868..05ac80da8ebc7d11153310ac892c25258c03993a 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 bad7aa920cdca632c08d454751c162eaf3bcc1bf..d2b81cf2e16d26526724fa3897362a81d717fcbe 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 1af64d435d3c28eb4ca9d6836703d6a0595c3f17..a7adfdcb5e27cef19a74a97b6e3d6da2b1d2fbed 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 db716ffd083ee5de5e793d004365c75cb511f113..3db88bbcae0fc57adc5023cb3648ee774da64d83 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 884cb51c8f67291fc25724c05ec03aa6f56f02ac..234a84ecde8b1b9c586102338daeb70101e58418 100644 (file)
@@ -1478,7 +1478,7 @@ static int dev_get_regmap_match(struct device *dev, void *res, void *data)
 
        /* If the user didn't specify a name match any */
        if (data)
-               return !strcmp((*r)->name, data);
+               return (*r)->name && !strcmp((*r)->name, data);
        else
                return 1;
 }
index df1cd0f718b81c0d5d7dd68afc4b67c6b05e2c50..800f131222fc8f9e8ecf9c8355f2a787a80cc5fc 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 3de11f0771449ad074ca0c19c04069373098e8f4..a999b698b131f7763916c3bd0de5c87478fd0df4 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 84c2c2e1122fb62c6948293af84a106ec3732981..277d039ecbb429b57b9f1ca4743aed678823c160 100644 (file)
@@ -962,13 +962,10 @@ static void btrtl_dmp_hdr(struct hci_dev *hdev, struct sk_buff *skb)
        skb_put_data(skb, buf, strlen(buf));
 }
 
-static int btrtl_register_devcoredump_support(struct hci_dev *hdev)
+static void btrtl_register_devcoredump_support(struct hci_dev *hdev)
 {
-       int err;
+       hci_devcd_register(hdev, btrtl_coredump, btrtl_dmp_hdr, NULL);
 
-       err = hci_devcd_register(hdev, btrtl_coredump, btrtl_dmp_hdr, NULL);
-
-       return err;
 }
 
 void btrtl_set_driver_name(struct hci_dev *hdev, const char *driver_name)
@@ -1255,8 +1252,7 @@ int btrtl_download_firmware(struct hci_dev *hdev,
        }
 
 done:
-       if (!err)
-               err = btrtl_register_devcoredump_support(hdev);
+       btrtl_register_devcoredump_support(hdev);
 
        return err;
 }
index 82597ab4f747bb6fd0796bf1ab2a781962677ac4..499f4809fcdf3d507dfe33399483762569c8c725 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 40e2b9fa11a261332e4125f3c7d0c44ba0c7e289..f3892e9ce800ffdf8900aa1f62feb34716467e4a 100644 (file)
@@ -74,7 +74,10 @@ static int vhci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
        struct vhci_data *data = hci_get_drvdata(hdev);
 
        memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1);
+
+       mutex_lock(&data->open_mutex);
        skb_queue_tail(&data->readq, skb);
+       mutex_unlock(&data->open_mutex);
 
        wake_up_interruptible(&data->read_wait);
        return 0;
index eb4e7bee1e20cf6e76dfcc706a324b82111943a8..d57bc066dce6b4c5bd97f5a662928b2b590f7221 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 a57677f908f3ba3c134fb97e7c1eecd7159d8f0c..d6e5e3abaad8afde8f2f0a852f2408b4e1c5c4ac 100644 (file)
@@ -3,7 +3,7 @@ menu "Cache Drivers"
 
 config AX45MP_L2_CACHE
        bool "Andes Technology AX45MP L2 Cache controller"
-       depends on RISCV_DMA_NONCOHERENT
+       depends on RISCV
        select RISCV_NONSTANDARD_CACHE_OPS
        help
          Support for the L2 cache controller on Andes Technology AX45MP platforms.
index 4eaf1b53f06bd78950f584d7a991e6253f671cc8..ef4ba467e747bc791fbf231ecff494b61be92b01 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 7ab2447bd2031a7e7ede11fb4bd2b564e4c1ff1e..3d7de355f8f682266739a0b8837777ef0f02f571 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 c249f9791ae864c607aaf9db0a4557fd2adfb7d1..473563bc74960f3a472f9e6f7547f2e53459bd1f 100644 (file)
@@ -3416,6 +3416,7 @@ static void possible_parent_show(struct seq_file *s, struct clk_core *core,
                                 unsigned int i, char terminator)
 {
        struct clk_core *parent;
+       const char *name = NULL;
 
        /*
         * Go through the following options to fetch a parent's name.
@@ -3430,18 +3431,20 @@ static void possible_parent_show(struct seq_file *s, struct clk_core *core,
         * registered (yet).
         */
        parent = clk_core_get_parent_by_index(core, i);
-       if (parent)
+       if (parent) {
                seq_puts(s, parent->name);
-       else if (core->parents[i].name)
+       } else if (core->parents[i].name) {
                seq_puts(s, core->parents[i].name);
-       else if (core->parents[i].fw_name)
+       } else if (core->parents[i].fw_name) {
                seq_printf(s, "<%s>(fw)", core->parents[i].fw_name);
-       else if (core->parents[i].index >= 0)
-               seq_puts(s,
-                        of_clk_get_parent_name(core->of_node,
-                                               core->parents[i].index));
-       else
-               seq_puts(s, "(missing)");
+       } else {
+               if (core->parents[i].index >= 0)
+                       name = of_clk_get_parent_name(core->of_node, core->parents[i].index);
+               if (!name)
+                       name = "(missing)";
+
+               seq_puts(s, name);
+       }
 
        seq_putc(s, terminator);
 }
index 8dd601bd85389fb2faf6a9555927c13925d2d482..0a5a95e0267ff433902882bbbe340287704d1eb0 100644 (file)
@@ -87,10 +87,8 @@ static int socfpga_clk_set_parent(struct clk_hw *hwclk, u8 parent)
        return 0;
 }
 
-static unsigned long socfpga_clk_recalc_rate(struct clk_hw *hwclk,
-       unsigned long parent_rate)
+static u32 socfpga_clk_get_div(struct socfpga_gate_clk *socfpgaclk)
 {
-       struct socfpga_gate_clk *socfpgaclk = to_socfpga_gate_clk(hwclk);
        u32 div = 1, val;
 
        if (socfpgaclk->fixed_div)
@@ -105,12 +103,33 @@ static unsigned long socfpga_clk_recalc_rate(struct clk_hw *hwclk,
                        div = (1 << val);
        }
 
+       return div;
+}
+
+static unsigned long socfpga_clk_recalc_rate(struct clk_hw *hwclk,
+                                            unsigned long parent_rate)
+{
+       struct socfpga_gate_clk *socfpgaclk = to_socfpga_gate_clk(hwclk);
+       u32 div = socfpga_clk_get_div(socfpgaclk);
+
        return parent_rate / div;
 }
 
+
+static int socfpga_clk_determine_rate(struct clk_hw *hwclk,
+                                     struct clk_rate_request *req)
+{
+       struct socfpga_gate_clk *socfpgaclk = to_socfpga_gate_clk(hwclk);
+       u32 div = socfpga_clk_get_div(socfpgaclk);
+
+       req->rate = req->best_parent_rate / div;
+
+       return 0;
+}
+
 static struct clk_ops gateclk_ops = {
        .recalc_rate = socfpga_clk_recalc_rate,
-       .determine_rate = clk_hw_determine_rate_no_reparent,
+       .determine_rate = socfpga_clk_determine_rate,
        .get_parent = socfpga_clk_get_parent,
        .set_parent = socfpga_clk_set_parent,
 };
index 8f4441dd572b2156cf568e62e84bfe7b7002b8ee..9384ecc6c7413867c432623377091857946acad5 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 d5aa09e9fce4c2cd816f7dd75f9da3fa3c84b8dd..067b918a889456d04aa1a2ec0e4787d8f9645e26 100644 (file)
@@ -431,7 +431,7 @@ static int clk_stm32_composite_determine_rate(struct clk_hw *hw,
 {
        struct clk_stm32_composite *composite = to_clk_stm32_composite(hw);
        const struct stm32_div_cfg *divider;
-       unsigned long rate;
+       long rate;
 
        if (composite->div_id == NO_STM32_DIV)
                return 0;
index a9f3fb448de62070f8897421e2be174b25a4593a..7bfba0afd77831b112c9383eabbd7f1e55bceeae 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 868bc7af21b0b3482cc235ef5e24cd59ddf107f4..9b2824ed785b995b9d85e485ab5a068bbf911384 100644 (file)
@@ -749,9 +749,14 @@ static struct ti_dt_clk omap44xx_clks[] = {
        DT_CLK(NULL, "mcbsp1_sync_mux_ck", "abe-clkctrl:0028:26"),
        DT_CLK(NULL, "mcbsp2_sync_mux_ck", "abe-clkctrl:0030:26"),
        DT_CLK(NULL, "mcbsp3_sync_mux_ck", "abe-clkctrl:0038:26"),
+       DT_CLK("40122000.mcbsp", "prcm_fck", "abe-clkctrl:0028:26"),
+       DT_CLK("40124000.mcbsp", "prcm_fck", "abe-clkctrl:0030:26"),
+       DT_CLK("40126000.mcbsp", "prcm_fck", "abe-clkctrl:0038:26"),
        DT_CLK(NULL, "mcbsp4_sync_mux_ck", "l4-per-clkctrl:00c0:26"),
+       DT_CLK("48096000.mcbsp", "prcm_fck", "l4-per-clkctrl:00c0:26"),
        DT_CLK(NULL, "ocp2scp_usb_phy_phy_48m", "l3-init-clkctrl:00c0:8"),
        DT_CLK(NULL, "otg_60m_gfclk", "l3-init-clkctrl:0040:24"),
+       DT_CLK(NULL, "pad_fck", "pad_clks_ck"),
        DT_CLK(NULL, "per_mcbsp4_gfclk", "l4-per-clkctrl:00c0:24"),
        DT_CLK(NULL, "pmd_stm_clock_mux_ck", "emu-sys-clkctrl:0000:20"),
        DT_CLK(NULL, "pmd_trace_clk_mux_ck", "emu-sys-clkctrl:0000:22"),
index b4aff76eb3735e389d3a32e26c9ae97cf6eadeaa..74dfd5823f835b60ff7a21c040188783fc81ca5e 100644 (file)
@@ -565,15 +565,19 @@ static struct ti_dt_clk omap54xx_clks[] = {
        DT_CLK(NULL, "gpio8_dbclk", "l4per-clkctrl:00f8:8"),
        DT_CLK(NULL, "mcbsp1_gfclk", "abe-clkctrl:0028:24"),
        DT_CLK(NULL, "mcbsp1_sync_mux_ck", "abe-clkctrl:0028:26"),
+       DT_CLK("40122000.mcbsp", "prcm_fck", "abe-clkctrl:0028:26"),
        DT_CLK(NULL, "mcbsp2_gfclk", "abe-clkctrl:0030:24"),
        DT_CLK(NULL, "mcbsp2_sync_mux_ck", "abe-clkctrl:0030:26"),
+       DT_CLK("40124000.mcbsp", "prcm_fck", "abe-clkctrl:0030:26"),
        DT_CLK(NULL, "mcbsp3_gfclk", "abe-clkctrl:0038:24"),
        DT_CLK(NULL, "mcbsp3_sync_mux_ck", "abe-clkctrl:0038:26"),
+       DT_CLK("40126000.mcbsp", "prcm_fck", "abe-clkctrl:0038:26"),
        DT_CLK(NULL, "mmc1_32khz_clk", "l3init-clkctrl:0008:8"),
        DT_CLK(NULL, "mmc1_fclk", "l3init-clkctrl:0008:25"),
        DT_CLK(NULL, "mmc1_fclk_mux", "l3init-clkctrl:0008:24"),
        DT_CLK(NULL, "mmc2_fclk", "l3init-clkctrl:0010:25"),
        DT_CLK(NULL, "mmc2_fclk_mux", "l3init-clkctrl:0010:24"),
+       DT_CLK(NULL, "pad_fck", "pad_clks_ck"),
        DT_CLK(NULL, "sata_ref_clk", "l3init-clkctrl:0068:8"),
        DT_CLK(NULL, "timer10_gfclk_mux", "l4per-clkctrl:0008:24"),
        DT_CLK(NULL, "timer11_gfclk_mux", "l4per-clkctrl:0010:24"),
index 05d562e9c8b188552eaa4e15384717a31dd8e6cc..44b19e69617632bf4951d8da1e514f9c0c689d4b 100644 (file)
@@ -54,7 +54,7 @@ static int cn_filter(struct sock *dsk, struct sk_buff *skb, void *data)
        enum proc_cn_mcast_op mc_op;
        uintptr_t val;
 
-       if (!dsk || !data)
+       if (!dsk || !dsk->sk_user_data || !data)
                return 0;
 
        ptr = (__u32 *)data;
index 80acdf62794a3a16adbed9964c48d53bf47defde..afc94d0062b1775f00847dc49bbfc0796a3d3019 100644 (file)
@@ -247,8 +247,8 @@ static int counter_get_ext(const struct counter_comp *const ext,
                if (*id == component_id)
                        return 0;
 
-               if (ext->type == COUNTER_COMP_ARRAY) {
-                       element = ext->priv;
+               if (ext[*ext_idx].type == COUNTER_COMP_ARRAY) {
+                       element = ext[*ext_idx].priv;
 
                        if (component_id - *id < element->length)
                                return 0;
index 975e431d15909e7038c7947602e926c9203f653f..b3e615cbd2caa63f1bc7f8f34cc86f8bc41be477 100644 (file)
@@ -97,7 +97,7 @@ static int mchp_tc_count_function_write(struct counter_device *counter,
                priv->qdec_mode = 0;
                /* Set highest rate based on whether soc has gclk or not */
                bmr &= ~(ATMEL_TC_QDEN | ATMEL_TC_POSEN);
-               if (priv->tc_cfg->has_gclk)
+               if (!priv->tc_cfg->has_gclk)
                        cmr |= ATMEL_TC_TIMER_CLOCK2;
                else
                        cmr |= ATMEL_TC_TIMER_CLOCK1;
index 59a4c02594563544c1ebaecf6a536487dc6adf54..154590e1f7643d60f21f0acb068abbdaba8c2e01 100644 (file)
@@ -35,6 +35,9 @@ struct virtio_crypto {
        struct virtqueue *ctrl_vq;
        struct data_queue *data_vq;
 
+       /* Work struct for config space updates */
+       struct work_struct config_work;
+
        /* To protect the vq operations for the controlq */
        spinlock_t ctrl_lock;
 
index 94849fa3bd74aaa85e7467a571b778e8e373417f..43a0838d31ff012129dabb11103e3a87c43d7242 100644 (file)
@@ -335,6 +335,14 @@ static void virtcrypto_del_vqs(struct virtio_crypto *vcrypto)
        virtcrypto_free_queues(vcrypto);
 }
 
+static void vcrypto_config_changed_work(struct work_struct *work)
+{
+       struct virtio_crypto *vcrypto =
+               container_of(work, struct virtio_crypto, config_work);
+
+       virtcrypto_update_status(vcrypto);
+}
+
 static int virtcrypto_probe(struct virtio_device *vdev)
 {
        int err = -EFAULT;
@@ -454,6 +462,8 @@ static int virtcrypto_probe(struct virtio_device *vdev)
        if (err)
                goto free_engines;
 
+       INIT_WORK(&vcrypto->config_work, vcrypto_config_changed_work);
+
        return 0;
 
 free_engines:
@@ -490,6 +500,7 @@ static void virtcrypto_remove(struct virtio_device *vdev)
 
        dev_info(&vdev->dev, "Start virtcrypto_remove.\n");
 
+       flush_work(&vcrypto->config_work);
        if (virtcrypto_dev_started(vcrypto))
                virtcrypto_dev_stop(vcrypto);
        virtio_reset_device(vdev);
@@ -504,7 +515,7 @@ static void virtcrypto_config_changed(struct virtio_device *vdev)
 {
        struct virtio_crypto *vcrypto = vdev->priv;
 
-       virtcrypto_update_status(vcrypto);
+       schedule_work(&vcrypto->config_work);
 }
 
 #ifdef CONFIG_PM_SLEEP
@@ -512,6 +523,7 @@ static int virtcrypto_freeze(struct virtio_device *vdev)
 {
        struct virtio_crypto *vcrypto = vdev->priv;
 
+       flush_work(&vcrypto->config_work);
        virtio_reset_device(vdev);
        virtcrypto_free_unused_reqs(vcrypto);
        if (virtcrypto_dev_started(vcrypto))
index d1c559879dcc00733cfb9abff6cffb64b0745659..40d055560e52fd2298fa3400384b686e37413b32 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 ca60bb8114f22a4df6f175b0f5a942e51e3cb45d..4df4f614f490ef96d26f412a9cff42e52d246486 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 724be8448eb4a52542bc3e0cd6b16de508f7979f..7ca01a834e188c8f09f2676b8c79689279acbabe 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 e115ba382e0445dc6c8ec1881e0e95ec307c4918..6d63b8798c29921470e37c9bf0e9d116c834508e 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 1cb1494c28fe82c36f0e75f9a1ee64f6ed77fc38..44a21ab7add51b70d17c645434934af347a93e58 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 c625bb2b5d563647f7a0ec40e0322a519056ea94..628af51c81af3d9a59cce67311b40d311c472e43 100644 (file)
@@ -76,16 +76,11 @@ struct dma_fence *__dma_fence_unwrap_merge(unsigned int num_fences,
                dma_fence_unwrap_for_each(tmp, &iter[i], fences[i]) {
                        if (!dma_fence_is_signaled(tmp)) {
                                ++count;
-                       } else if (test_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT,
-                                           &tmp->flags)) {
-                               if (ktime_after(tmp->timestamp, timestamp))
-                                       timestamp = tmp->timestamp;
                        } else {
-                               /*
-                                * Use the current time if the fence is
-                                * currently signaling.
-                                */
-                               timestamp = ktime_get();
+                               ktime_t t = dma_fence_timestamp(tmp);
+
+                               if (ktime_after(t, timestamp))
+                                       timestamp = t;
                        }
                }
        }
index af57799c86ceec5bb4b8f4354aa3bbc822211771..2e9a316c596a3b3a02a950e704a265db4516b46d 100644 (file)
@@ -268,13 +268,10 @@ static int sync_fill_fence_info(struct dma_fence *fence,
                sizeof(info->driver_name));
 
        info->status = dma_fence_get_status(fence);
-       while (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags) &&
-              !test_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags))
-               cpu_relax();
        info->timestamp_ns =
-               test_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags) ?
-               ktime_to_ns(fence->timestamp) :
-               ktime_set(0, 0);
+               dma_fence_is_signaled(fence) ?
+                       ktime_to_ns(dma_fence_timestamp(fence)) :
+                       ktime_set(0, 0);
 
        return info->status;
 }
index a0f5741abcc4797e9fea0b259dcaf57290a975ba..6a3abe5b17908dc3fbbfa4812fdc8e6c6ebbb504 100644 (file)
@@ -92,8 +92,14 @@ static void fsl_edma3_enable_request(struct fsl_edma_chan *fsl_chan)
 
        edma_writel_chreg(fsl_chan, val, ch_sbr);
 
-       if (flags & FSL_EDMA_DRV_HAS_CHMUX)
-               edma_writel_chreg(fsl_chan, fsl_chan->srcid, ch_mux);
+       if (flags & FSL_EDMA_DRV_HAS_CHMUX) {
+               /*
+                * ch_mux: With the exception of 0, attempts to write a value
+                * already in use will be forced to 0.
+                */
+               if (!edma_readl_chreg(fsl_chan, ch_mux))
+                       edma_writel_chreg(fsl_chan, fsl_chan->srcid, ch_mux);
+       }
 
        val = edma_readl_chreg(fsl_chan, ch_csr);
        val |= EDMA_V3_CH_CSR_ERQ;
@@ -448,12 +454,25 @@ static void fsl_edma_set_tcd_regs(struct fsl_edma_chan *fsl_chan,
 
        edma_write_tcdreg(fsl_chan, tcd->dlast_sga, dlast_sga);
 
+       csr = le16_to_cpu(tcd->csr);
+
        if (fsl_chan->is_sw) {
-               csr = le16_to_cpu(tcd->csr);
                csr |= EDMA_TCD_CSR_START;
                tcd->csr = cpu_to_le16(csr);
        }
 
+       /*
+        * Must clear CHn_CSR[DONE] bit before enable TCDn_CSR[ESG] at EDMAv3
+        * eDMAv4 have not such requirement.
+        * Change MLINK need clear CHn_CSR[DONE] for both eDMAv3 and eDMAv4.
+        */
+       if (((fsl_edma_drvflags(fsl_chan) & FSL_EDMA_DRV_CLEAR_DONE_E_SG) &&
+               (csr & EDMA_TCD_CSR_E_SG)) ||
+           ((fsl_edma_drvflags(fsl_chan) & FSL_EDMA_DRV_CLEAR_DONE_E_LINK) &&
+               (csr & EDMA_TCD_CSR_E_LINK)))
+               edma_writel_chreg(fsl_chan, edma_readl_chreg(fsl_chan, ch_csr), ch_csr);
+
+
        edma_write_tcdreg(fsl_chan, tcd->csr, csr);
 }
 
index 3cc0cc8fc2d05d41b953ae55a4b38dab235eccfe..40d50cc3d75a346100a58a64c510039dc9ee60a9 100644 (file)
@@ -183,11 +183,23 @@ struct fsl_edma_desc {
 #define FSL_EDMA_DRV_BUS_8BYTE         BIT(10)
 #define FSL_EDMA_DRV_DEV_TO_DEV                BIT(11)
 #define FSL_EDMA_DRV_ALIGN_64BYTE      BIT(12)
+/* Need clean CHn_CSR DONE before enable TCD's ESG */
+#define FSL_EDMA_DRV_CLEAR_DONE_E_SG   BIT(13)
+/* Need clean CHn_CSR DONE before enable TCD's MAJORELINK */
+#define FSL_EDMA_DRV_CLEAR_DONE_E_LINK BIT(14)
 
 #define FSL_EDMA_DRV_EDMA3     (FSL_EDMA_DRV_SPLIT_REG |       \
                                 FSL_EDMA_DRV_BUS_8BYTE |       \
                                 FSL_EDMA_DRV_DEV_TO_DEV |      \
-                                FSL_EDMA_DRV_ALIGN_64BYTE)
+                                FSL_EDMA_DRV_ALIGN_64BYTE |    \
+                                FSL_EDMA_DRV_CLEAR_DONE_E_SG | \
+                                FSL_EDMA_DRV_CLEAR_DONE_E_LINK)
+
+#define FSL_EDMA_DRV_EDMA4     (FSL_EDMA_DRV_SPLIT_REG |       \
+                                FSL_EDMA_DRV_BUS_8BYTE |       \
+                                FSL_EDMA_DRV_DEV_TO_DEV |      \
+                                FSL_EDMA_DRV_ALIGN_64BYTE |    \
+                                FSL_EDMA_DRV_CLEAR_DONE_E_LINK)
 
 struct fsl_edma_drvdata {
        u32                     dmamuxs; /* only used before v3 */
index 63d48d046f046fbdee054e64c97c8cf2808fa5c2..8c4ed7012e232e3997453d1923722a4286b434ba 100644 (file)
@@ -154,18 +154,20 @@ static struct dma_chan *fsl_edma3_xlate(struct of_phandle_args *dma_spec,
                fsl_chan = to_fsl_edma_chan(chan);
                i = fsl_chan - fsl_edma->chans;
 
-               chan = dma_get_slave_channel(chan);
-               chan->device->privatecnt++;
                fsl_chan->priority = dma_spec->args[1];
                fsl_chan->is_rxchan = dma_spec->args[2] & ARGS_RX;
                fsl_chan->is_remote = dma_spec->args[2] & ARGS_REMOTE;
                fsl_chan->is_multi_fifo = dma_spec->args[2] & ARGS_MULTI_FIFO;
 
                if (!b_chmux && i == dma_spec->args[0]) {
+                       chan = dma_get_slave_channel(chan);
+                       chan->device->privatecnt++;
                        mutex_unlock(&fsl_edma->fsl_edma_mutex);
                        return chan;
                } else if (b_chmux && !fsl_chan->srcid) {
                        /* if controller support channel mux, choose a free channel */
+                       chan = dma_get_slave_channel(chan);
+                       chan->device->privatecnt++;
                        fsl_chan->srcid = dma_spec->args[0];
                        mutex_unlock(&fsl_edma->fsl_edma_mutex);
                        return chan;
@@ -355,7 +357,7 @@ static struct fsl_edma_drvdata imx93_data3 = {
 };
 
 static struct fsl_edma_drvdata imx93_data4 = {
-       .flags = FSL_EDMA_DRV_HAS_CHMUX | FSL_EDMA_DRV_HAS_DMACLK | FSL_EDMA_DRV_EDMA3,
+       .flags = FSL_EDMA_DRV_HAS_CHMUX | FSL_EDMA_DRV_HAS_DMACLK | FSL_EDMA_DRV_EDMA4,
        .chreg_space_sz = 0x8000,
        .chreg_off = 0x10000,
        .setup_irq = fsl_edma3_irq_init,
index 22d6f4e455b7973cae80208ccfcd638f3e0e0dca..8f754f922217dedb7b49d2991d85b007201331ac 100644 (file)
@@ -477,6 +477,7 @@ static void idxd_cmd_exec(struct idxd_device *idxd, int cmd_code, u32 operand,
        union idxd_command_reg cmd;
        DECLARE_COMPLETION_ONSTACK(done);
        u32 stat;
+       unsigned long flags;
 
        if (idxd_device_is_halted(idxd)) {
                dev_warn(&idxd->pdev->dev, "Device is HALTED!\n");
@@ -490,7 +491,7 @@ static void idxd_cmd_exec(struct idxd_device *idxd, int cmd_code, u32 operand,
        cmd.operand = operand;
        cmd.int_req = 1;
 
-       spin_lock(&idxd->cmd_lock);
+       spin_lock_irqsave(&idxd->cmd_lock, flags);
        wait_event_lock_irq(idxd->cmd_waitq,
                            !test_bit(IDXD_FLAG_CMD_RUNNING, &idxd->flags),
                            idxd->cmd_lock);
@@ -507,7 +508,7 @@ static void idxd_cmd_exec(struct idxd_device *idxd, int cmd_code, u32 operand,
         * After command submitted, release lock and go to sleep until
         * the command completes via interrupt.
         */
-       spin_unlock(&idxd->cmd_lock);
+       spin_unlock_irqrestore(&idxd->cmd_lock, flags);
        wait_for_completion(&done);
        stat = ioread32(idxd->reg_base + IDXD_CMDSTS_OFFSET);
        spin_lock(&idxd->cmd_lock);
index c51dc017b48a84fc7d7f20d1c7ec0c1010a6159d..06d12ac39144f4eefa285c58d289b1e0b70b5d54 100644 (file)
@@ -450,9 +450,8 @@ static int mtk_uart_apdma_device_pause(struct dma_chan *chan)
        mtk_uart_apdma_write(c, VFF_EN, VFF_EN_CLR_B);
        mtk_uart_apdma_write(c, VFF_INT_EN, VFF_INT_EN_CLR_B);
 
-       synchronize_irq(c->irq);
-
        spin_unlock_irqrestore(&c->vc.lock, flags);
+       synchronize_irq(c->irq);
 
        return 0;
 }
index 89e82508c13392c721de92969922cb001483b60d..002833fb1fa04cabddb058fa6c575d7ffc42247e 100644 (file)
@@ -3668,6 +3668,7 @@ static int __init d40_probe(struct platform_device *pdev)
                regulator_disable(base->lcpa_regulator);
                regulator_put(base->lcpa_regulator);
        }
+       pm_runtime_disable(base->dev);
 
  report_failure:
        d40_err(dev, "probe failed\n");
index 5c36811aa1342c8df4f340dbbaeadbd77c8ef3bf..0b30151fb45c4c18c17565e1f254f1783fe63059 100644 (file)
@@ -1113,8 +1113,10 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_slave_sg(
                chan->chan_reg.dma_scr &= ~STM32_DMA_SCR_PFCTRL;
 
        /* Activate Double Buffer Mode if DMA triggers STM32 MDMA and more than 1 sg */
-       if (chan->trig_mdma && sg_len > 1)
+       if (chan->trig_mdma && sg_len > 1) {
                chan->chan_reg.dma_scr |= STM32_DMA_SCR_DBM;
+               chan->chan_reg.dma_scr &= ~STM32_DMA_SCR_CT;
+       }
 
        for_each_sg(sgl, sg, sg_len, i) {
                ret = stm32_dma_set_xfer_param(chan, direction, &buswidth,
@@ -1387,11 +1389,12 @@ static size_t stm32_dma_desc_residue(struct stm32_dma_chan *chan,
 
        residue = stm32_dma_get_remaining_bytes(chan);
 
-       if (chan->desc->cyclic && !stm32_dma_is_current_sg(chan)) {
+       if ((chan->desc->cyclic || chan->trig_mdma) && !stm32_dma_is_current_sg(chan)) {
                n_sg++;
                if (n_sg == chan->desc->num_sgs)
                        n_sg = 0;
-               residue = sg_req->len;
+               if (!chan->trig_mdma)
+                       residue = sg_req->len;
        }
 
        /*
@@ -1401,7 +1404,7 @@ static size_t stm32_dma_desc_residue(struct stm32_dma_chan *chan,
         * residue = remaining bytes from NDTR + remaining
         * periods/sg to be transferred
         */
-       if (!chan->desc->cyclic || n_sg != 0)
+       if ((!chan->desc->cyclic && !chan->trig_mdma) || n_sg != 0)
                for (i = n_sg; i < desc->num_sgs; i++)
                        residue += desc->sg_req[i].len;
 
index 0de234022c6d6d24f5cce496cc196bb1263dffe2..bae08b3f55c73fa07bc5e67c427a94c326f7ac39 100644 (file)
@@ -777,8 +777,6 @@ static int stm32_mdma_setup_xfer(struct stm32_mdma_chan *chan,
        /* Enable interrupts */
        ccr &= ~STM32_MDMA_CCR_IRQ_MASK;
        ccr |= STM32_MDMA_CCR_TEIE | STM32_MDMA_CCR_CTCIE;
-       if (sg_len > 1)
-               ccr |= STM32_MDMA_CCR_BTIE;
        desc->ccr = ccr;
 
        return 0;
@@ -1236,6 +1234,10 @@ static int stm32_mdma_resume(struct dma_chan *c)
        unsigned long flags;
        u32 status, reg;
 
+       /* Transfer can be terminated */
+       if (!chan->desc || (stm32_mdma_read(dmadev, STM32_MDMA_CCR(chan->id)) & STM32_MDMA_CCR_EN))
+               return -EPERM;
+
        hwdesc = chan->desc->node[chan->curr_hwdesc].hwdesc;
 
        spin_lock_irqsave(&chan->vchan.lock, flags);
@@ -1316,21 +1318,35 @@ static int stm32_mdma_slave_config(struct dma_chan *c,
 
 static size_t stm32_mdma_desc_residue(struct stm32_mdma_chan *chan,
                                      struct stm32_mdma_desc *desc,
-                                     u32 curr_hwdesc)
+                                     u32 curr_hwdesc,
+                                     struct dma_tx_state *state)
 {
        struct stm32_mdma_device *dmadev = stm32_mdma_get_dev(chan);
        struct stm32_mdma_hwdesc *hwdesc;
-       u32 cbndtr, residue, modulo, burst_size;
+       u32 cisr, clar, cbndtr, residue, modulo, burst_size;
        int i;
 
+       cisr = stm32_mdma_read(dmadev, STM32_MDMA_CISR(chan->id));
+
        residue = 0;
-       for (i = curr_hwdesc + 1; i < desc->count; i++) {
+       /* Get the next hw descriptor to process from current transfer */
+       clar = stm32_mdma_read(dmadev, STM32_MDMA_CLAR(chan->id));
+       for (i = desc->count - 1; i >= 0; i--) {
                hwdesc = desc->node[i].hwdesc;
+
+               if (hwdesc->clar == clar)
+                       break;/* Current transfer found, stop cumulating */
+
+               /* Cumulate residue of unprocessed hw descriptors */
                residue += STM32_MDMA_CBNDTR_BNDT(hwdesc->cbndtr);
        }
        cbndtr = stm32_mdma_read(dmadev, STM32_MDMA_CBNDTR(chan->id));
        residue += cbndtr & STM32_MDMA_CBNDTR_BNDT_MASK;
 
+       state->in_flight_bytes = 0;
+       if (chan->chan_config.m2m_hw && (cisr & STM32_MDMA_CISR_CRQA))
+               state->in_flight_bytes = cbndtr & STM32_MDMA_CBNDTR_BNDT_MASK;
+
        if (!chan->mem_burst)
                return residue;
 
@@ -1360,11 +1376,10 @@ static enum dma_status stm32_mdma_tx_status(struct dma_chan *c,
 
        vdesc = vchan_find_desc(&chan->vchan, cookie);
        if (chan->desc && cookie == chan->desc->vdesc.tx.cookie)
-               residue = stm32_mdma_desc_residue(chan, chan->desc,
-                                                 chan->curr_hwdesc);
+               residue = stm32_mdma_desc_residue(chan, chan->desc, chan->curr_hwdesc, state);
        else if (vdesc)
-               residue = stm32_mdma_desc_residue(chan,
-                                                 to_stm32_mdma_desc(vdesc), 0);
+               residue = stm32_mdma_desc_residue(chan, to_stm32_mdma_desc(vdesc), 0, state);
+
        dma_set_residue(state, residue);
 
        spin_unlock_irqrestore(&chan->vchan.lock, flags);
index 789193ed038650b5d73f64fd8db8cab84c031936..c278d5facf7d8bc6696e32d7f7ebc38c58b67afc 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 26db5b8dfc1ef5952a02ee32869adaa2184ebe19..7edf2c95282fa2bae047cffac250b55337fdba02 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,11 @@ 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;
+               sdev->manage_shutdown = true;
+       }
 
        if (sdev->type == TYPE_ROM)
                sdev->use_10_for_ms = 1;
index 2109cd178ff706f3ec7b0db0735d18519ba639cb..121f4fc903cd57b17e2dd6835a31570f4edf3774 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 c0cd556fbaaec6946a98b2785990c2edaa14b699..30dedd6ebfde61f54fef878cdfb5b6eadd2a70c1 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 49b70c70dc6960b79cc69e5f382a9fdd3e8b9c2e..79d4254d1f9bc537be6ad3e958928b89d40efba3 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 1599f11768426d8ff72c9c2cfc9387728af2efa3..1974f0ad32badbea55d1f4c1a43f4f95c065c3b5 100644 (file)
@@ -273,9 +273,13 @@ static __init int efivar_ssdt_load(void)
                if (status == EFI_NOT_FOUND) {
                        break;
                } else if (status == EFI_BUFFER_TOO_SMALL) {
-                       name = krealloc(name, name_size, GFP_KERNEL);
-                       if (!name)
+                       efi_char16_t *name_tmp =
+                               krealloc(name, name_size, GFP_KERNEL);
+                       if (!name_tmp) {
+                               kfree(name);
                                return -ENOMEM;
+                       }
+                       name = name_tmp;
                        continue;
                }
 
@@ -623,6 +627,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 +783,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 2fee52ed335d13789d5853f9a0ee1f58337fa942..9d5df683f8821c116d17b7a0327567e651d78f04 100644 (file)
@@ -605,11 +605,8 @@ setup_e820(struct boot_params *params, struct setup_data *e820ext, u32 e820ext_s
                        break;
 
                case EFI_UNACCEPTED_MEMORY:
-                       if (!IS_ENABLED(CONFIG_UNACCEPTED_MEMORY)) {
-                               efi_warn_once(
-"The system has unaccepted memory,  but kernel does not support it\nConsider enabling CONFIG_UNACCEPTED_MEMORY\n");
+                       if (!IS_ENABLED(CONFIG_UNACCEPTED_MEMORY))
                                continue;
-                       }
                        e820_type = E820_TYPE_RAM;
                        process_unaccepted_memory(d->phys_addr,
                                                  d->phys_addr + PAGE_SIZE * d->num_pages);
@@ -852,6 +849,8 @@ void __noreturn efi_stub_entry(efi_handle_t handle,
        unsigned long kernel_entry;
        efi_status_t status;
 
+       boot_params_pointer = boot_params;
+
        efi_system_table = sys_table_arg;
        /* Check if we were booted by the EFI firmware */
        if (efi_system_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
index 37c5a36b9d8cf9b2cad93f228502fd336d142908..2748bca192dfb2cd4a4b42b371d968acdf5cb121 100644 (file)
@@ -2,6 +2,8 @@
 
 #include <linux/efi.h>
 
+extern struct boot_params *boot_params_pointer asm("boot_params");
+
 extern void trampoline_32bit_src(void *, bool);
 extern const u16 trampoline_ljmp_imm_offset;
 
index 853f7dc3c21d8f0dafed9d43f57ebdf13fcf911a..135278ddaf627bb1fd41ba6062a3596e52bd8f72 100644 (file)
@@ -5,9 +5,17 @@
 #include <linux/spinlock.h>
 #include <asm/unaccepted_memory.h>
 
-/* Protects unaccepted memory bitmap */
+/* Protects unaccepted memory bitmap and accepting_list */
 static DEFINE_SPINLOCK(unaccepted_memory_lock);
 
+struct accept_range {
+       struct list_head list;
+       unsigned long start;
+       unsigned long end;
+};
+
+static LIST_HEAD(accepting_list);
+
 /*
  * accept_memory() -- Consult bitmap and accept the memory if needed.
  *
@@ -24,6 +32,7 @@ void accept_memory(phys_addr_t start, phys_addr_t end)
 {
        struct efi_unaccepted_memory *unaccepted;
        unsigned long range_start, range_end;
+       struct accept_range range, *entry;
        unsigned long flags;
        u64 unit_size;
 
@@ -78,20 +87,67 @@ void accept_memory(phys_addr_t start, phys_addr_t end)
        if (end > unaccepted->size * unit_size * BITS_PER_BYTE)
                end = unaccepted->size * unit_size * BITS_PER_BYTE;
 
-       range_start = start / unit_size;
-
+       range.start = start / unit_size;
+       range.end = DIV_ROUND_UP(end, unit_size);
+retry:
        spin_lock_irqsave(&unaccepted_memory_lock, flags);
+
+       /*
+        * Check if anybody works on accepting the same range of the memory.
+        *
+        * The check is done with unit_size granularity. It is crucial to catch
+        * all accept requests to the same unit_size block, even if they don't
+        * overlap on physical address level.
+        */
+       list_for_each_entry(entry, &accepting_list, list) {
+               if (entry->end < range.start)
+                       continue;
+               if (entry->start >= range.end)
+                       continue;
+
+               /*
+                * Somebody else accepting the range. Or at least part of it.
+                *
+                * Drop the lock and retry until it is complete.
+                */
+               spin_unlock_irqrestore(&unaccepted_memory_lock, flags);
+               goto retry;
+       }
+
+       /*
+        * Register that the range is about to be accepted.
+        * Make sure nobody else will accept it.
+        */
+       list_add(&range.list, &accepting_list);
+
+       range_start = range.start;
        for_each_set_bitrange_from(range_start, range_end, unaccepted->bitmap,
-                                  DIV_ROUND_UP(end, unit_size)) {
+                                  range.end) {
                unsigned long phys_start, phys_end;
                unsigned long len = range_end - range_start;
 
                phys_start = range_start * unit_size + unaccepted->phys_base;
                phys_end = range_end * unit_size + unaccepted->phys_base;
 
+               /*
+                * Keep interrupts disabled until the accept operation is
+                * complete in order to prevent deadlocks.
+                *
+                * Enabling interrupts before calling arch_accept_memory()
+                * creates an opportunity for an interrupt handler to request
+                * acceptance for the same memory. The handler will continuously
+                * spin with interrupts disabled, preventing other task from
+                * making progress with the acceptance process.
+                */
+               spin_unlock(&unaccepted_memory_lock);
+
                arch_accept_memory(phys_start, phys_end);
+
+               spin_lock(&unaccepted_memory_lock);
                bitmap_clear(unaccepted->bitmap, range_start, len);
        }
+
+       list_del(&range.list);
        spin_unlock_irqrestore(&unaccepted_memory_lock, flags);
 }
 
index 3dba590a2a9579c44e8cc498b62e47744eb29f06..a48a58e0c61f8f1de483a368453025a48cd693ae 100644 (file)
@@ -118,6 +118,7 @@ static int imx_dsp_setup_channels(struct imx_dsp_ipc *dsp_ipc)
                        if (ret != -EPROBE_DEFER)
                                dev_err(dev, "Failed to request mbox chan %s ret %d\n",
                                        chan_name, ret);
+                       kfree(dsp_chan->name);
                        goto out;
                }
 
index e4a64815f16d63b054d1f7f706b1abf349b7a8e7..d4e55204c092671b31a621a14fcbd7d93d819c1c 100644 (file)
@@ -1,6 +1,6 @@
 config FPGA_KUNIT_TESTS
-       tristate "KUnit test for the FPGA subsystem" if !KUNIT_ALL_TESTS
-       depends on FPGA && FPGA_REGION && FPGA_BRIDGE && KUNIT=y
+       bool "KUnit test for the FPGA subsystem" if !KUNIT_ALL_TESTS
+       depends on FPGA=y && FPGA_REGION=y && FPGA_BRIDGE=y && KUNIT=y && MODULES=n
        default KUNIT_ALL_TESTS
         help
           This builds unit tests for the FPGA subsystem
index 9f9d50ee78710bbf708662ebbfeac7d1672eaab0..baab07e3fc59678a8fe3e97d03d2a6e671a9c023 100644 (file)
@@ -93,6 +93,8 @@ static void fpga_region_test_class_find(struct kunit *test)
 
        region = fpga_region_class_find(NULL, &ctx->region_pdev->dev, fake_region_match);
        KUNIT_EXPECT_PTR_EQ(test, region, ctx->region);
+
+       put_device(&region->dev);
 }
 
 /*
index da33bbbdacb956c914342a3ed297f069346f48a7..58f107194fdafdfae6d86318fdaf2f206065757a 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 2b9b7be9b8fdd892cae6a82e071795fef3d49d9e..01c0fd0a9d8c63959a0aeee445944165aaef3e5e 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 7e9f7a32d3ee58ea047fe942a062bba0395a2af5..cae9661862fe1ddade8676596244d4a474fbf8ce 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 271db3639a78209e00d45d558d6354bb0161e27f..44bf1709a6488cd7e61eca8e56463f670bbee4b8 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 78f8790168ae1e4bad29229970cec99ff6f52d9b..f96d260a4a19d8b788dbf92aef7da5c4e0bfcb63 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 bbd9e919119921e5e77a3aeac2b0e0cc337f05c9..fad979797486534d3cc6a1437fdca765baeb7b47 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 dbc7ba0ee72c7013853af1e2cc15f5304e96cdad..656d6b1dddb5db90725224891b2a164b52a8d6c1 100644 (file)
@@ -126,14 +126,14 @@ static int vf610_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
        unsigned long mask = BIT(gpio);
        u32 val;
 
+       vf610_gpio_set(chip, gpio, value);
+
        if (port->sdata && port->sdata->have_paddr) {
                val = vf610_gpio_readl(port->gpio_base + GPIO_PDDR);
                val |= mask;
                vf610_gpio_writel(val, port->gpio_base + GPIO_PDDR);
        }
 
-       vf610_gpio_set(chip, gpio, value);
-
        return pinctrl_gpio_direction_output(chip->base + gpio);
 }
 
@@ -246,7 +246,8 @@ static const struct irq_chip vf610_irqchip = {
        .irq_unmask = vf610_gpio_irq_unmask,
        .irq_set_type = vf610_gpio_irq_set_type,
        .irq_set_wake = vf610_gpio_irq_set_wake,
-       .flags = IRQCHIP_IMMUTABLE,
+       .flags = IRQCHIP_IMMUTABLE | IRQCHIP_MASK_ON_SUSPEND
+                       | IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND,
        GPIOCHIP_IRQ_RESOURCE_HELPERS,
 };
 
index fbda452fb4d6afd4154d4f9e219b3b0cfb434e1a..51e41676de0b8df597a7d9afd493165863e5b053 100644 (file)
@@ -951,6 +951,7 @@ static struct gpio_desc *acpi_get_gpiod_from_data(struct fwnode_handle *fwnode,
        if (!propname)
                return ERR_PTR(-EINVAL);
 
+       memset(&lookup, 0, sizeof(lookup));
        lookup.index = index;
 
        ret = acpi_gpio_property_lookup(fwnode, propname, index, &lookup);
index ab9ef1c2034912d8fc330f6009a81dc31759f5b5..3caa020391c75283c9145d18fb3be151496620af 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 7d6daf8d2bfaf8c19695304f2150bffc80d45b65..e036011137aa220f3078d8aea82f0c10684b2dbb 100644 (file)
@@ -1103,7 +1103,7 @@ static int reserve_bo_and_vm(struct kgd_mem *mem,
                if (unlikely(ret))
                        goto error;
 
-               ret = drm_exec_lock_obj(&ctx->exec, &bo->tbo.base);
+               ret = drm_exec_prepare_obj(&ctx->exec, &bo->tbo.base, 1);
                drm_exec_retry_on_contention(&ctx->exec);
                if (unlikely(ret))
                        goto error;
index 73ee14f7a9a4b83cfea610dbf8427adaa7da8b40..dce9e7d5e4ec672827f574fb64816ca205ef96ee 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 efdb1c48f431530d01fd25eb581033472a5b5239..d93a8961274c6ae8b088abfe89d3d1fa365ff9ad 100644 (file)
@@ -65,7 +65,8 @@ static int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p,
        }
 
        amdgpu_sync_create(&p->sync);
-       drm_exec_init(&p->exec, DRM_EXEC_INTERRUPTIBLE_WAIT);
+       drm_exec_init(&p->exec, DRM_EXEC_INTERRUPTIBLE_WAIT |
+                     DRM_EXEC_IGNORE_DUPLICATES);
        return 0;
 }
 
index 0dc9c655c4fbdbd9dbd3224508fac806dbd99dfc..76549c2cffebe1b2c188e5e2ff4ebc94fffc6d5a 100644 (file)
@@ -47,7 +47,6 @@ const unsigned int amdgpu_ctx_num_entities[AMDGPU_HW_IP_NUM] = {
 bool amdgpu_ctx_priority_is_valid(int32_t ctx_prio)
 {
        switch (ctx_prio) {
-       case AMDGPU_CTX_PRIORITY_UNSET:
        case AMDGPU_CTX_PRIORITY_VERY_LOW:
        case AMDGPU_CTX_PRIORITY_LOW:
        case AMDGPU_CTX_PRIORITY_NORMAL:
@@ -55,6 +54,11 @@ bool amdgpu_ctx_priority_is_valid(int32_t ctx_prio)
        case AMDGPU_CTX_PRIORITY_VERY_HIGH:
                return true;
        default:
+       case AMDGPU_CTX_PRIORITY_UNSET:
+               /* UNSET priority is not valid and we don't carry that
+                * around, but set it to NORMAL in the only place this
+                * function is called, amdgpu_ctx_ioctl().
+                */
                return false;
        }
 }
@@ -64,7 +68,8 @@ amdgpu_ctx_to_drm_sched_prio(int32_t ctx_prio)
 {
        switch (ctx_prio) {
        case AMDGPU_CTX_PRIORITY_UNSET:
-               return DRM_SCHED_PRIORITY_UNSET;
+               pr_warn_once("AMD-->DRM context priority value UNSET-->NORMAL");
+               return DRM_SCHED_PRIORITY_NORMAL;
 
        case AMDGPU_CTX_PRIORITY_VERY_LOW:
                return DRM_SCHED_PRIORITY_MIN;
@@ -94,9 +99,6 @@ amdgpu_ctx_to_drm_sched_prio(int32_t ctx_prio)
 static int amdgpu_ctx_priority_permit(struct drm_file *filp,
                                      int32_t priority)
 {
-       if (!amdgpu_ctx_priority_is_valid(priority))
-               return -EINVAL;
-
        /* NORMAL and below are accessible by everyone */
        if (priority <= AMDGPU_CTX_PRIORITY_NORMAL)
                return 0;
@@ -631,8 +633,6 @@ static int amdgpu_ctx_query2(struct amdgpu_device *adev,
        return 0;
 }
 
-
-
 static int amdgpu_ctx_stable_pstate(struct amdgpu_device *adev,
                                    struct amdgpu_fpriv *fpriv, uint32_t id,
                                    bool set, u32 *stable_pstate)
@@ -675,8 +675,10 @@ int amdgpu_ctx_ioctl(struct drm_device *dev, void *data,
        id = args->in.ctx_id;
        priority = args->in.priority;
 
-       /* For backwards compatibility reasons, we need to accept
-        * ioctls with garbage in the priority field */
+       /* For backwards compatibility, we need to accept ioctls with garbage
+        * in the priority field. Garbage values in the priority field, result
+        * in the priority being set to NORMAL.
+        */
        if (!amdgpu_ctx_priority_is_valid(priority))
                priority = AMDGPU_CTX_PRIORITY_NORMAL;
 
index 30c4f5cca02c9f6f6f4aaffc363158ca8145c43e..2b8356699f235dc2e18f991b70e18de56200e5c2 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 12210598e5b8e64c8f88d50eaec69ff3f3161bac..ba3a87cb88ccc9de8ea6ad71012d880ab1777336 100644 (file)
@@ -403,7 +403,10 @@ amdgpu_dma_buf_move_notify(struct dma_buf_attachment *attach)
                                continue;
                }
 
-               r = amdgpu_vm_clear_freed(adev, vm, NULL);
+               /* Reserve fences for two SDMA page table updates */
+               r = dma_resv_reserve_fences(resv, 2);
+               if (!r)
+                       r = amdgpu_vm_clear_freed(adev, vm, NULL);
                if (!r)
                        r = amdgpu_vm_handle_moved(adev, vm);
 
index da4be0bbb446672bfadb9e1f6f69e281a421a4cf..8eee5d783a92bd3dd3f5567b1d788acee2997602 100644 (file)
@@ -142,6 +142,10 @@ int amdgpu_doorbell_create_kernel_doorbells(struct amdgpu_device *adev)
        int r;
        int size;
 
+       /* SI HW does not have doorbells, skip allocation */
+       if (adev->doorbell.num_kernel_doorbells == 0)
+               return 0;
+
        /* Reserve first num_kernel_doorbells (page-aligned) for kernel ops */
        size = ALIGN(adev->doorbell.num_kernel_doorbells * sizeof(u32), PAGE_SIZE);
 
index 9c66d98af6d86ae41870fb1cb2d18b26787d9f29..7cd0dfaeee206c15d9ef069947085d3088f95816 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 f3ee83cdf97eff81316c86c08a3f04e6126dfaee..d28e21baef16ee3076c20a0bd9aa5fd6c0ba774b 100644 (file)
@@ -252,7 +252,7 @@ static inline bool amdgpu_bo_in_cpu_visible_vram(struct amdgpu_bo *bo)
        struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
        struct amdgpu_res_cursor cursor;
 
-       if (bo->tbo.resource->mem_type != TTM_PL_VRAM)
+       if (!bo->tbo.resource || bo->tbo.resource->mem_type != TTM_PL_VRAM)
                return false;
 
        amdgpu_res_first(bo->tbo.resource, 0, amdgpu_bo_size(bo), &cursor);
index 937c54fc7174518ec80461616cf353423125bd65..163445baa4fc80a432209247e43c4fb76d4da979 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 f5daadcec865d6863650d1d515fd416ac890595c..82f25996ff5ef63f1528e5353d495703a7922a32 100644 (file)
@@ -1090,7 +1090,8 @@ int amdgpu_vm_bo_update(struct amdgpu_device *adev, struct amdgpu_bo_va *bo_va,
                        struct drm_gem_object *gobj = dma_buf->priv;
                        struct amdgpu_bo *abo = gem_to_amdgpu_bo(gobj);
 
-                       if (abo->tbo.resource->mem_type == TTM_PL_VRAM)
+                       if (abo->tbo.resource &&
+                           abo->tbo.resource->mem_type == TTM_PL_VRAM)
                                bo = gem_to_amdgpu_bo(gobj);
                }
                mem = bo->tbo.resource;
index 6a8494f98d3ef488659479270b8a2a5464585868..fe8ba9e9837b39e82bc94cceb5a5a4e9a88b5ee4 100644 (file)
@@ -1124,7 +1124,7 @@ static void vi_program_aspm(struct amdgpu_device *adev)
        bool bL1SS = false;
        bool bClkReqSupport = true;
 
-       if (!amdgpu_device_should_use_aspm(adev) || !amdgpu_device_aspm_support_quirk())
+       if (!amdgpu_device_should_use_aspm(adev) || !amdgpu_device_pcie_dynamic_switching_supported())
                return;
 
        if (adev->flags & AMD_IS_APU ||
index 8a6cb41444a4767a1f5270d49af93ec8722269b6..0d3d538b64ebc319d705bcdde28ab9179c3575b4 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 c6fd34bab3585ad8c027f4b1bcc3af145bb379a9..868946dd7ef12602842ab389cef64a4275ff10da 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 c435f7632e8e8b76b868a26fec65d40f938ee6b6..5ee87965a07818a67916326ff277a1626aba6e04 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 984b52923534056cc3e4a76e115e3edbd0ce2332..e9345f6554dbcb06cce61b98e1b68c0432f967ce 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 3a9077b60029ba9626301d204c35443290664ba9..d08e60dff46deb851f2dc22cec478551b5f2d8a4 100644 (file)
@@ -1262,6 +1262,9 @@ static void disable_vbios_mode_if_required(
                if (stream == NULL)
                        continue;
 
+               if (stream->apply_seamless_boot_optimization)
+                       continue;
+
                // only looking for first odm pipe
                if (pipe->prev_odm_pipe)
                        continue;
index 478281f2a5ba7f2e2b8c93a0cee3bd2edac6e17d..2a6157555fd1e4617c4f7320c49b367eab1d543f 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 e72f15ac00482df19be0cdd9d9affef5f981a2d1..aeadc587433fd5a1410123b8529e60c48496a292 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 3082da04a63db76d8b15cd7f62bf639e18f083d4..1d052f08aff5e16ffc10a9695bca927a64ea68f5 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 41147da54458943b4b70ae9664b3860b00193f68..8bb2da13826f16bac126b7a5c59e0057e30ad8bb 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 4bb289f9b4b8b82a59a99ad92e18deaa6900b850..da2860da60188e084bbbfafd11403822befc20ab 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 f448b903e19075676247fc72d30a1a9b1f501085..84148a79414b7ff4cbc1c41348334cf995d99329 100644 (file)
@@ -692,7 +692,7 @@ static struct ti_sn65dsi86 *bridge_to_ti_sn65dsi86(struct drm_bridge *bridge)
        return container_of(bridge, struct ti_sn65dsi86, bridge);
 }
 
-static int ti_sn_attach_host(struct ti_sn65dsi86 *pdata)
+static int ti_sn_attach_host(struct auxiliary_device *adev, struct ti_sn65dsi86 *pdata)
 {
        int val;
        struct mipi_dsi_host *host;
@@ -707,7 +707,7 @@ static int ti_sn_attach_host(struct ti_sn65dsi86 *pdata)
        if (!host)
                return -EPROBE_DEFER;
 
-       dsi = devm_mipi_dsi_device_register_full(dev, host, &info);
+       dsi = devm_mipi_dsi_device_register_full(&adev->dev, host, &info);
        if (IS_ERR(dsi))
                return PTR_ERR(dsi);
 
@@ -725,7 +725,7 @@ static int ti_sn_attach_host(struct ti_sn65dsi86 *pdata)
 
        pdata->dsi = dsi;
 
-       return devm_mipi_dsi_attach(dev, dsi);
+       return devm_mipi_dsi_attach(&adev->dev, dsi);
 }
 
 static int ti_sn_bridge_attach(struct drm_bridge *bridge,
@@ -1298,9 +1298,9 @@ static int ti_sn_bridge_probe(struct auxiliary_device *adev,
        struct device_node *np = pdata->dev->of_node;
        int ret;
 
-       pdata->next_bridge = devm_drm_of_get_bridge(pdata->dev, np, 1, 0);
+       pdata->next_bridge = devm_drm_of_get_bridge(&adev->dev, np, 1, 0);
        if (IS_ERR(pdata->next_bridge))
-               return dev_err_probe(pdata->dev, PTR_ERR(pdata->next_bridge),
+               return dev_err_probe(&adev->dev, PTR_ERR(pdata->next_bridge),
                                     "failed to create panel bridge\n");
 
        ti_sn_bridge_parse_lanes(pdata, np);
@@ -1319,9 +1319,9 @@ static int ti_sn_bridge_probe(struct auxiliary_device *adev,
 
        drm_bridge_add(&pdata->bridge);
 
-       ret = ti_sn_attach_host(pdata);
+       ret = ti_sn_attach_host(adev, pdata);
        if (ret) {
-               dev_err_probe(pdata->dev, ret, "failed to attach dsi host\n");
+               dev_err_probe(&adev->dev, ret, "failed to attach dsi host\n");
                goto err_remove_bridge;
        }
 
index ed96cfcfa304013158dbaa3629529d32ed07cc7d..8c929ef72c72c76809a532724e593fa0e168fa47 100644 (file)
@@ -2574,14 +2574,14 @@ static struct drm_dp_mst_branch *get_mst_branch_device_by_guid_helper(
        struct drm_dp_mst_branch *found_mstb;
        struct drm_dp_mst_port *port;
 
+       if (!mstb)
+               return NULL;
+
        if (memcmp(mstb->guid, guid, 16) == 0)
                return mstb;
 
 
        list_for_each_entry(port, &mstb->ports, next) {
-               if (!port->mstb)
-                       continue;
-
                found_mstb = get_mst_branch_device_by_guid_helper(port->mstb, guid);
 
                if (found_mstb)
index 292e38eb621806a007c61ff631a50d8fb7f072b6..60794fcde1d50ffc41458603b6dd08e314b47614 100644 (file)
@@ -290,7 +290,8 @@ static int
 update_connector_routing(struct drm_atomic_state *state,
                         struct drm_connector *connector,
                         struct drm_connector_state *old_connector_state,
-                        struct drm_connector_state *new_connector_state)
+                        struct drm_connector_state *new_connector_state,
+                        bool added_by_user)
 {
        const struct drm_connector_helper_funcs *funcs;
        struct drm_encoder *new_encoder;
@@ -339,9 +340,13 @@ update_connector_routing(struct drm_atomic_state *state,
         * there's a chance the connector may have been destroyed during the
         * process, but it's better to ignore that then cause
         * drm_atomic_helper_resume() to fail.
+        *
+        * Last, we want to ignore connector registration when the connector
+        * was not pulled in the atomic state by user-space (ie, was pulled
+        * in by the driver, e.g. when updating a DP-MST stream).
         */
        if (!state->duplicated && drm_connector_is_unregistered(connector) &&
-           crtc_state->active) {
+           added_by_user && crtc_state->active) {
                drm_dbg_atomic(connector->dev,
                               "[CONNECTOR:%d:%s] is not registered\n",
                               connector->base.id, connector->name);
@@ -620,7 +625,10 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
        struct drm_connector *connector;
        struct drm_connector_state *old_connector_state, *new_connector_state;
        int i, ret;
-       unsigned int connectors_mask = 0;
+       unsigned int connectors_mask = 0, user_connectors_mask = 0;
+
+       for_each_oldnew_connector_in_state(state, connector, old_connector_state, new_connector_state, i)
+               user_connectors_mask |= BIT(i);
 
        for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
                bool has_connectors =
@@ -685,7 +693,8 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
                 */
                ret = update_connector_routing(state, connector,
                                               old_connector_state,
-                                              new_connector_state);
+                                              new_connector_state,
+                                              BIT(i) & user_connectors_mask);
                if (ret)
                        return ret;
                if (old_connector_state->crtc) {
index 340da8257b51b4f5e639e084ff10e38b5c2a3a3a..4b71040ae5be5c15c3f4e0a4de943bba24b59e7f 100644 (file)
@@ -123,6 +123,9 @@ static const struct edid_quirk {
        /* AEO model 0 reports 8 bpc, but is a 6 bpc panel */
        EDID_QUIRK('A', 'E', 'O', 0, EDID_QUIRK_FORCE_6BPC),
 
+       /* BenQ GW2765 */
+       EDID_QUIRK('B', 'N', 'Q', 0x78d6, EDID_QUIRK_FORCE_8BPC),
+
        /* BOE model on HP Pavilion 15-n233sl reports 8 bpc, but is a 6 bpc panel */
        EDID_QUIRK('B', 'O', 'E', 0x78b, EDID_QUIRK_FORCE_6BPC),
 
index 6129b89bb36618db7686cec9cc0a7a4c8d9d5410..44a948b80ee14eb4d9f430b61bd0b7dab0afef17 100644 (file)
@@ -540,7 +540,7 @@ struct page **drm_gem_get_pages(struct drm_gem_object *obj)
        struct page **pages;
        struct folio *folio;
        struct folio_batch fbatch;
-       int i, j, npages;
+       long i, j, npages;
 
        if (WARN_ON(!obj->filp))
                return ERR_PTR(-EINVAL);
@@ -564,11 +564,13 @@ struct page **drm_gem_get_pages(struct drm_gem_object *obj)
 
        i = 0;
        while (i < npages) {
+               long nr;
                folio = shmem_read_folio_gfp(mapping, i,
                                mapping_gfp_mask(mapping));
                if (IS_ERR(folio))
                        goto fail;
-               for (j = 0; j < folio_nr_pages(folio); j++, i++)
+               nr = min(npages - i, folio_nr_pages(folio));
+               for (j = 0; j < nr; j++, i++)
                        pages[i] = folio_file_page(folio, i);
 
                /* Make sure shmem keeps __GFP_DMA32 allocated pages in the
index 0cb646cb04ee1ae5028aa03439df18f06925760a..d5c15292ae93781335a8e8a441be94f9bb235f04 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 1b00ef2c6185073fb29c1683ee1d3adae3c87402..80e4ec6ee4031ba9021b73bc808b5d6ae935a4b6 100644 (file)
@@ -2553,8 +2553,7 @@ static void intel_cx0_phy_lane_reset(struct drm_i915_private *i915,
                drm_warn(&i915->drm, "PHY %c failed to bring out of SOC reset after %dus.\n",
                         phy_name(phy), XELPDP_PORT_BUF_SOC_READY_TIMEOUT_US);
 
-       intel_de_rmw(i915, XELPDP_PORT_BUF_CTL2(port),
-                    XELPDP_LANE_PIPE_RESET(0) | XELPDP_LANE_PIPE_RESET(1),
+       intel_de_rmw(i915, XELPDP_PORT_BUF_CTL2(port), lane_pipe_reset,
                     lane_pipe_reset);
 
        if (__intel_de_wait_for_register(i915, XELPDP_PORT_BUF_CTL2(port),
index aa4d842d4c5a8a4ceaf81dd07773f8b1582f943b..310654542b42c107ef62192e236cad9048435a3c 100644 (file)
@@ -235,6 +235,7 @@ static vm_fault_t i915_error_to_vmf_fault(int err)
        case 0:
        case -EAGAIN:
        case -ENOSPC: /* transient failure to evict? */
+       case -ENOBUFS: /* temporarily out of fences? */
        case -ERESTARTSYS:
        case -EINTR:
        case -EBUSY:
index 6b6d22c194110c5c04797493db44154b8426d0d1..0ba955611dfb543b1c87b6de1d11faeecbf988f8 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 8f1633c3fb9352cc0678ff80329736187cef39b8..73a4a4eb29e08689fdac30acd3a88739f3205a12 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 a4ff55aa5e55b91835e0bbde3617601d56d9a6ef..7ad36198aab2a4301e509614b0d3fb2300ef11f7 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 ee15486fed0daa57479b07da01e2b7c3ea78391b..e85d70a62123f9bbd824c9df1542dd7ecf9c7b62 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 8a641bcf777cb4da2c211911a470272d759314a4..3292524469d509655db5a7130a07c744af440bb3 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 dd0ed941441aab84be728ee5f333f44d682a8c66..da21f2786b5d7d2601024be7630e56e289bf61dc 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 0b414eae16831cbd697cd24e4e7128cd3e0a87fa..2c0f1f3e28ff89aa956349bc953fea5576c06b1e 100644 (file)
@@ -376,9 +376,26 @@ void intel_gt_mcr_lock(struct intel_gt *gt, unsigned long *flags)
         * driver threads, but also with hardware/firmware agents.  A dedicated
         * locking register is used.
         */
-       if (GRAPHICS_VER_FULL(gt->i915) >= IP_VER(12, 70))
+       if (GRAPHICS_VER_FULL(gt->i915) >= IP_VER(12, 70)) {
+               /*
+                * The steering control and semaphore registers are inside an
+                * "always on" power domain with respect to RC6.  However there
+                * are some issues if higher-level platform sleep states are
+                * entering/exiting at the same time these registers are
+                * accessed.  Grabbing GT forcewake and holding it over the
+                * entire lock/steer/unlock cycle ensures that those sleep
+                * states have been fully exited before we access these
+                * registers.  This wakeref will be released in the unlock
+                * routine.
+                *
+                * This is expected to become a formally documented/numbered
+                * workaround soon.
+                */
+               intel_uncore_forcewake_get(gt->uncore, FORCEWAKE_GT);
+
                err = wait_for(intel_uncore_read_fw(gt->uncore,
                                                    MTL_STEER_SEMAPHORE) == 0x1, 100);
+       }
 
        /*
         * Even on platforms with a hardware lock, we'll continue to grab
@@ -415,8 +432,11 @@ void intel_gt_mcr_unlock(struct intel_gt *gt, unsigned long flags)
 {
        spin_unlock_irqrestore(&gt->mcr_lock, flags);
 
-       if (GRAPHICS_VER_FULL(gt->i915) >= IP_VER(12, 70))
+       if (GRAPHICS_VER_FULL(gt->i915) >= IP_VER(12, 70)) {
                intel_uncore_write_fw(gt->uncore, MTL_STEER_SEMAPHORE, 0x1);
+
+               intel_uncore_forcewake_put(gt->uncore, FORCEWAKE_GT);
+       }
 }
 
 /**
index 957d0aeb0c022f464720f1b456192b849ebff875..c378cc7c953c47c3af190a62bcff2b36f57f9b7a 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 b5b7f2fe8c78e4c70423909d3d65addd7769ff26..dc7b40e06e38afc2e88f6f6e9c6c564d6a7b8b30 100644 (file)
@@ -1432,6 +1432,36 @@ static void guc_timestamp_ping(struct work_struct *wrk)
        unsigned long index;
        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
@@ -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 1f65bb33dd212f2c44895f2317c8738a2d05b64c..a8551ce322de21bc2183f64029a0782340b77ad6 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 04bc1f4a111504c7ced76345c288aecf17ba5356..59e1e21df27104760bbb432c6fef30278f667932 100644 (file)
@@ -482,8 +482,7 @@ static void oa_report_id_clear(struct i915_perf_stream *stream, u32 *report)
 static bool oa_report_ctx_invalid(struct i915_perf_stream *stream, void *report)
 {
        return !(oa_report_id(stream, report) &
-              stream->perf->gen8_valid_ctx_bit) &&
-              GRAPHICS_VER(stream->perf->i915) <= 11;
+              stream->perf->gen8_valid_ctx_bit);
 }
 
 static u64 oa_timestamp(struct i915_perf_stream *stream, void *report)
@@ -5106,6 +5105,7 @@ static void i915_perf_init_info(struct drm_i915_private *i915)
                perf->gen8_valid_ctx_bit = BIT(16);
                break;
        case 12:
+               perf->gen8_valid_ctx_bit = BIT(16);
                /*
                 * Calculate offset at runtime in oa_pin_context for gen12 and
                 * cache the value in perf->ctx_oactxctrl_offset.
index d35973b411863b0de152024f09a01893f2fd8d49..7b1076b5e748c54f068cf66ad75f695134d413d4 100644 (file)
@@ -832,9 +832,18 @@ static void i915_pmu_event_start(struct perf_event *event, int flags)
 
 static void i915_pmu_event_stop(struct perf_event *event, int flags)
 {
+       struct drm_i915_private *i915 =
+               container_of(event->pmu, typeof(*i915), pmu.base);
+       struct i915_pmu *pmu = &i915->pmu;
+
+       if (pmu->closed)
+               goto out;
+
        if (flags & PERF_EF_UPDATE)
                i915_pmu_event_read(event);
        i915_pmu_disable(event);
+
+out:
        event->hw.state = PERF_HES_STOPPED;
 }
 
index fa7a883688094c8176b6222f79eed6b761e5466b..1df22a852a23e23841b1bdcf4d960bae0b17ec70 100644 (file)
@@ -5,5 +5,7 @@ config DRM_LOGICVC
        select DRM_KMS_HELPER
        select DRM_KMS_DMA_HELPER
        select DRM_GEM_DMA_HELPER
+       select REGMAP
+       select REGMAP_MMIO
        help
          DRM display driver for the logiCVC programmable logic block from Xylon
index 9f364df52478d8a43ced1fb2a7f1c0b35ef9e53f..0e0a41b2f57f05d513d256ebf3d84333ecc5484a 100644 (file)
@@ -239,6 +239,7 @@ int mtk_drm_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map)
        npages = obj->size >> PAGE_SHIFT;
        mtk_gem->pages = kcalloc(npages, sizeof(*mtk_gem->pages), GFP_KERNEL);
        if (!mtk_gem->pages) {
+               sg_free_table(sgt);
                kfree(sgt);
                return -ENOMEM;
        }
@@ -248,12 +249,15 @@ int mtk_drm_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map)
        mtk_gem->kvaddr = vmap(mtk_gem->pages, npages, VM_MAP,
                               pgprot_writecombine(PAGE_KERNEL));
        if (!mtk_gem->kvaddr) {
+               sg_free_table(sgt);
                kfree(sgt);
                kfree(mtk_gem->pages);
                return -ENOMEM;
        }
-out:
+       sg_free_table(sgt);
        kfree(sgt);
+
+out:
        iosys_map_set_vaddr(map, mtk_gem->kvaddr);
 
        return 0;
index 9913971fa5d20bc9d192695d8b2773d0244615ce..25ea765586908f14d08715f45ca9def85a6a07f3 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 c2aaaded07ed6a9808eb4b93fe945715203f0cf1..0be195f9149c5698f708d5131c4bd5782927bf3f 100644 (file)
@@ -119,6 +119,7 @@ static u64 _dpu_plane_calc_bw(const struct dpu_mdss_cfg *catalog,
        struct dpu_sw_pipe_cfg *pipe_cfg)
 {
        int src_width, src_height, dst_height, fps;
+       u64 plane_pixel_rate, plane_bit_rate;
        u64 plane_prefill_bw;
        u64 plane_bw;
        u32 hw_latency_lines;
@@ -136,13 +137,12 @@ static u64 _dpu_plane_calc_bw(const struct dpu_mdss_cfg *catalog,
        scale_factor = src_height > dst_height ?
                mult_frac(src_height, 1, dst_height) : 1;
 
-       plane_bw =
-               src_width * mode->vtotal * fps * fmt->bpp *
-               scale_factor;
+       plane_pixel_rate = src_width * mode->vtotal * fps;
+       plane_bit_rate = plane_pixel_rate * fmt->bpp;
 
-       plane_prefill_bw =
-               src_width * hw_latency_lines * fps * fmt->bpp *
-               scale_factor * mode->vtotal;
+       plane_bw = plane_bit_rate * scale_factor;
+
+       plane_prefill_bw = plane_bw * hw_latency_lines;
 
        if ((vbp+vpw) > hw_latency_lines)
                do_div(plane_prefill_bw, (vbp+vpw));
@@ -733,9 +733,11 @@ static int dpu_plane_check_inline_rotation(struct dpu_plane *pdpu,
 static int dpu_plane_atomic_check_pipe(struct dpu_plane *pdpu,
                struct dpu_sw_pipe *pipe,
                struct dpu_sw_pipe_cfg *pipe_cfg,
-               const struct dpu_format *fmt)
+               const struct dpu_format *fmt,
+               const struct drm_display_mode *mode)
 {
        uint32_t min_src_size;
+       struct dpu_kms *kms = _dpu_plane_get_kms(&pdpu->base);
 
        min_src_size = DPU_FORMAT_IS_YUV(fmt) ? 2 : 1;
 
@@ -774,6 +776,12 @@ static int dpu_plane_atomic_check_pipe(struct dpu_plane *pdpu,
                return -EINVAL;
        }
 
+       /* max clk check */
+       if (_dpu_plane_calc_clk(mode, pipe_cfg) > kms->perf.max_core_clk_rate) {
+               DPU_DEBUG_PLANE(pdpu, "plane exceeds max mdp core clk limits\n");
+               return -E2BIG;
+       }
+
        return 0;
 }
 
@@ -899,12 +907,13 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
                r_pipe_cfg->dst_rect.x1 = pipe_cfg->dst_rect.x2;
        }
 
-       ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg, fmt);
+       ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg, fmt, &crtc_state->adjusted_mode);
        if (ret)
                return ret;
 
        if (r_pipe->sspp) {
-               ret = dpu_plane_atomic_check_pipe(pdpu, r_pipe, r_pipe_cfg, fmt);
+               ret = dpu_plane_atomic_check_pipe(pdpu, r_pipe, r_pipe_cfg, fmt,
+                                                 &crtc_state->adjusted_mode);
                if (ret)
                        return ret;
        }
index a7a5c7e0ab923b9e4a08786c4669dea27800e6ab..77a8d9366ed7b01d46a01cf602e74eafb15d4937 100644 (file)
@@ -1774,13 +1774,6 @@ int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl)
                return rc;
 
        while (--link_train_max_retries) {
-               rc = dp_ctrl_reinitialize_mainlink(ctrl);
-               if (rc) {
-                       DRM_ERROR("Failed to reinitialize mainlink. rc=%d\n",
-                                       rc);
-                       break;
-               }
-
                training_step = DP_TRAINING_NONE;
                rc = dp_ctrl_setup_main_link(ctrl, &training_step);
                if (rc == 0) {
@@ -1832,6 +1825,12 @@ int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl)
                        /* stop link training before start re training  */
                        dp_ctrl_clear_training_pattern(ctrl);
                }
+
+               rc = dp_ctrl_reinitialize_mainlink(ctrl);
+               if (rc) {
+                       DRM_ERROR("Failed to reinitialize mainlink. rc=%d\n", rc);
+                       break;
+               }
        }
 
        if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN)
index 42427129acea86057839d862e7d922965707f695..6375daaeb98e1c7ca0310eb6b0df2fa89b78a85d 100644 (file)
@@ -1090,7 +1090,7 @@ int dp_link_process_request(struct dp_link *dp_link)
        } else if (dp_link_read_psr_error_status(link)) {
                DRM_ERROR("PSR IRQ_HPD received\n");
        } else if (dp_link_psr_capability_changed(link)) {
-               drm_dbg_dp(link->drm_dev, "PSR Capability changed");
+               drm_dbg_dp(link->drm_dev, "PSR Capability changed\n");
        } else {
                ret = dp_link_process_link_status_update(link);
                if (!ret) {
@@ -1107,7 +1107,7 @@ int dp_link_process_request(struct dp_link *dp_link)
                }
        }
 
-       drm_dbg_dp(link->drm_dev, "sink request=%#x",
+       drm_dbg_dp(link->drm_dev, "sink request=%#x\n",
                                dp_link->sink_request);
        return ret;
 }
index 5d9ec27c89d3a0538f283bc7149b6ed2aecf4c54..3d6fb708dc223e55d1d8cc8bb943285014fee98e 100644 (file)
@@ -1082,9 +1082,21 @@ static void dsi_wait4video_done(struct msm_dsi_host *msm_host)
 
 static void dsi_wait4video_eng_busy(struct msm_dsi_host *msm_host)
 {
+       u32 data;
+
        if (!(msm_host->mode_flags & MIPI_DSI_MODE_VIDEO))
                return;
 
+       data = dsi_read(msm_host, REG_DSI_STATUS0);
+
+       /* if video mode engine is not busy, its because
+        * either timing engine was not turned on or the
+        * DSI controller has finished transmitting the video
+        * data already, so no need to wait in those cases
+        */
+       if (!(data & DSI_STATUS0_VIDEO_MODE_ENGINE_BUSY))
+               return;
+
        if (msm_host->power_on && msm_host->enabled) {
                dsi_wait4video_done(msm_host);
                /* delay 4 ms to skip BLLP */
@@ -1894,10 +1906,9 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi)
        }
 
        msm_host->irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
-       if (msm_host->irq < 0) {
-               ret = msm_host->irq;
-               dev_err(&pdev->dev, "failed to get irq: %d\n", ret);
-               return ret;
+       if (!msm_host->irq) {
+               dev_err(&pdev->dev, "failed to get irq\n");
+               return -EINVAL;
        }
 
        /* do not autoenable, will be enabled later */
index 2e87dd6cb17bf5488433301b92efa5055cf25862..348c66b146834116002e84ac0e5b7cfbebcd3c10 100644 (file)
@@ -511,7 +511,7 @@ static int mdss_remove(struct platform_device *pdev)
 static const struct msm_mdss_data msm8998_data = {
        .ubwc_enc_version = UBWC_1_0,
        .ubwc_dec_version = UBWC_1_0,
-       .highest_bank_bit = 1,
+       .highest_bank_bit = 2,
 };
 
 static const struct msm_mdss_data qcm2290_data = {
index 30afbec9e3b1bdbf87fd05c1cb4b58739f2941c6..2edd7bb13faea5ebb15985867cab304d12d2da96 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 bb3d6e5c122f6dd06d4b8e48be27adc3cbf21763..7c97b288680760819971a7823221da5e7179c7ab 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 1744d95b233e11a1e51339ea96f15627f36a20b4..c52cda82353e337e07ec51227333a4dba25c8b9c 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 1fe17ff95f5eec4c49e73a7123c91112c2a3fd22..e73a233c6572322dbee898b8f6962cf6b386b23f 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 19024ce21fbbd968de9a26a77c59f23a7586a67b..c1837ba95fb5802cf589e8ee5aaa14ca2de1c083 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 778cacd90f656361aeac7d6774b32b40f7162bbd..5488d337bcc0e29852a20e2e2c6af986cc60f9fe 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 61d9e70da9fd536252b7643a42385717c1027957..ca762ea5541361bb023e8b0288470502797f1a15 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 88217185e0f388353a247a7bb033c59300f73d2f..3b7ea52212260583ffbdfae77ddd92936d1d00ae 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 46b057fe1412ece4bd4fabaa9bca136260ef8dfe..3249e5c1c89308dd7a9d4a12a4c48bcf29479af9 100644 (file)
@@ -62,6 +62,18 @@ nvkm_uconn_uevent_gpio(struct nvkm_object *object, u64 token, u32 bits)
        return object->client->event(token, &args, sizeof(args.v0));
 }
 
+static bool
+nvkm_connector_is_dp_dms(u8 type)
+{
+       switch (type) {
+       case DCB_CONNECTOR_DMS59_DP0:
+       case DCB_CONNECTOR_DMS59_DP1:
+               return true;
+       default:
+               return false;
+       }
+}
+
 static int
 nvkm_uconn_uevent(struct nvkm_object *object, void *argv, u32 argc, struct nvkm_uevent *uevent)
 {
@@ -101,7 +113,7 @@ nvkm_uconn_uevent(struct nvkm_object *object, void *argv, u32 argc, struct nvkm_
        if (args->v0.types & NVIF_CONN_EVENT_V0_UNPLUG) bits |= NVKM_GPIO_LO;
        if (args->v0.types & NVIF_CONN_EVENT_V0_IRQ) {
                /* TODO: support DP IRQ on ANX9805 and remove this hack. */
-               if (!outp->info.location)
+               if (!outp->info.location && !nvkm_connector_is_dp_dms(conn->info.type))
                        return -EINVAL;
        }
 
index 5ac926281d2c65e1c6e7b652a29570940a33f017..c9087f474cbc5a6b9beb045b72abd025940781ff 100644 (file)
@@ -1342,9 +1342,7 @@ static const struct panel_init_cmd starry_himax83102_j02_init_cmd[] = {
        _INIT_DCS_CMD(0xB1, 0x01, 0xBF, 0x11),
        _INIT_DCS_CMD(0xCB, 0x86),
        _INIT_DCS_CMD(0xD2, 0x3C, 0xFA),
-       _INIT_DCS_CMD(0xE9, 0xC5),
-       _INIT_DCS_CMD(0xD3, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0C, 0x01),
-       _INIT_DCS_CMD(0xE9, 0x3F),
+       _INIT_DCS_CMD(0xD3, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0C, 0x01),
        _INIT_DCS_CMD(0xE7, 0x02, 0x00, 0x28, 0x01, 0x7E, 0x0F, 0x7E, 0x10, 0xA0, 0x00, 0x00, 0x20, 0x40, 0x50, 0x40),
        _INIT_DCS_CMD(0xBD, 0x02),
        _INIT_DCS_CMD(0xD8, 0xFF, 0xFF, 0xBF, 0xFE, 0xAA, 0xA0, 0xFF, 0xFF, 0xBF, 0xFE, 0xAA, 0xA0),
index feb665df35a1d925b0739c2ae350c660e9db772d..95c8472d878a9993aff09e3ec77fd95d4bc06b84 100644 (file)
@@ -976,32 +976,6 @@ static const struct panel_desc auo_b116xak01 = {
        },
 };
 
-static const struct drm_display_mode auo_b116xw03_mode = {
-       .clock = 70589,
-       .hdisplay = 1366,
-       .hsync_start = 1366 + 40,
-       .hsync_end = 1366 + 40 + 40,
-       .htotal = 1366 + 40 + 40 + 32,
-       .vdisplay = 768,
-       .vsync_start = 768 + 10,
-       .vsync_end = 768 + 10 + 12,
-       .vtotal = 768 + 10 + 12 + 6,
-       .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
-};
-
-static const struct panel_desc auo_b116xw03 = {
-       .modes = &auo_b116xw03_mode,
-       .num_modes = 1,
-       .bpc = 6,
-       .size = {
-               .width = 256,
-               .height = 144,
-       },
-       .delay = {
-               .enable = 400,
-       },
-};
-
 static const struct drm_display_mode auo_b133han05_mode = {
        .clock = 142600,
        .hdisplay = 1920,
@@ -1725,9 +1699,6 @@ static const struct of_device_id platform_of_match[] = {
        }, {
                .compatible = "auo,b116xa01",
                .data = &auo_b116xak01,
-       }, {
-               .compatible = "auo,b116xw03",
-               .data = &auo_b116xw03,
        }, {
                .compatible = "auo,b133han05",
                .data = &auo_b133han05,
index 95959dcc6e0e2ca454df765f7a6c13b96f5324e1..dd7928d9570f726d86e7224f2f19cbdbeeffea10 100644 (file)
@@ -919,6 +919,38 @@ static const struct panel_desc auo_b101xtn01 = {
        },
 };
 
+static const struct drm_display_mode auo_b116xw03_mode = {
+       .clock = 70589,
+       .hdisplay = 1366,
+       .hsync_start = 1366 + 40,
+       .hsync_end = 1366 + 40 + 40,
+       .htotal = 1366 + 40 + 40 + 32,
+       .vdisplay = 768,
+       .vsync_start = 768 + 10,
+       .vsync_end = 768 + 10 + 12,
+       .vtotal = 768 + 10 + 12 + 6,
+       .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
+};
+
+static const struct panel_desc auo_b116xw03 = {
+       .modes = &auo_b116xw03_mode,
+       .num_modes = 1,
+       .bpc = 6,
+       .size = {
+               .width = 256,
+               .height = 144,
+       },
+       .delay = {
+               .prepare = 1,
+               .enable = 200,
+               .disable = 200,
+               .unprepare = 500,
+       },
+       .bus_format = MEDIA_BUS_FMT_RGB666_1X7X3_SPWG,
+       .bus_flags = DRM_BUS_FLAG_DE_HIGH,
+       .connector_type = DRM_MODE_CONNECTOR_LVDS,
+};
+
 static const struct display_timing auo_g070vvn01_timings = {
        .pixelclock = { 33300000, 34209000, 45000000 },
        .hactive = { 800, 800, 800 },
@@ -4102,6 +4134,9 @@ static const struct of_device_id platform_of_match[] = {
        }, {
                .compatible = "auo,b101xtn01",
                .data = &auo_b101xtn01,
+       }, {
+               .compatible = "auo,b116xw03",
+               .data = &auo_b116xw03,
        }, {
                .compatible = "auo,g070vvn01",
                .data = &auo_g070vvn01,
index 506371c427451a07f8b57662f33a5115b09bc062..5a3a622fc672f34978075360cf54654d72ac7c60 100644 (file)
@@ -929,7 +929,7 @@ drm_sched_get_cleanup_job(struct drm_gpu_scheduler *sched)
 
                if (next) {
                        next->s_fence->scheduled.timestamp =
-                               job->s_fence->finished.timestamp;
+                               dma_fence_timestamp(&job->s_fence->finished);
                        /* start TO timer for next job */
                        drm_sched_start_timeout(sched);
                }
index c1dfbfcaa0001f405a84725f53e2739b1ccc80d3..bccb33b900f390ff070b7e45241d57603f890cab 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 186b28dc70380f1477d5eabb49ece2e9ed37e848..05d5e7af6d250881b50b29d26e1069ca6c41273e 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 ff86ba1ae1b8b07b609b7e5567f3400d34c79010..8ea120eb8674bd41f48b4405cb784d87d356eeba 100644 (file)
@@ -745,7 +745,7 @@ static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv,
 
                ret = devm_aperture_acquire_from_firmware(dev, res->start, resource_size(res));
                if (ret) {
-                       drm_err(dev, "could not acquire memory range %pr: %d\n", &res, ret);
+                       drm_err(dev, "could not acquire memory range %pr: %d\n", res, ret);
                        return ERR_PTR(ret);
                }
 
index 7726a72befc5446bd73d9da51b7ccd8175c0ab5d..d48b39132b32427e089c01c272d237ec90f3c40b 100644 (file)
@@ -232,10 +232,6 @@ void ttm_device_fini(struct ttm_device *bdev)
        struct ttm_resource_manager *man;
        unsigned i;
 
-       man = ttm_manager_type(bdev, TTM_PL_SYSTEM);
-       ttm_resource_manager_set_used(man, false);
-       ttm_set_driver_manager(bdev, TTM_PL_SYSTEM, NULL);
-
        mutex_lock(&ttm_global_mutex);
        list_del(&bdev->device_list);
        mutex_unlock(&ttm_global_mutex);
@@ -243,6 +239,10 @@ void ttm_device_fini(struct ttm_device *bdev)
        drain_workqueue(bdev->wq);
        destroy_workqueue(bdev->wq);
 
+       man = ttm_manager_type(bdev, TTM_PL_SYSTEM);
+       ttm_resource_manager_set_used(man, false);
+       ttm_set_driver_manager(bdev, TTM_PL_SYSTEM, NULL);
+
        spin_lock(&bdev->lru_lock);
        for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i)
                if (list_empty(&man->lru[0]))
index 3c00135ead45af7bd5f9b9c64236750a0cdd4ad7..5c514946bbad974cdb05ee8ee6f456066b741255 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 c43853597776ffb0e6fea21e8cecbb1f6add9a7c..2bfac3aad7b7d6327b552b550f656973fd8758eb 100644 (file)
@@ -34,6 +34,8 @@
 
 static void vmw_bo_release(struct vmw_bo *vbo)
 {
+       WARN_ON(vbo->tbo.base.funcs &&
+               kref_read(&vbo->tbo.base.refcount) != 0);
        vmw_bo_unmap(vbo);
        drm_gem_object_release(&vbo->tbo.base);
 }
@@ -497,7 +499,7 @@ static int vmw_user_bo_synccpu_release(struct drm_file *filp,
                if (!(flags & drm_vmw_synccpu_allow_cs)) {
                        atomic_dec(&vmw_bo->cpu_writers);
                }
-               vmw_user_bo_unref(vmw_bo);
+               vmw_user_bo_unref(&vmw_bo);
        }
 
        return ret;
@@ -539,7 +541,7 @@ int vmw_user_bo_synccpu_ioctl(struct drm_device *dev, void *data,
                        return ret;
 
                ret = vmw_user_bo_synccpu_grab(vbo, arg->flags);
-               vmw_user_bo_unref(vbo);
+               vmw_user_bo_unref(&vbo);
                if (unlikely(ret != 0)) {
                        if (ret == -ERESTARTSYS || ret == -EBUSY)
                                return -EBUSY;
@@ -612,7 +614,6 @@ int vmw_user_bo_lookup(struct drm_file *filp,
        }
 
        *out = to_vmw_bo(gobj);
-       ttm_bo_get(&(*out)->tbo);
 
        return 0;
 }
index 1d433fceed3d84117b289534940d5192e362fa98..0d496dc9c6af7a352c0432f50f4dd9be37448b5e 100644 (file)
@@ -195,12 +195,19 @@ static inline struct vmw_bo *vmw_bo_reference(struct vmw_bo *buf)
        return buf;
 }
 
-static inline void vmw_user_bo_unref(struct vmw_bo *vbo)
+static inline struct vmw_bo *vmw_user_bo_ref(struct vmw_bo *vbo)
 {
-       if (vbo) {
-               ttm_bo_put(&vbo->tbo);
-               drm_gem_object_put(&vbo->tbo.base);
-       }
+       drm_gem_object_get(&vbo->tbo.base);
+       return vbo;
+}
+
+static inline void vmw_user_bo_unref(struct vmw_bo **buf)
+{
+       struct vmw_bo *tmp_buf = *buf;
+
+       *buf = NULL;
+       if (tmp_buf)
+               drm_gem_object_put(&tmp_buf->tbo.base);
 }
 
 static inline struct vmw_bo *to_vmw_bo(struct drm_gem_object *gobj)
index c0b24d1cacbf0bd3392817d35a4501316455d34c..a7c07692262b8fdbcb68f54c6a3858bebc342ec4 100644 (file)
@@ -432,7 +432,7 @@ static int vmw_cotable_resize(struct vmw_resource *res, size_t new_size)
         * for the new COTable. Initially pin the buffer object to make sure
         * we can use tryreserve without failure.
         */
-       ret = vmw_bo_create(dev_priv, &bo_params, &buf);
+       ret = vmw_gem_object_create(dev_priv, &bo_params, &buf);
        if (ret) {
                DRM_ERROR("Failed initializing new cotable MOB.\n");
                goto out_done;
@@ -502,7 +502,7 @@ static int vmw_cotable_resize(struct vmw_resource *res, size_t new_size)
 
        vmw_resource_mob_attach(res);
        /* Let go of the old mob. */
-       vmw_bo_unreference(&old_buf);
+       vmw_user_bo_unref(&old_buf);
        res->id = vcotbl->type;
 
        ret = dma_resv_reserve_fences(bo->base.resv, 1);
@@ -521,7 +521,7 @@ out_map_new:
 out_wait:
        ttm_bo_unpin(bo);
        ttm_bo_unreserve(bo);
-       vmw_bo_unreference(&buf);
+       vmw_user_bo_unref(&buf);
 
 out_done:
        MKS_STAT_TIME_POP(MKSSTAT_KERN_COTABLE_RESIZE);
index 58bfdf203ecae3460d3f9cf64d03f608e66bb7cd..3cd5090dedfc5b0571b4f4f1a1a1ac6a0d5b0638 100644 (file)
@@ -853,6 +853,10 @@ static inline bool vmw_resource_mob_attached(const struct vmw_resource *res)
 /**
  * GEM related functionality - vmwgfx_gem.c
  */
+struct vmw_bo_params;
+int vmw_gem_object_create(struct vmw_private *vmw,
+                         struct vmw_bo_params *params,
+                         struct vmw_bo **p_vbo);
 extern int vmw_gem_object_create_with_handle(struct vmw_private *dev_priv,
                                             struct drm_file *filp,
                                             uint32_t size,
index 98e0723ca6f5eec96017a39a0372e1eb5c471545..36987ef3fc300623eae6caff131f4d89ac4d1450 100644 (file)
@@ -1151,7 +1151,7 @@ static int vmw_translate_mob_ptr(struct vmw_private *dev_priv,
                                 SVGAMobId *id,
                                 struct vmw_bo **vmw_bo_p)
 {
-       struct vmw_bo *vmw_bo;
+       struct vmw_bo *vmw_bo, *tmp_bo;
        uint32_t handle = *id;
        struct vmw_relocation *reloc;
        int ret;
@@ -1164,7 +1164,8 @@ static int vmw_translate_mob_ptr(struct vmw_private *dev_priv,
        }
        vmw_bo_placement_set(vmw_bo, VMW_BO_DOMAIN_MOB, VMW_BO_DOMAIN_MOB);
        ret = vmw_validation_add_bo(sw_context->ctx, vmw_bo);
-       vmw_user_bo_unref(vmw_bo);
+       tmp_bo = vmw_bo;
+       vmw_user_bo_unref(&tmp_bo);
        if (unlikely(ret != 0))
                return ret;
 
@@ -1206,7 +1207,7 @@ static int vmw_translate_guest_ptr(struct vmw_private *dev_priv,
                                   SVGAGuestPtr *ptr,
                                   struct vmw_bo **vmw_bo_p)
 {
-       struct vmw_bo *vmw_bo;
+       struct vmw_bo *vmw_bo, *tmp_bo;
        uint32_t handle = ptr->gmrId;
        struct vmw_relocation *reloc;
        int ret;
@@ -1220,7 +1221,8 @@ static int vmw_translate_guest_ptr(struct vmw_private *dev_priv,
        vmw_bo_placement_set(vmw_bo, VMW_BO_DOMAIN_GMR | VMW_BO_DOMAIN_VRAM,
                             VMW_BO_DOMAIN_GMR | VMW_BO_DOMAIN_VRAM);
        ret = vmw_validation_add_bo(sw_context->ctx, vmw_bo);
-       vmw_user_bo_unref(vmw_bo);
+       tmp_bo = vmw_bo;
+       vmw_user_bo_unref(&tmp_bo);
        if (unlikely(ret != 0))
                return ret;
 
@@ -1619,7 +1621,7 @@ static int vmw_cmd_tex_state(struct vmw_private *dev_priv,
 {
        VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdSetTextureState);
        SVGA3dTextureState *last_state = (SVGA3dTextureState *)
-         ((unsigned long) header + header->size + sizeof(header));
+         ((unsigned long) header + header->size + sizeof(*header));
        SVGA3dTextureState *cur_state = (SVGA3dTextureState *)
                ((unsigned long) header + sizeof(*cmd));
        struct vmw_resource *ctx;
index c0da89e16e6fa765e21f040a2ba63a2c2b4f83bf..8b1eb0061610c79c56c1fe914345d3b6029e6768 100644 (file)
@@ -111,6 +111,20 @@ static const struct drm_gem_object_funcs vmw_gem_object_funcs = {
        .vm_ops = &vmw_vm_ops,
 };
 
+int vmw_gem_object_create(struct vmw_private *vmw,
+                         struct vmw_bo_params *params,
+                         struct vmw_bo **p_vbo)
+{
+       int ret = vmw_bo_create(vmw, params, p_vbo);
+
+       if (ret != 0)
+               goto out_no_bo;
+
+       (*p_vbo)->tbo.base.funcs = &vmw_gem_object_funcs;
+out_no_bo:
+       return ret;
+}
+
 int vmw_gem_object_create_with_handle(struct vmw_private *dev_priv,
                                      struct drm_file *filp,
                                      uint32_t size,
@@ -126,12 +140,10 @@ int vmw_gem_object_create_with_handle(struct vmw_private *dev_priv,
                .pin = false
        };
 
-       ret = vmw_bo_create(dev_priv, &params, p_vbo);
+       ret = vmw_gem_object_create(dev_priv, &params, p_vbo);
        if (ret != 0)
                goto out_no_bo;
 
-       (*p_vbo)->tbo.base.funcs = &vmw_gem_object_funcs;
-
        ret = drm_gem_handle_create(filp, &(*p_vbo)->tbo.base, handle);
 out_no_bo:
        return ret;
index 1489ad73c103fe3ac5e1a8e34b3ff1704b7253da..818b7f109f5380edc379f0b80e00649721abf31c 100644 (file)
@@ -1471,8 +1471,8 @@ static int vmw_create_bo_proxy(struct drm_device *dev,
        /* Reserve and switch the backing mob. */
        mutex_lock(&res->dev_priv->cmdbuf_mutex);
        (void) vmw_resource_reserve(res, false, true);
-       vmw_bo_unreference(&res->guest_memory_bo);
-       res->guest_memory_bo = vmw_bo_reference(bo_mob);
+       vmw_user_bo_unref(&res->guest_memory_bo);
+       res->guest_memory_bo = vmw_user_bo_ref(bo_mob);
        res->guest_memory_offset = 0;
        vmw_resource_unreserve(res, false, false, false, NULL, 0);
        mutex_unlock(&res->dev_priv->cmdbuf_mutex);
@@ -1666,7 +1666,7 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev,
 err_out:
        /* vmw_user_lookup_handle takes one ref so does new_fb */
        if (bo)
-               vmw_user_bo_unref(bo);
+               vmw_user_bo_unref(&bo);
        if (surface)
                vmw_surface_unreference(&surface);
 
index fb85f244c3d028022a8a422df6b5022184ef29db..c45b4724e4141dbfc07df9554c09917b8c9ec9ec 100644 (file)
@@ -451,7 +451,7 @@ int vmw_overlay_ioctl(struct drm_device *dev, void *data,
 
        ret = vmw_overlay_update_stream(dev_priv, buf, arg, true);
 
-       vmw_user_bo_unref(buf);
+       vmw_user_bo_unref(&buf);
 
 out_unlock:
        mutex_unlock(&overlay->mutex);
index 71eeabf001c874d03fc005d76b68a50f6e49f1d1..ca300c7427d28b1e761b2126af6e11c4478f8928 100644 (file)
@@ -141,7 +141,7 @@ static void vmw_resource_release(struct kref *kref)
                if (res->coherent)
                        vmw_bo_dirty_release(res->guest_memory_bo);
                ttm_bo_unreserve(bo);
-               vmw_bo_unreference(&res->guest_memory_bo);
+               vmw_user_bo_unref(&res->guest_memory_bo);
        }
 
        if (likely(res->hw_destroy != NULL)) {
@@ -338,7 +338,7 @@ static int vmw_resource_buf_alloc(struct vmw_resource *res,
                return 0;
        }
 
-       ret = vmw_bo_create(res->dev_priv, &bo_params, &gbo);
+       ret = vmw_gem_object_create(res->dev_priv, &bo_params, &gbo);
        if (unlikely(ret != 0))
                goto out_no_bo;
 
@@ -457,11 +457,11 @@ void vmw_resource_unreserve(struct vmw_resource *res,
                        vmw_resource_mob_detach(res);
                        if (res->coherent)
                                vmw_bo_dirty_release(res->guest_memory_bo);
-                       vmw_bo_unreference(&res->guest_memory_bo);
+                       vmw_user_bo_unref(&res->guest_memory_bo);
                }
 
                if (new_guest_memory_bo) {
-                       res->guest_memory_bo = vmw_bo_reference(new_guest_memory_bo);
+                       res->guest_memory_bo = vmw_user_bo_ref(new_guest_memory_bo);
 
                        /*
                         * The validation code should already have added a
@@ -551,7 +551,7 @@ out_no_reserve:
        ttm_bo_put(val_buf->bo);
        val_buf->bo = NULL;
        if (guest_memory_dirty)
-               vmw_bo_unreference(&res->guest_memory_bo);
+               vmw_user_bo_unref(&res->guest_memory_bo);
 
        return ret;
 }
@@ -727,7 +727,7 @@ int vmw_resource_validate(struct vmw_resource *res, bool intr,
                goto out_no_validate;
        else if (!res->func->needs_guest_memory && res->guest_memory_bo) {
                WARN_ON_ONCE(vmw_resource_mob_attached(res));
-               vmw_bo_unreference(&res->guest_memory_bo);
+               vmw_user_bo_unref(&res->guest_memory_bo);
        }
 
        return 0;
index 1e81ff2422cf6f3900ab968b3a1c77e15834bd90..a01ca3226d0af8909df61837e55d4726cd16a306 100644 (file)
@@ -180,7 +180,7 @@ static int vmw_gb_shader_init(struct vmw_private *dev_priv,
 
        res->guest_memory_size = size;
        if (byte_code) {
-               res->guest_memory_bo = vmw_bo_reference(byte_code);
+               res->guest_memory_bo = vmw_user_bo_ref(byte_code);
                res->guest_memory_offset = offset;
        }
        shader->size = size;
@@ -809,7 +809,7 @@ static int vmw_shader_define(struct drm_device *dev, struct drm_file *file_priv,
                                    shader_type, num_input_sig,
                                    num_output_sig, tfile, shader_handle);
 out_bad_arg:
-       vmw_user_bo_unref(buffer);
+       vmw_user_bo_unref(&buffer);
        return ret;
 }
 
index 5db403ee8261d38dae1477ac414c70c7b3ff689a..3829be282ff00f3f991e7df67f157ebeaaa6a610 100644 (file)
@@ -686,9 +686,6 @@ static void vmw_user_surface_base_release(struct ttm_base_object **p_base)
            container_of(base, struct vmw_user_surface, prime.base);
        struct vmw_resource *res = &user_srf->srf.res;
 
-       if (res->guest_memory_bo)
-               drm_gem_object_put(&res->guest_memory_bo->tbo.base);
-
        *p_base = NULL;
        vmw_resource_unreference(&res);
 }
@@ -855,23 +852,21 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
         * expect a backup buffer to be present.
         */
        if (dev_priv->has_mob && req->shareable) {
-               uint32_t backup_handle;
-
-               ret = vmw_gem_object_create_with_handle(dev_priv,
-                                                       file_priv,
-                                                       res->guest_memory_size,
-                                                       &backup_handle,
-                                                       &res->guest_memory_bo);
+               struct vmw_bo_params params = {
+                       .domain = VMW_BO_DOMAIN_SYS,
+                       .busy_domain = VMW_BO_DOMAIN_SYS,
+                       .bo_type = ttm_bo_type_device,
+                       .size = res->guest_memory_size,
+                       .pin = false
+               };
+
+               ret = vmw_gem_object_create(dev_priv,
+                                           &params,
+                                           &res->guest_memory_bo);
                if (unlikely(ret != 0)) {
                        vmw_resource_unreference(&res);
                        goto out_unlock;
                }
-               vmw_bo_reference(res->guest_memory_bo);
-               /*
-                * We don't expose the handle to the userspace and surface
-                * already holds a gem reference
-                */
-               drm_gem_handle_delete(file_priv, backup_handle);
        }
 
        tmp = vmw_resource_reference(&srf->res);
@@ -1512,7 +1507,7 @@ vmw_gb_surface_define_internal(struct drm_device *dev,
                if (ret == 0) {
                        if (res->guest_memory_bo->tbo.base.size < res->guest_memory_size) {
                                VMW_DEBUG_USER("Surface backup buffer too small.\n");
-                               vmw_bo_unreference(&res->guest_memory_bo);
+                               vmw_user_bo_unref(&res->guest_memory_bo);
                                ret = -EINVAL;
                                goto out_unlock;
                        } else {
@@ -1526,8 +1521,6 @@ vmw_gb_surface_define_internal(struct drm_device *dev,
                                                        res->guest_memory_size,
                                                        &backup_handle,
                                                        &res->guest_memory_bo);
-               if (ret == 0)
-                       vmw_bo_reference(res->guest_memory_bo);
        }
 
        if (unlikely(ret != 0)) {
index 0cea301cc9a902a18e11301a6a0b3450d44a30f2..790aa908e2a7880c33b63908d5aeea3f1ecfb659 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 403506b9697e75a3c2ac9042299bac8e1e2d342e..b346d68a06f5a992b4aab6fc1d8e02a40f89dd52 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 7e499992a79326069c5a58db5b969fca822df603..e4d2dfd5d2536e0703cceec55c703193b6253647 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 0235cc1690a10993e0bfd0e525ff871223bb8044..c8b20d44b14724d9327b23bce09a586d473bfbf5 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 05f5b5f588a28818824830c17c28e171525f4a1b..a209d51bd2476b3421fb18dcf2485bda1ce09505 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 521b2ffb424490976097f0a6801afec00183501b..8db4ae05febc8f069528cb79095b44d97e83159b 100644 (file)
@@ -2144,6 +2144,10 @@ static const struct hid_device_id mt_devices[] = {
                        USB_DEVICE_ID_MTP_STM)},
 
        /* 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) },
index 250f5d2f888ab0f7c19296d96fa3a018a0163d21..10468f727e5bb07aababe273ce71876429aed49a 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 9a3576dbf4217437d132f2074feeeefb7846653b..c463e54decbce1476bb9e56980af2330fed6a4b9 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 dd942061fd7750217b57a1758ea561b6cb69cb8f..ebc0aa4e4345febb0240eba81b0f7b2424264df2 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 43d2cf7153d79e6412799ede4b55502b6880d5fd..b3edadf42d6d91066cd993a6b89b4bec8d3f6a0e 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 9601c0605fd9e6c1cfbd4a85754d3c45dc545da5..2735cd585af0df846d7430bac643cfd0ce81fc9b 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 55cb25038e632bcfa962612fcd89b974a9bb8554..710fda5f19e1c9dc2d87f6b2e13a045de7a2bd41 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 02a71244fc3b765d77efedcc56cbc876afdfc864..b5b81bd83bb1573d0434eeb2a6cdf54898e4f227 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 66dc5f97a009804f739a1baf0bfa043395b4ea6f..8311e1028ddb03096f207798f9226e29b4025efc 100644 (file)
@@ -610,7 +610,8 @@ static int tmc_etr_alloc_flat_buf(struct tmc_drvdata *drvdata,
 
        flat_buf->vaddr = dma_alloc_noncoherent(real_dev, etr_buf->size,
                                                &flat_buf->daddr,
-                                               DMA_FROM_DEVICE, GFP_KERNEL);
+                                               DMA_FROM_DEVICE,
+                                               GFP_KERNEL | __GFP_NOWARN);
        if (!flat_buf->vaddr) {
                kfree(flat_buf);
                return -ENOMEM;
@@ -1173,16 +1174,6 @@ static struct etr_buf *tmc_etr_get_sysfs_buffer(struct coresight_device *csdev)
                goto out;
        }
 
-       /*
-        * In sysFS mode we can have multiple writers per sink.  Since this
-        * sink is already enabled no memory is needed and the HW need not be
-        * touched, even if the buffer size has changed.
-        */
-       if (drvdata->mode == CS_MODE_SYSFS) {
-               atomic_inc(&csdev->refcnt);
-               goto out;
-       }
-
        /*
         * If we don't have a buffer or it doesn't match the requested size,
         * use the buffer allocated above. Otherwise reuse the existing buffer.
@@ -1204,7 +1195,7 @@ out:
 
 static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
 {
-       int ret;
+       int ret = 0;
        unsigned long flags;
        struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
        struct etr_buf *sysfs_buf = tmc_etr_get_sysfs_buffer(csdev);
@@ -1213,12 +1204,24 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
                return PTR_ERR(sysfs_buf);
 
        spin_lock_irqsave(&drvdata->spinlock, flags);
+
+       /*
+        * In sysFS mode we can have multiple writers per sink.  Since this
+        * sink is already enabled no memory is needed and the HW need not be
+        * touched, even if the buffer size has changed.
+        */
+       if (drvdata->mode == CS_MODE_SYSFS) {
+               atomic_inc(&csdev->refcnt);
+               goto out;
+       }
+
        ret = tmc_etr_enable_hw(drvdata, sysfs_buf);
        if (!ret) {
                drvdata->mode = CS_MODE_SYSFS;
                atomic_inc(&csdev->refcnt);
        }
 
+out:
        spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
        if (!ret)
index 5a416b39b8183628bb71890a847b1ed3d799e806..28e2a5fc45282df4e8b050efb9e1431752526d7d 100644 (file)
@@ -749,6 +749,8 @@ static void __aspeed_i2c_reg_slave(struct aspeed_i2c_bus *bus, u16 slave_addr)
        func_ctrl_reg_val = readl(bus->base + ASPEED_I2C_FUN_CTRL_REG);
        func_ctrl_reg_val |= ASPEED_I2CD_SLAVE_EN;
        writel(func_ctrl_reg_val, bus->base + ASPEED_I2C_FUN_CTRL_REG);
+
+       bus->slave_state = ASPEED_I2C_SLAVE_INACTIVE;
 }
 
 static int aspeed_i2c_reg_slave(struct i2c_client *client)
@@ -765,7 +767,6 @@ static int aspeed_i2c_reg_slave(struct i2c_client *client)
        __aspeed_i2c_reg_slave(bus, client->addr);
 
        bus->slave = client;
-       bus->slave_state = ASPEED_I2C_SLAVE_INACTIVE;
        spin_unlock_irqrestore(&bus->lock, flags);
 
        return 0;
index cdd8c67d91298681f5243f307fc77cd7a5536f15..affcfb243f0f52a5848a48016eac8e78ef709f7e 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 cf4f684f535664ff59275d604cdbbbe7dc60939c..a7f6f3eafad7dd72241f57a2a356219d36bfaf56 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 73ae064321331d9bd920299096698b1456944388..1d855258a45dc3c68c71280cb791f77383f38457 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 495a8b5f6a2ba31c430a89d37c252a780d6ceb50..ae4bae63ad4f3c3086635928acdd9b46deb10c28 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 579b30581725f29fe69d0e2d309896cd7070efb0..0d3c9a041b5611361b489dc70ff866fcc0b28f67 100644 (file)
@@ -1059,9 +1059,10 @@ static int stm32f7_i2c_smbus_xfer_msg(struct stm32f7_i2c_dev *i2c_dev,
        /* Configure PEC */
        if ((flags & I2C_CLIENT_PEC) && f7_msg->size != I2C_SMBUS_QUICK) {
                cr1 |= STM32F7_I2C_CR1_PECEN;
-               cr2 |= STM32F7_I2C_CR2_PECBYTE;
-               if (!f7_msg->read_write)
+               if (!f7_msg->read_write) {
+                       cr2 |= STM32F7_I2C_CR2_PECBYTE;
                        f7_msg->count++;
+               }
        } else {
                cr1 &= ~STM32F7_I2C_CR1_PECEN;
                cr2 &= ~STM32F7_I2C_CR2_PECBYTE;
@@ -1149,8 +1150,10 @@ static void stm32f7_i2c_smbus_rep_start(struct stm32f7_i2c_dev *i2c_dev)
        f7_msg->stop = true;
 
        /* Add one byte for PEC if needed */
-       if (cr1 & STM32F7_I2C_CR1_PECEN)
+       if (cr1 & STM32F7_I2C_CR1_PECEN) {
+               cr2 |= STM32F7_I2C_CR2_PECBYTE;
                f7_msg->count++;
+       }
 
        /* Set number of bytes to be transferred */
        cr2 &= ~(STM32F7_I2C_CR2_NBYTES_MASK);
index b3bb97762c859fcdc04c3b21491055d9f105ce4e..71391b590adaeba9d69044dd5b66afcfa8c32aea 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 313904be5f3bde25990ffb631c248e60aa94bb09..57ff09f18c371dd28cdbe989d144f546e24ec8a3 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 a3a122fae71e09853200069e668b326e139eb90f..9f2e4aa28159338f2613a784fe5c539cf3152a6f 100644 (file)
@@ -61,7 +61,7 @@ static int i2c_demux_activate_master(struct i2c_demux_pinctrl_priv *priv, u32 ne
        if (ret)
                goto err;
 
-       adap = of_find_i2c_adapter_by_node(priv->chan[new_chan].parent_np);
+       adap = of_get_i2c_adapter_by_node(priv->chan[new_chan].parent_np);
        if (!adap) {
                ret = -ENODEV;
                goto err_with_revert;
@@ -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 5d5cbe0130cdf99de1917d5c013b8894c622a727..5ca03bd34c8d115190327c5d8e35d3b09d554ef9 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 baccf4bfaf0284be021aeb744d84e1cfaefa8cea..8305661e12539b6bfff279f3165eb5d216d6a55a 100644 (file)
@@ -52,7 +52,7 @@ static struct i2c_adapter *mux_parent_adapter(struct device *dev)
                dev_err(dev, "Cannot parse i2c-parent\n");
                return ERR_PTR(-ENODEV);
        }
-       parent = of_find_i2c_adapter_by_node(parent_np);
+       parent = of_get_i2c_adapter_by_node(parent_np);
        of_node_put(parent_np);
        if (!parent)
                return ERR_PTR(-EPROBE_DEFER);
index 18236b9fa14a9558dfb08bf656da442090d4611f..6ebca7bfd8a2652ec5e7bf1abef21a35992d38ac 100644 (file)
@@ -62,7 +62,7 @@ static struct i2c_adapter *i2c_mux_pinctrl_parent_adapter(struct device *dev)
                dev_err(dev, "Cannot parse i2c-parent\n");
                return ERR_PTR(-ENODEV);
        }
-       parent = of_find_i2c_adapter_by_node(parent_np);
+       parent = of_get_i2c_adapter_by_node(parent_np);
        of_node_put(parent_np);
        if (!parent)
                return ERR_PTR(-EPROBE_DEFER);
index 69d1103b95087d6f0741184890a66ae6f9e50cf1..b64fd365f83fb8656b2a798b59d7429b63a6f5e4 100644 (file)
@@ -177,6 +177,7 @@ struct ad7192_chip_info {
 struct ad7192_state {
        const struct ad7192_chip_info   *chip_info;
        struct regulator                *avdd;
+       struct regulator                *vref;
        struct clk                      *mclk;
        u16                             int_vref_mv;
        u32                             fclk;
@@ -1008,10 +1009,30 @@ static int ad7192_probe(struct spi_device *spi)
        if (ret)
                return dev_err_probe(&spi->dev, ret, "Failed to enable specified DVdd supply\n");
 
-       ret = regulator_get_voltage(st->avdd);
-       if (ret < 0) {
-               dev_err(&spi->dev, "Device tree error, reference voltage undefined\n");
-               return ret;
+       st->vref = devm_regulator_get_optional(&spi->dev, "vref");
+       if (IS_ERR(st->vref)) {
+               if (PTR_ERR(st->vref) != -ENODEV)
+                       return PTR_ERR(st->vref);
+
+               ret = regulator_get_voltage(st->avdd);
+               if (ret < 0)
+                       return dev_err_probe(&spi->dev, ret,
+                                            "Device tree error, AVdd voltage undefined\n");
+       } else {
+               ret = regulator_enable(st->vref);
+               if (ret) {
+                       dev_err(&spi->dev, "Failed to enable specified Vref supply\n");
+                       return ret;
+               }
+
+               ret = devm_add_action_or_reset(&spi->dev, ad7192_reg_disable, st->vref);
+               if (ret)
+                       return ret;
+
+               ret = regulator_get_voltage(st->vref);
+               if (ret < 0)
+                       return dev_err_probe(&spi->dev, ret,
+                                            "Device tree error, Vref voltage undefined\n");
        }
        st->int_vref_mv = ret / 1000;
 
index cff1ba57fb16a7f6a29d77eb759f1a4e522febff..43c8af41b4a9d8939eceef8a47131de4805747fe 100644 (file)
@@ -826,16 +826,26 @@ static int exynos_adc_probe(struct platform_device *pdev)
                }
        }
 
+       /* leave out any TS related code if unreachable */
+       if (IS_REACHABLE(CONFIG_INPUT)) {
+               has_ts = of_property_read_bool(pdev->dev.of_node,
+                                              "has-touchscreen") || pdata;
+       }
+
        irq = platform_get_irq(pdev, 0);
        if (irq < 0)
                return irq;
        info->irq = irq;
 
-       irq = platform_get_irq(pdev, 1);
-       if (irq == -EPROBE_DEFER)
-               return irq;
+       if (has_ts) {
+               irq = platform_get_irq(pdev, 1);
+               if (irq == -EPROBE_DEFER)
+                       return irq;
 
-       info->tsirq = irq;
+               info->tsirq = irq;
+       } else {
+               info->tsirq = -1;
+       }
 
        info->dev = &pdev->dev;
 
@@ -900,12 +910,6 @@ static int exynos_adc_probe(struct platform_device *pdev)
        if (info->data->init_hw)
                info->data->init_hw(info);
 
-       /* leave out any TS related code if unreachable */
-       if (IS_REACHABLE(CONFIG_INPUT)) {
-               has_ts = of_property_read_bool(pdev->dev.of_node,
-                                              "has-touchscreen") || pdata;
-       }
-
        if (pdata)
                info->delay = pdata->delay;
        else
index f5a0fc9e64c542acb4742a5abfb4458685657150..fff6e5a2d956992587a69b35201399763573123e 100644 (file)
@@ -38,8 +38,8 @@
 #define IMX8QXP_ADR_ADC_FCTRL          0x30
 #define IMX8QXP_ADR_ADC_SWTRIG         0x34
 #define IMX8QXP_ADR_ADC_TCTRL(tid)     (0xc0 + (tid) * 4)
-#define IMX8QXP_ADR_ADC_CMDH(cid)      (0x100 + (cid) * 8)
-#define IMX8QXP_ADR_ADC_CMDL(cid)      (0x104 + (cid) * 8)
+#define IMX8QXP_ADR_ADC_CMDL(cid)      (0x100 + (cid) * 8)
+#define IMX8QXP_ADR_ADC_CMDH(cid)      (0x104 + (cid) * 8)
 #define IMX8QXP_ADR_ADC_RESFIFO                0x300
 #define IMX8QXP_ADR_ADC_TST            0xffc
 
index dba73300f89482ba5dc285ddc93c29ab353feff3..564c0cad0fc7973d6f830bf1e154d0849d4bc4a8 100644 (file)
@@ -456,6 +456,9 @@ static const struct xadc_ops xadc_zynq_ops = {
        .interrupt_handler = xadc_zynq_interrupt_handler,
        .update_alarm = xadc_zynq_update_alarm,
        .type = XADC_TYPE_S7,
+       /* Temp in C = (val * 503.975) / 2**bits - 273.15 */
+       .temp_scale = 503975,
+       .temp_offset = 273150,
 };
 
 static const unsigned int xadc_axi_reg_offsets[] = {
@@ -566,6 +569,9 @@ static const struct xadc_ops xadc_7s_axi_ops = {
        .interrupt_handler = xadc_axi_interrupt_handler,
        .flags = XADC_FLAGS_BUFFERED | XADC_FLAGS_IRQ_OPTIONAL,
        .type = XADC_TYPE_S7,
+       /* Temp in C = (val * 503.975) / 2**bits - 273.15 */
+       .temp_scale = 503975,
+       .temp_offset = 273150,
 };
 
 static const struct xadc_ops xadc_us_axi_ops = {
@@ -577,6 +583,12 @@ static const struct xadc_ops xadc_us_axi_ops = {
        .interrupt_handler = xadc_axi_interrupt_handler,
        .flags = XADC_FLAGS_BUFFERED | XADC_FLAGS_IRQ_OPTIONAL,
        .type = XADC_TYPE_US,
+       /**
+        * Values below are for UltraScale+ (SYSMONE4) using internal reference.
+        * See https://docs.xilinx.com/v/u/en-US/ug580-ultrascale-sysmon
+        */
+       .temp_scale = 509314,
+       .temp_offset = 280231,
 };
 
 static int _xadc_update_adc_reg(struct xadc *xadc, unsigned int reg,
@@ -945,8 +957,7 @@ static int xadc_read_raw(struct iio_dev *indio_dev,
                        *val2 = bits;
                        return IIO_VAL_FRACTIONAL_LOG2;
                case IIO_TEMP:
-                       /* Temp in C = (val * 503.975) / 2**bits - 273.15 */
-                       *val = 503975;
+                       *val = xadc->ops->temp_scale;
                        *val2 = bits;
                        return IIO_VAL_FRACTIONAL_LOG2;
                default:
@@ -954,7 +965,7 @@ static int xadc_read_raw(struct iio_dev *indio_dev,
                }
        case IIO_CHAN_INFO_OFFSET:
                /* Only the temperature channel has an offset */
-               *val = -((273150 << bits) / 503975);
+               *val = -((xadc->ops->temp_offset << bits) / xadc->ops->temp_scale);
                return IIO_VAL_INT;
        case IIO_CHAN_INFO_SAMP_FREQ:
                ret = xadc_read_samplerate(xadc);
@@ -1423,28 +1434,6 @@ static int xadc_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
-       /* Disable all alarms */
-       ret = xadc_update_adc_reg(xadc, XADC_REG_CONF1, XADC_CONF1_ALARM_MASK,
-                                 XADC_CONF1_ALARM_MASK);
-       if (ret)
-               return ret;
-
-       /* Set thresholds to min/max */
-       for (i = 0; i < 16; i++) {
-               /*
-                * Set max voltage threshold and both temperature thresholds to
-                * 0xffff, min voltage threshold to 0.
-                */
-               if (i % 8 < 4 || i == 7)
-                       xadc->threshold[i] = 0xffff;
-               else
-                       xadc->threshold[i] = 0;
-               ret = xadc_write_adc_reg(xadc, XADC_REG_THRESHOLD(i),
-                       xadc->threshold[i]);
-               if (ret)
-                       return ret;
-       }
-
        /* Go to non-buffered mode */
        xadc_postdisable(indio_dev);
 
index 7d78ce6989671a19ae3cb1aae957e84625b1684d..3036f4d613ff5d44018c098781576d3f71fd5b49 100644 (file)
@@ -85,6 +85,8 @@ struct xadc_ops {
 
        unsigned int flags;
        enum xadc_type type;
+       int temp_scale;
+       int temp_offset;
 };
 
 static inline int _xadc_read_adc_reg(struct xadc *xadc, unsigned int reg,
index 877f9124803c9c437749e31879cafba374e7b4bc..397544f23b85067c6b7d401e22c49424b321f0c2 100644 (file)
@@ -24,6 +24,8 @@ config AD74413R
        depends on GPIOLIB && SPI
        select REGMAP_SPI
        select CRC8
+       select IIO_BUFFER
+       select IIO_TRIGGERED_BUFFER
        help
          Say yes here to build support for Analog Devices AD74412R/AD74413R
          quad-channel software configurable input/output solution.
index 1f280c360701bc333fad01c4c07d3e34a914ea32..56e5913ab82d1c045c9ca27012008a4495502cbf 100644 (file)
@@ -214,8 +214,18 @@ static int rescale_read_raw(struct iio_dev *indio_dev,
                                return ret < 0 ? ret : -EOPNOTSUPP;
                }
 
-               ret = iio_read_channel_scale(rescale->source, &scale, &scale2);
-               return rescale_process_offset(rescale, ret, scale, scale2,
+               if (iio_channel_has_info(rescale->source->channel,
+                                        IIO_CHAN_INFO_SCALE)) {
+                       ret = iio_read_channel_scale(rescale->source, &scale, &scale2);
+                       return rescale_process_offset(rescale, ret, scale, scale2,
+                                                     schan_off, val, val2);
+               }
+
+               /*
+                * If we get here we have no scale so scale 1:1 but apply
+                * rescaler and offset, if any.
+                */
+               return rescale_process_offset(rescale, IIO_VAL_FRACTIONAL, 1, 1,
                                              schan_off, val, val2);
        default:
                return -EINVAL;
@@ -280,8 +290,9 @@ static int rescale_configure_channel(struct device *dev,
        chan->type = rescale->cfg->type;
 
        if (iio_channel_has_info(schan, IIO_CHAN_INFO_RAW) &&
-           iio_channel_has_info(schan, IIO_CHAN_INFO_SCALE)) {
-               dev_info(dev, "using raw+scale source channel\n");
+           (iio_channel_has_info(schan, IIO_CHAN_INFO_SCALE) ||
+            iio_channel_has_info(schan, IIO_CHAN_INFO_OFFSET))) {
+               dev_info(dev, "using raw+scale/offset source channel\n");
        } else if (iio_channel_has_info(schan, IIO_CHAN_INFO_PROCESSED)) {
                dev_info(dev, "using processed channel\n");
                rescale->chan_processed = true;
index b72d39fc2434e44071cae83ae9b33e027c40eae1..6bfe5d6847e75469ccc69a2940548e9c90b77b17 100644 (file)
@@ -190,8 +190,11 @@ int cros_ec_sensors_push_data(struct iio_dev *indio_dev,
        /*
         * Ignore samples if the buffer is not set: it is needed if the ODR is
         * set but the buffer is not enabled yet.
+        *
+        * Note: iio_device_claim_buffer_mode() returns -EBUSY if the buffer
+        * is not enabled.
         */
-       if (!iio_buffer_enabled(indio_dev))
+       if (iio_device_claim_buffer_mode(indio_dev) < 0)
                return 0;
 
        out = (s16 *)st->samples;
@@ -210,6 +213,7 @@ int cros_ec_sensors_push_data(struct iio_dev *indio_dev,
        iio_push_to_buffers_with_timestamp(indio_dev, st->samples,
                                           timestamp + delta);
 
+       iio_device_release_buffer_mode(indio_dev);
        return 0;
 }
 EXPORT_SYMBOL_GPL(cros_ec_sensors_push_data);
index d5ea1a1be1226bf57c231bc9a8f3634d005028f6..a492e8f2fc0fbcc711b504c251342aebf772c8a9 100644 (file)
@@ -140,8 +140,8 @@ enum ad3552r_ch_vref_select {
 };
 
 enum ad3542r_id {
-       AD3542R_ID = 0x4008,
-       AD3552R_ID = 0x4009,
+       AD3542R_ID = 0x4009,
+       AD3552R_ID = 0x4008,
 };
 
 enum ad3552r_ch_output_range {
index 6355c1f2842317ec2fef1806f563556771ad7522..92923074f93024f02d2093b6562a9de36ac44878 100644 (file)
@@ -351,9 +351,9 @@ static int admv1013_update_mixer_vgate(struct admv1013_state *st)
        if (vcm < 0)
                return vcm;
 
-       if (vcm < 1800000)
+       if (vcm <= 1800000)
                mixer_vgate = (2389 * vcm / 1000000 + 8100) / 100;
-       else if (vcm > 1800000 && vcm < 2600000)
+       else if (vcm > 1800000 && vcm <= 2600000)
                mixer_vgate = (2375 * vcm / 1000000 + 125) / 100;
        else
                return -EINVAL;
index fa79b1ac4f85b7879f7202d9787eb9253a4a2b90..83e53acfbe88011f4306f19438b6f31d4cad5b22 100644 (file)
@@ -2,6 +2,8 @@
 
 config BOSCH_BNO055
        tristate
+       select IIO_BUFFER
+       select IIO_TRIGGERED_BUFFER
 
 config BOSCH_BNO055_SERIAL
        tristate "Bosch BNO055 attached via UART"
index 3a52b09c282313f4b6e27e56908a6f8829ca9932..fdf763a04b0bfac2fef3eb50a1f1d85df995122e 100644 (file)
@@ -1513,7 +1513,6 @@ static int vcnl4040_write_event_config(struct iio_dev *indio_dev,
 
 out:
        mutex_unlock(&data->vcnl4000_lock);
-       data->chip_spec->set_power_state(data, data->ps_int || data->als_int);
 
        return ret;
 }
index 6089f3f9d8f4b8c547a2e4f526de4c3dd2d950f5..a2ef1373a274e27bb323eb9e4a4bf3291e73334b 100644 (file)
@@ -2179,7 +2179,7 @@ int bmp280_common_probe(struct device *dev,
         * however as it happens, the BMP085 shares the chip ID of BMP180
         * so we look for an IRQ if we have that.
         */
-       if (irq > 0 || (chip_id  == BMP180_CHIP_ID)) {
+       if (irq > 0 && (chip_id  == BMP180_CHIP_ID)) {
                ret = bmp085_fetch_eoc_irq(dev, name, irq, data);
                if (ret)
                        return ret;
index b10dbf5cf494091a60d281178a7785653b6d2eb1..1ff091b2f764d4b926d70ab1c35722e2deafe301 100644 (file)
@@ -57,8 +57,8 @@
 #define  DPS310_RESET_MAGIC    0x09
 #define DPS310_COEF_BASE       0x10
 
-/* Make sure sleep time is <= 20ms for usleep_range */
-#define DPS310_POLL_SLEEP_US(t)                min(20000, (t) / 8)
+/* Make sure sleep time is <= 30ms for usleep_range */
+#define DPS310_POLL_SLEEP_US(t)                min(30000, (t) / 8)
 /* Silently handle error in rate value here */
 #define DPS310_POLL_TIMEOUT_US(rc)     ((rc) <= 0 ? 1000000 : 1000000 / (rc))
 
@@ -402,8 +402,8 @@ static int dps310_reset_wait(struct dps310_data *data)
        if (rc)
                return rc;
 
-       /* Wait for device chip access: 2.5ms in specification */
-       usleep_range(2500, 12000);
+       /* Wait for device chip access: 15ms in specification */
+       usleep_range(15000, 55000);
        return 0;
 }
 
index 627497e61a63507066c527381730eb6283734e12..2fc706f9d8ae7d1db059f9c60483b71946a16f4e 100644 (file)
@@ -76,7 +76,7 @@ static bool ms5611_prom_is_valid(u16 *prom, size_t len)
 
        crc = (crc >> 12) & 0x000F;
 
-       return crc_orig != 0x0000 && crc == crc_orig;
+       return crc == crc_orig;
 }
 
 static int ms5611_read_prom(struct iio_dev *indio_dev)
index 5bd791b46d98d227b2dbfcfba2ba23dbaf7ddf86..bdff91f6b1a3731178605a9b1c84c43d33d23ecb 100644 (file)
@@ -759,14 +759,14 @@ static irqreturn_t irsd200_trigger_handler(int irq, void *pollf)
 {
        struct iio_dev *indio_dev = ((struct iio_poll_func *)pollf)->indio_dev;
        struct irsd200_data *data = iio_priv(indio_dev);
-       s16 buf = 0;
+       s64 buf[2] = {};
        int ret;
 
-       ret = irsd200_read_data(data, &buf);
+       ret = irsd200_read_data(data, (s16 *)buf);
        if (ret)
                goto end;
 
-       iio_push_to_buffers_with_timestamp(indio_dev, &buf,
+       iio_push_to_buffers_with_timestamp(indio_dev, buf,
                                           iio_get_time_ns(indio_dev));
 
 end:
index c343edf2f664015be0e94cdde3979ea0ce1aa841..1e2cd7c8716e810da7de504199cabb30545948c2 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 7b68b3ea979f79dfd682062fa9f89f797742fdd9..f2fb2d8a65970a3c8fe6c7cfe42fd0b3e2a6bf93 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 d5d3e4f0de779ef1e82f06482287b3de355323e1..6d1dbc97875906a8c5589b807eccf0fcf772add9 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 bf800f8cb3e4bb63abb63c6df54eb655ccde4b9d..495d5a5d0373f1e91db030de98bded5af8d44884 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 0848c2c2ffcf2e86a1979e66f0958e5b0eedf604..faa88d12ee8681788ab44b6f4861a2f6e170bcf9 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 c8c4017fe4059eb3b3dc01341b6773468a26d4fe..e47b4ca64d33ef274355215056da15a35360afc7 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 ced615b5ea096ed58d4198ceaf8b960428d98ecd..040ba2224f9ff67e508f5ecd443c96f8cb8f645c 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 dcccb60152323efda17f1d470400a1e3cc1e18ea..c317947563fbc650d7eb2070f3f0131ca8871660 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 24ee79aa2122ed628fcf6b86c1d52bc071bd4a02..88f534cf690e928bc8d8224bcb280538a2adcd41 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 1e419e080b5352bbcdf3c7faa4277cca97f6e3ce..520034acf73aac388ae7f66851fb990ea6adec72 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 aed5cdea50e6c08f35691320a3a50b6fff173973..555629b798b956949fe6c622517986529aa73faa 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 3e345ef380f17cd52ae955c48bd6176eb2169735..8a3762d9ff58c1550f3d2b429a47949079a089df 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 a2605178f4edaac5410fd4078fb8870b60236a42..43e776073f49f59d7a1753763c97f3842d68b164 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 1574218764e0a748441cf73b4cfc9716b0bbfa2d..2916e77f589b813c6f9f0608f4081c719463cfe0 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 ede380551e55ca9f5fe1f9dab02fe9b50c2403e6..f5c21565bb3cece5ceef091317d17bc455e4d758 100644 (file)
@@ -130,6 +130,7 @@ static const struct xpad_device {
        { 0x0079, 0x18d4, "GPD Win 2 X-Box Controller", 0, XTYPE_XBOX360 },
        { 0x03eb, 0xff01, "Wooting One (Legacy)", 0, XTYPE_XBOX360 },
        { 0x03eb, 0xff02, "Wooting Two (Legacy)", 0, XTYPE_XBOX360 },
+       { 0x03f0, 0x0495, "HyperX Clutch Gladiate", 0, XTYPE_XBOXONE },
        { 0x044f, 0x0f00, "Thrustmaster Wheel", 0, XTYPE_XBOX },
        { 0x044f, 0x0f03, "Thrustmaster Wheel", 0, XTYPE_XBOX },
        { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX },
@@ -272,6 +273,7 @@ static const struct xpad_device {
        { 0x1038, 0x1430, "SteelSeries Stratus Duo", 0, XTYPE_XBOX360 },
        { 0x1038, 0x1431, "SteelSeries Stratus Duo", 0, XTYPE_XBOX360 },
        { 0x11c9, 0x55f0, "Nacon GC-100XF", 0, XTYPE_XBOX360 },
+       { 0x11ff, 0x0511, "PXN V900", 0, XTYPE_XBOX360 },
        { 0x1209, 0x2882, "Ardwiino Controller", 0, XTYPE_XBOX360 },
        { 0x12ab, 0x0004, "Honey Bee Xbox360 dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
        { 0x12ab, 0x0301, "PDP AFTERGLOW AX.1", 0, XTYPE_XBOX360 },
@@ -459,6 +461,7 @@ static const struct usb_device_id xpad_table[] = {
        { USB_INTERFACE_INFO('X', 'B', 0) },    /* Xbox USB-IF not-approved class */
        XPAD_XBOX360_VENDOR(0x0079),            /* GPD Win 2 controller */
        XPAD_XBOX360_VENDOR(0x03eb),            /* Wooting Keyboards (Legacy) */
+       XPAD_XBOXONE_VENDOR(0x03f0),            /* HP HyperX Xbox One controllers */
        XPAD_XBOX360_VENDOR(0x044f),            /* Thrustmaster Xbox 360 controllers */
        XPAD_XBOX360_VENDOR(0x045e),            /* Microsoft Xbox 360 controllers */
        XPAD_XBOXONE_VENDOR(0x045e),            /* Microsoft Xbox One controllers */
@@ -477,6 +480,7 @@ static const struct usb_device_id xpad_table[] = {
        XPAD_XBOX360_VENDOR(0x1038),            /* SteelSeries controllers */
        XPAD_XBOXONE_VENDOR(0x10f5),            /* Turtle Beach Controllers */
        XPAD_XBOX360_VENDOR(0x11c9),            /* Nacon GC100XF */
+       XPAD_XBOX360_VENDOR(0x11ff),            /* PXN V900 */
        XPAD_XBOX360_VENDOR(0x1209),            /* Ardwiino Controllers */
        XPAD_XBOX360_VENDOR(0x12ab),            /* Xbox 360 dance pads */
        XPAD_XBOX360_VENDOR(0x1430),            /* RedOctane Xbox 360 controllers */
index c1c733a9cb8908d9564c74cd98e6f0db7be2a7c8..db2ba89adaefa624f47e7ad7e24d366e411d6d36 100644 (file)
@@ -425,6 +425,7 @@ static void powermate_disconnect(struct usb_interface *intf)
                pm->requires_update = 0;
                usb_kill_urb(pm->irq);
                input_unregister_device(pm->input);
+               usb_kill_urb(pm->config);
                usb_free_urb(pm->irq);
                usb_free_urb(pm->config);
                powermate_free_buffers(interface_to_usbdev(intf), pm);
index 2118b2075f437c2bfda8d3ec68b97ff831c3d74a..4e38229404b4b001e7caceced16c43023773e0d1 100644 (file)
@@ -2114,6 +2114,7 @@ static int elantech_setup_ps2(struct psmouse *psmouse,
        psmouse->protocol_handler = elantech_process_byte;
        psmouse->disconnect = elantech_disconnect;
        psmouse->reconnect = elantech_reconnect;
+       psmouse->fast_reconnect = NULL;
        psmouse->pktsize = info->hw_version > 1 ? 6 : 4;
 
        return 0;
index 7b13de9799089fcea428738cb3f59fb9939b5abb..2a2459b1b4f2cb91b0465f77637f22a0b71bcf62 100644 (file)
@@ -5,7 +5,6 @@
 
 #define pr_fmt(fmt)            KBUILD_MODNAME ": " fmt
 
-#include <linux/delay.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/libps2.h>
@@ -119,18 +118,13 @@ static psmouse_ret_t psmouse_smbus_process_byte(struct psmouse *psmouse)
        return PSMOUSE_FULL_PACKET;
 }
 
-static void psmouse_activate_smbus_mode(struct psmouse_smbus_dev *smbdev)
-{
-       if (smbdev->need_deactivate) {
-               psmouse_deactivate(smbdev->psmouse);
-               /* Give the device time to switch into SMBus mode */
-               msleep(30);
-       }
-}
-
 static int psmouse_smbus_reconnect(struct psmouse *psmouse)
 {
-       psmouse_activate_smbus_mode(psmouse->private);
+       struct psmouse_smbus_dev *smbdev = psmouse->private;
+
+       if (smbdev->need_deactivate)
+               psmouse_deactivate(psmouse);
+
        return 0;
 }
 
@@ -263,7 +257,8 @@ int psmouse_smbus_init(struct psmouse *psmouse,
                }
        }
 
-       psmouse_activate_smbus_mode(smbdev);
+       if (need_deactivate)
+               psmouse_deactivate(psmouse);
 
        psmouse->private = smbdev;
        psmouse->protocol_handler = psmouse_smbus_process_byte;
index ada299ec5bba55ae03a004bf8ebccf10249e58ae..22d16d80efb938b5ae9576d5bb064900af343499 100644 (file)
@@ -1623,6 +1623,7 @@ static int synaptics_init_ps2(struct psmouse *psmouse,
        psmouse->set_rate = synaptics_set_rate;
        psmouse->disconnect = synaptics_disconnect;
        psmouse->reconnect = synaptics_reconnect;
+       psmouse->fast_reconnect = NULL;
        psmouse->cleanup = synaptics_reset;
        /* Synaptics can usually stay in sync without extra help */
        psmouse->resync_time = 0;
@@ -1752,6 +1753,7 @@ static int synaptics_create_intertouch(struct psmouse *psmouse,
                psmouse_matches_pnp_id(psmouse, topbuttonpad_pnp_ids) &&
                !SYN_CAP_EXT_BUTTONS_STICK(info->ext_cap_10);
        const struct rmi_device_platform_data pdata = {
+               .reset_delay_ms = 30,
                .sensor_pdata = {
                        .sensor_type = rmi_sensor_touchpad,
                        .axis_align.flip_y = true,
index 7059a2762aebc1f2a4b09908f214d04e6ab54ee8..b0b099b5528a8b78fbe60b0db9a79b2751a74edb 100644 (file)
@@ -235,12 +235,29 @@ static void rmi_smb_clear_state(struct rmi_smb_xport *rmi_smb)
 
 static int rmi_smb_enable_smbus_mode(struct rmi_smb_xport *rmi_smb)
 {
-       int retval;
+       struct i2c_client *client = rmi_smb->client;
+       int smbus_version;
+
+       /*
+        * psmouse driver resets the controller, we only need to wait
+        * to give the firmware chance to fully reinitialize.
+        */
+       if (rmi_smb->xport.pdata.reset_delay_ms)
+               msleep(rmi_smb->xport.pdata.reset_delay_ms);
 
        /* we need to get the smbus version to activate the touchpad */
-       retval = rmi_smb_get_version(rmi_smb);
-       if (retval < 0)
-               return retval;
+       smbus_version = rmi_smb_get_version(rmi_smb);
+       if (smbus_version < 0)
+               return smbus_version;
+
+       rmi_dbg(RMI_DEBUG_XPORT, &client->dev, "Smbus version is %d",
+               smbus_version);
+
+       if (smbus_version != 2 && smbus_version != 3) {
+               dev_err(&client->dev, "Unrecognized SMB version %d\n",
+                               smbus_version);
+               return -ENODEV;
+       }
 
        return 0;
 }
@@ -253,11 +270,10 @@ static int rmi_smb_reset(struct rmi_transport_dev *xport, u16 reset_addr)
        rmi_smb_clear_state(rmi_smb);
 
        /*
-        * we do not call the actual reset command, it has to be handled in
-        * PS/2 or there will be races between PS/2 and SMBus.
-        * PS/2 should ensure that a psmouse_reset is called before
-        * intializing the device and after it has been removed to be in a known
-        * state.
+        * We do not call the actual reset command, it has to be handled in
+        * PS/2 or there will be races between PS/2 and SMBus. PS/2 should
+        * ensure that a psmouse_reset is called before initializing the
+        * device and after it has been removed to be in a known state.
         */
        return rmi_smb_enable_smbus_mode(rmi_smb);
 }
@@ -272,7 +288,6 @@ static int rmi_smb_probe(struct i2c_client *client)
 {
        struct rmi_device_platform_data *pdata = dev_get_platdata(&client->dev);
        struct rmi_smb_xport *rmi_smb;
-       int smbus_version;
        int error;
 
        if (!pdata) {
@@ -311,18 +326,9 @@ static int rmi_smb_probe(struct i2c_client *client)
        rmi_smb->xport.proto_name = "smb";
        rmi_smb->xport.ops = &rmi_smb_ops;
 
-       smbus_version = rmi_smb_get_version(rmi_smb);
-       if (smbus_version < 0)
-               return smbus_version;
-
-       rmi_dbg(RMI_DEBUG_XPORT, &client->dev, "Smbus version is %d",
-               smbus_version);
-
-       if (smbus_version != 2 && smbus_version != 3) {
-               dev_err(&client->dev, "Unrecognized SMB version %d\n",
-                               smbus_version);
-               return -ENODEV;
-       }
+       error = rmi_smb_enable_smbus_mode(rmi_smb);
+       if (error)
+               return error;
 
        i2c_set_clientdata(client, rmi_smb);
 
index 1724d6cb8649d6094a84ec91e9e09211e0307e21..9c39553d30fa27e1cebb6e05e233c56c3c8d5bee 100644 (file)
@@ -618,6 +618,14 @@ static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = {
                },
                .driver_data = (void *)(SERIO_QUIRK_NOMUX)
        },
+       {
+               /* Fujitsu Lifebook E5411 */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU CLIENT COMPUTING LIMITED"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E5411"),
+               },
+               .driver_data = (void *)(SERIO_QUIRK_NOAUX)
+       },
        {
                /* Gigabyte M912 */
                .matches = {
index da9954d6df44c19b45032ba862e13acfee267832..af32fbe57b630373f6fd8b67e3129be1d54de1d1 100644 (file)
@@ -900,6 +900,25 @@ static int goodix_add_acpi_gpio_mappings(struct goodix_ts_data *ts)
                dev_info(dev, "No ACPI GpioInt resource, assuming that the GPIO order is reset, int\n");
                ts->irq_pin_access_method = IRQ_PIN_ACCESS_ACPI_GPIO;
                gpio_mapping = acpi_goodix_int_last_gpios;
+       } else if (ts->gpio_count == 1 && ts->gpio_int_idx == 0) {
+               /*
+                * On newer devices there is only 1 GpioInt resource and _PS0
+                * does the whole reset sequence for us.
+                */
+               acpi_device_fix_up_power(ACPI_COMPANION(dev));
+
+               /*
+                * Before the _PS0 call the int GPIO may have been in output
+                * mode and the call should have put the int GPIO in input mode,
+                * but the GPIO subsys cached state may still think it is
+                * in output mode, causing gpiochip_lock_as_irq() failure.
+                *
+                * Add a mapping for the int GPIO to make the
+                * gpiod_int = gpiod_get(..., GPIOD_IN) call succeed,
+                * which will explicitly set the direction to input.
+                */
+               ts->irq_pin_access_method = IRQ_PIN_ACCESS_NONE;
+               gpio_mapping = acpi_goodix_int_first_gpios;
        } else {
                dev_warn(dev, "Unexpected ACPI resources: gpio_count %d, gpio_int_idx %d\n",
                         ts->gpio_count, ts->gpio_int_idx);
index 2082081402d324abe99dc4c02b43866367ca4fa0..0b89275084274659fb91f8dbd2567693bdf963dd 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 4d83edc2be994d470daf102fc5b98234368c9404..8a16cd3ef487cad4d63e8ebfae6f775b7bef3825 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 e82bf1c449a35dd300738f9b6b457dc9d3e3bca8..bd0a596f9863a32eb11316822d424ec6349de0ef 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 5db283c17e0dc5cd7ffd0147efec316595df53c8..3685ba90ec88e81baac849f1693f507e005f4a21 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 c18fb699c87ac5faabf40c84eafba8fb28f8ad9d..7dac94f62b4ec661af7030b475103ef4ac184fee 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 3bfc56df4f781cbb15f6cad090681f8327b8dde4..c146378c7d032c3805f46e6db24a6a9e47e4a264 100644 (file)
@@ -1108,7 +1108,8 @@ map_end:
 
        }
 
-       iommu_flush_iotlb_all(domain);
+       if (!list_empty(&mappings) && iommu_is_dma_domain(domain))
+               iommu_flush_iotlb_all(domain);
 
 out:
        iommu_put_resv_regions(dev, &mappings);
index 640275873a271ec7806083df05003f7fe5237754..fab6c347ce578ec7c79131a9ceeaab3f41b0aafe 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 3db4592cda1c01ad8a27e73f62b9d0890019667d..f407cce9ecaaae3e1ef4e0265784336845648f8b 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 e0c2b10d154d64586ac887102c988826f0fa3874..a8c89df1a997866c31238d94bb5cd26c5acf8dcb 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
        {
@@ -4808,6 +4812,11 @@ static const struct gic_quirk its_quirks[] = {
                .init   = its_enable_rk3588001,
        },
 #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,11 +5112,6 @@ 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)
@@ -5174,7 +5156,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 +5173,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 +5335,55 @@ 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->get_msi_base = its_irq_get_msi_base;
+       its->msi_domain_flags = IRQ_DOMAIN_FLAG_ISOLATED_MSI;
+
+       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 eedfa8e9f0772c6f55e44520a4be443b689ca7f1..f59ac9586b7b1d2240ea66aec29a4e0dde676919 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",
@@ -1923,6 +1931,11 @@ static const struct gic_quirk gic_quirks[] = {
                .mask   = 0xff0f0fff,
                .init   = gic_enable_quirk_arm64_2941627,
        },
+       {
+               .desc   = "GICv3: non-coherent attribute",
+               .property = "dma-noncoherent",
+               .init   = rd_set_non_coherent,
+       },
        {
        }
 };
index 4bbfa2b0a4df9b83e0fd40942eed805fd984b498..96f4e322ed6b727cb9a4d732b28ed309e21e04f6 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 4adeee1bc391fb17aed9a3097a0bb70665ecc166..e8d01b14ccdde7848c7fb14489a5a015b86e8e95 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 d8ba5fba7450a94f0c6dabebb186b8200fe0d866..971240e2e31b48ef284d06f406eb62e41ff7cc53 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 8c581c985aa7ddb0e9c96008807fb945eb1361ea..7f314e58f3ce56f10e3e9fc7ad4e266b25180231 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 a32c0d28d038467ac10c28cb7c00e4305bab720e..74b2f124116e3415d77269959c1ed5e7d7efd671 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 1efd17979f240e9000cd219dbc9d72a99ff64c7a..b82b89888a5e042aee79f222b2ce2fcfdd36a092 100644 (file)
@@ -678,7 +678,7 @@ ph_state(struct dchannel *dch)
 }
 
 /*
- * disable/enable BChannel for desired protocoll
+ * disable/enable BChannel for desired protocol
  */
 static int
 hfcsusb_setup_bch(struct bchannel *bch, int protocol)
index 04f9ea675f2cef6a7653aef2573fd56083640736..214ed81eb0e926cf8be1502395186c7d2bf6f0c1 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 978fdfc19a06ae68827d55367b7f74184eee43eb..0cac5bead84fa3bc8680000342bea01dba4a1b7b 100644 (file)
@@ -387,17 +387,13 @@ EXPORT_SYMBOL_NS_GPL(mcb_free_dev, MCB);
 
 static int __mcb_bus_add_devices(struct device *dev, void *data)
 {
-       struct mcb_device *mdev = to_mcb_device(dev);
        int retval;
 
-       if (mdev->is_added)
-               return 0;
-
        retval = device_attach(dev);
-       if (retval < 0)
+       if (retval < 0) {
                dev_err(dev, "Error adding device (%d)\n", retval);
-
-       mdev->is_added = true;
+               return retval;
+       }
 
        return 0;
 }
index 2aef990f379f77001e374fb466460c1f234de6fe..656b6b71c76823cab55bc7a10cce0a6024adac25 100644 (file)
@@ -99,8 +99,6 @@ static int chameleon_parse_gdd(struct mcb_bus *bus,
        mdev->mem.end = mdev->mem.start + size - 1;
        mdev->mem.flags = IORESOURCE_MEM;
 
-       mdev->is_added = false;
-
        ret = mcb_device_register(bus, mdev);
        if (ret < 0)
                goto err;
index f2662c21a6dfe7ac1c6db10fa21ef94b45dee2ac..5315fd261c23b7f084b4b049b374e9b8941bc7eb 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 ad8e670a2f9be8c12697ad92bb25f60a2e046c46..b487f7acc860f77eda051fb7a7f6495ed8e7040e 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 4cb9c608ee1919ac543e93da6e86f4a1dca940d3..284cd71bcc685b7dd4a44d4cd1d009684b57b5cd 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 0f430ddc1f6704e96dd42357eaf77f03be19793f..fd87747be9b177c07c25048a62fbbded363fab5e 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 a1136fdfbed2d4b16f858dae07d5fa1db620b2b1..ec53abe2e84e53ef2e24a9760f10f94836340f67 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 20e7c7cf5eeb953d60babada315c2e020acf7d37..be84ff1e2b170562226404ded0c33f3064a1cad5 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 3af6125a2eee8130417c1ee00ec7d8367d62300f..4d9fd76e2f60f3fd219f14752c714fcce29087be 100644 (file)
@@ -1850,9 +1850,9 @@ static int ov8858_parse_of(struct ov8858 *ov8858)
        }
 
        ret = v4l2_fwnode_endpoint_parse(endpoint, &vep);
+       fwnode_handle_put(endpoint);
        if (ret) {
                dev_err(dev, "Failed to parse endpoint: %d\n", ret);
-               fwnode_handle_put(endpoint);
                return ret;
        }
 
@@ -1864,12 +1864,9 @@ static int ov8858_parse_of(struct ov8858 *ov8858)
        default:
                dev_err(dev, "Unsupported number of data lanes %u\n",
                        ov8858->num_lanes);
-               fwnode_handle_put(endpoint);
                return -EINVAL;
        }
 
-       ov8858->subdev.fwnode = endpoint;
-
        return 0;
 }
 
@@ -1913,7 +1910,7 @@ static int ov8858_probe(struct i2c_client *client)
 
        ret = ov8858_init_ctrls(ov8858);
        if (ret)
-               goto err_put_fwnode;
+               return ret;
 
        sd = &ov8858->subdev;
        sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
@@ -1964,8 +1961,6 @@ err_clean_entity:
        media_entity_cleanup(&sd->entity);
 err_free_handler:
        v4l2_ctrl_handler_free(&ov8858->ctrl_handler);
-err_put_fwnode:
-       fwnode_handle_put(ov8858->subdev.fwnode);
 
        return ret;
 }
@@ -1978,7 +1973,6 @@ static void ov8858_remove(struct i2c_client *client)
        v4l2_async_unregister_subdev(sd);
        media_entity_cleanup(&sd->entity);
        v4l2_ctrl_handler_free(&ov8858->ctrl_handler);
-       fwnode_handle_put(ov8858->subdev.fwnode);
 
        pm_runtime_disable(&client->dev);
        if (!pm_runtime_status_suspended(&client->dev))
index a36a709243fdbd4390ee8d53cc20fa70d1d4fbfc..3e22df36354fdbd03e828d61d652903f854ff098 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 436baf6c8b089d43efac8b4eda44dd9c22620717..241a696e374a922b6f8aa058150e75c3e42a11b7 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 e113902fa8064221ce6589c4965fa727120e2e56..ee4684159d3de86bf7051a652ee63ecdc0dd3574 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 1bde8b6e0b1121a82f80af5e7f072f94628d5f72..e38198e259c03ce9444571d2a3902499492c6e45 100644 (file)
@@ -107,8 +107,10 @@ static struct acpi_device *ipu_bridge_get_ivsc_acpi_dev(struct acpi_device *adev
                for_each_acpi_dev_match(ivsc_adev, acpi_id->id, NULL, -1)
                        /* camera sensor depends on IVSC in DSDT if exist */
                        for_each_acpi_consumer_dev(ivsc_adev, consumer)
-                               if (consumer->handle == handle)
+                               if (consumer->handle == handle) {
+                                       acpi_dev_put(consumer);
                                        return ivsc_adev;
+                               }
        }
 
        return NULL;
index 0951545eab21a06b107331cd6d4b8768e557bb6f..c0a250daa9270ec59473f4d44a65ecc826f4f90b 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 1ef1c4e3750d7033ca753ef71f4c01be8817af11..a8cb981544f71f5cdc193b29e26f84ef3552bae0 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 6e6caf50e11ef8026b5788973ec734ed10ac19e4..59b89e421dc2892c0e02f88b8119af8898be86ed 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 ec1a16734a280dce566149664354b41bd34cad81..d6499ffe30e8b6a3f46ec3266de4c8d598cfdf82 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 d299cc2962a5ae0eb84e8115c3cf364789d1e4c6..ae6290d28f8e98eabfee667d60a73ea29c5ea60a 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 16f19a6401301e01e879af3baca3fb59672ac536..5f93712bf485408cb3a7d174b4ddb44b65250ff4 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 8926eb0803b27a0a333da2b9a6b58246092b4d5c..6e603c0382487862cf5a76e59b0dce8ed2c29896 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 4285770fde184ca3eccf4617bf18e273ae0fb1f2..996684a7303831fd463216eb89c702257458d938 100644 (file)
@@ -55,11 +55,18 @@ xvip_graph_find_entity(struct xvip_composite_device *xdev,
 {
        struct xvip_graph_entity *entity;
        struct v4l2_async_connection *asd;
-
-       list_for_each_entry(asd, &xdev->notifier.done_list, asc_entry) {
-               entity = to_xvip_entity(asd);
-               if (entity->asd.match.fwnode == fwnode)
-                       return entity;
+       struct list_head *lists[] = {
+               &xdev->notifier.done_list,
+               &xdev->notifier.waiting_list
+       };
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(lists); i++) {
+               list_for_each_entry(asd, lists[i], asc_entry) {
+                       entity = to_xvip_entity(asd);
+                       if (entity->asd.match.fwnode == fwnode)
+                               return entity;
+               }
        }
 
        return NULL;
index b3c472b8c5a960aa81cfced5d245436d4f99364e..cb61fd6cc6c617dc36ed8f305b02a851ee8fa76f 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 4ff79940ad8d46664b252dc75b2b3ab792eb65e0..b2a15d9fb1f33cc7d302f3f99b30fc6921007098 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 5e9d3da862dd86ac84634ef8664c69866557d990..e59a463c27618ebbce7618b754c56bb41be2db3b 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 b92348ad61f6408c725f99665a732a49c3d4e35c..31752c06d1f0c8bba6915f4e7bd9d5a4b75029c0 100644 (file)
@@ -502,6 +502,13 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg,
                                       V4L2_SUBDEV_CLIENT_CAP_STREAMS;
        int rval;
 
+       /*
+        * If the streams API is not enabled, remove V4L2_SUBDEV_CAP_STREAMS.
+        * Remove this when the API is no longer experimental.
+        */
+       if (!v4l2_subdev_enable_streams_api)
+               streams_subdev = false;
+
        switch (cmd) {
        case VIDIOC_SUBDEV_QUERYCAP: {
                struct v4l2_subdev_capability *cap = arg;
index aea95745c73f8541b3fd6c6c247a8c02bf2f0fec..90ce58fd629e5f32dd6cb207e60544b2718ee5c7 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 37b23e9bae823c1b3db4ac912d0b3632175b59a1..7b6d07cbe6fc6f32cb3c850806e1ef8b7257c9b4 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 3dae5e3a16976f0e229523544396e21670747cae..cd512284bfb399cf10af85592ca5e9af46416e94 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 f4ab09439da70c977ea29bbb63e1ae8d80a1f08f..0c7f10bcf6f1222d641b5edd52cfd11c769f314e 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 47ab72a43256bc2ce1aa6fd3ece81bc50b78ca6d..6c81040e18bef57a4e0d1ac3df75d242f928c56a 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 79b18f6f73a8a83cd6865721f60509a225b8df6e..d2d3a6ccb8f7ddeaba9454355891e1d7c833f4b9 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 94af6bf8a25a6f3c36bc3084f5cd95e7926a1fb5..67252512a1329724f2ec964377ecbd0a20885cf7 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 a3f4b52bb159f0c1287b692e7484815bddff8614..a30751ad373307701a24ba7808b19f4f5d775fad 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 a66b7c111cd51923540f32f86910f66332125c3f..1c6c62a7f7f5535f4c1025ee0d957006a4c5deb4 100644 (file)
@@ -958,6 +958,7 @@ static int fastrpc_get_args(u32 kernel, struct fastrpc_invoke_ctx *ctx)
        if (err)
                return err;
 
+       memset(ctx->buf->virt, 0, pkt_size);
        rpra = ctx->buf->virt;
        list = fastrpc_invoke_buf_start(rpra, ctx->nscalars);
        pages = fastrpc_phy_page_start(list, ctx->nscalars);
@@ -1090,6 +1091,7 @@ static int fastrpc_put_args(struct fastrpc_invoke_ctx *ctx,
                }
        }
 
+       /* Clean up fdlist which is updated by DSP */
        for (i = 0; i < FASTRPC_MAX_FDLIST; i++) {
                if (!fdlist[i])
                        break;
@@ -1156,11 +1158,9 @@ static int fastrpc_internal_invoke(struct fastrpc_user *fl,  u32 kernel,
        if (IS_ERR(ctx))
                return PTR_ERR(ctx);
 
-       if (ctx->nscalars) {
-               err = fastrpc_get_args(kernel, ctx);
-               if (err)
-                       goto bail;
-       }
+       err = fastrpc_get_args(kernel, ctx);
+       if (err)
+               goto bail;
 
        /* make sure that all CPU memory writes are seen by DSP */
        dma_wmb();
@@ -1176,6 +1176,13 @@ static int fastrpc_internal_invoke(struct fastrpc_user *fl,  u32 kernel,
                err = wait_for_completion_interruptible(&ctx->work);
        }
 
+       if (err)
+               goto bail;
+
+       /* make sure that all memory writes by DSP are seen by CPU */
+       dma_rmb();
+       /* populate all the output buffers with results */
+       err = fastrpc_put_args(ctx, kernel);
        if (err)
                goto bail;
 
@@ -1184,15 +1191,6 @@ static int fastrpc_internal_invoke(struct fastrpc_user *fl,  u32 kernel,
        if (err)
                goto bail;
 
-       if (ctx->nscalars) {
-               /* make sure that all memory writes by DSP are seen by CPU */
-               dma_rmb();
-               /* populate all the output buffers with results */
-               err = fastrpc_put_args(ctx, kernel);
-               if (err)
-                       goto bail;
-       }
-
 bail:
        if (err != -ERESTARTSYS && err != -ETIMEDOUT) {
                /* We are done with this compute context */
@@ -1983,11 +1981,13 @@ static int fastrpc_req_mem_unmap_impl(struct fastrpc_user *fl, struct fastrpc_me
        sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_MEM_UNMAP, 1, 0);
        err = fastrpc_internal_invoke(fl, true, FASTRPC_INIT_HANDLE, sc,
                                      &args[0]);
-       fastrpc_map_put(map);
-       if (err)
+       if (err) {
                dev_err(dev, "unmmap\tpt fd = %d, 0x%09llx error\n",  map->fd, map->raddr);
+               return err;
+       }
+       fastrpc_map_put(map);
 
-       return err;
+       return 0;
 }
 
 static int fastrpc_req_mem_unmap(struct fastrpc_user *fl, char __user *argp)
index b5b414a71e0bb73da7e087fd88430a64c74eb820..3a8f27c3e310a5cd7dea54cac77774166b561122 100644 (file)
@@ -179,6 +179,7 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
                               struct mmc_queue *mq);
 static void mmc_blk_hsq_req_done(struct mmc_request *mrq);
 static int mmc_spi_err_check(struct mmc_card *card);
+static int mmc_blk_busy_cb(void *cb_data, bool *busy);
 
 static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
 {
@@ -470,7 +471,7 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
        struct mmc_data data = {};
        struct mmc_request mrq = {};
        struct scatterlist sg;
-       bool r1b_resp, use_r1b_resp = false;
+       bool r1b_resp;
        unsigned int busy_timeout_ms;
        int err;
        unsigned int target_part;
@@ -551,8 +552,7 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
        busy_timeout_ms = idata->ic.cmd_timeout_ms ? : MMC_BLK_TIMEOUT_MS;
        r1b_resp = (cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B;
        if (r1b_resp)
-               use_r1b_resp = mmc_prepare_busy_cmd(card->host, &cmd,
-                                                   busy_timeout_ms);
+               mmc_prepare_busy_cmd(card->host, &cmd, busy_timeout_ms);
 
        mmc_wait_for_req(card->host, &mrq);
        memcpy(&idata->ic.response, cmd.resp, sizeof(cmd.resp));
@@ -605,19 +605,28 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
        if (idata->ic.postsleep_min_us)
                usleep_range(idata->ic.postsleep_min_us, idata->ic.postsleep_max_us);
 
-       /* No need to poll when using HW busy detection. */
-       if ((card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp)
-               return 0;
-
        if (mmc_host_is_spi(card->host)) {
                if (idata->ic.write_flag || r1b_resp || cmd.flags & MMC_RSP_SPI_BUSY)
                        return mmc_spi_err_check(card);
                return err;
        }
-       /* Ensure RPMB/R1B command has completed by polling with CMD13. */
-       if (idata->rpmb || r1b_resp)
-               err = mmc_poll_for_busy(card, busy_timeout_ms, false,
-                                       MMC_BUSY_IO);
+
+       /*
+        * Ensure RPMB, writes and R1B responses are completed by polling with
+        * CMD13. Note that, usually we don't need to poll when using HW busy
+        * detection, but here it's needed since some commands may indicate the
+        * error through the R1 status bits.
+        */
+       if (idata->rpmb || idata->ic.write_flag || r1b_resp) {
+               struct mmc_blk_busy_data cb_data = {
+                       .card = card,
+               };
+
+               err = __mmc_poll_for_busy(card->host, 0, busy_timeout_ms,
+                                         &mmc_blk_busy_cb, &cb_data);
+
+               idata->ic.response[0] = cb_data.status;
+       }
 
        return err;
 }
index 89cd48fcec79f2aea73f61a951b907722abd78e7..4a4bab9aa7263e1c8638449576f08e07e0911d37 100644 (file)
@@ -104,7 +104,7 @@ static int mmc_decode_cid(struct mmc_card *card)
        case 3: /* MMC v3.1 - v3.3 */
        case 4: /* MMC v4 */
                card->cid.manfid        = UNSTUFF_BITS(resp, 120, 8);
-               card->cid.oemid         = UNSTUFF_BITS(resp, 104, 16);
+               card->cid.oemid         = UNSTUFF_BITS(resp, 104, 8);
                card->cid.prod_name[0]  = UNSTUFF_BITS(resp, 96, 8);
                card->cid.prod_name[1]  = UNSTUFF_BITS(resp, 88, 8);
                card->cid.prod_name[2]  = UNSTUFF_BITS(resp, 80, 8);
index f64b9ac76a5cdb66fc6ba7c7b1374b2734b17154..5914516df2f7fd93b90c31e287f4448d74f856fa 100644 (file)
@@ -1089,8 +1089,14 @@ static int mmc_sdio_resume(struct mmc_host *host)
                }
                err = mmc_sdio_reinit_card(host);
        } else if (mmc_card_wake_sdio_irq(host)) {
-               /* We may have switched to 1-bit mode during suspend */
+               /*
+                * We may have switched to 1-bit mode during suspend,
+                * need to hold retuning, because tuning only supprt
+                * 4-bit mode or 8 bit mode.
+                */
+               mmc_retune_hold_now(host);
                err = sdio_enable_4bit_bus(host->card);
+               mmc_retune_release(host);
        }
 
        if (err)
index 5392200cfdf7a1230e4c0e2fb19736c74c7176b4..97f7c3d4be6ea910e615bab2bf08ad1e4a5fb726 100644 (file)
@@ -669,11 +669,11 @@ static void msdc_reset_hw(struct msdc_host *host)
        u32 val;
 
        sdr_set_bits(host->base + MSDC_CFG, MSDC_CFG_RST);
-       readl_poll_timeout(host->base + MSDC_CFG, val, !(val & MSDC_CFG_RST), 0, 0);
+       readl_poll_timeout_atomic(host->base + MSDC_CFG, val, !(val & MSDC_CFG_RST), 0, 0);
 
        sdr_set_bits(host->base + MSDC_FIFOCS, MSDC_FIFOCS_CLR);
-       readl_poll_timeout(host->base + MSDC_FIFOCS, val,
-                          !(val & MSDC_FIFOCS_CLR), 0, 0);
+       readl_poll_timeout_atomic(host->base + MSDC_FIFOCS, val,
+                                 !(val & MSDC_FIFOCS_CLR), 0, 0);
 
        val = readl(host->base + MSDC_INT);
        writel(val, host->base + MSDC_INT);
index ae8c307b7aa7b7f0781a246674d0646b3a5b973e..109d4b010f9786d2847f144210b57de732460ea4 100644 (file)
@@ -1144,42 +1144,6 @@ static u32 sdhci_gl9750_readl(struct sdhci_host *host, int reg)
        return value;
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int sdhci_pci_gli_resume(struct sdhci_pci_chip *chip)
-{
-       struct sdhci_pci_slot *slot = chip->slots[0];
-
-       pci_free_irq_vectors(slot->chip->pdev);
-       gli_pcie_enable_msi(slot);
-
-       return sdhci_pci_resume_host(chip);
-}
-
-static int sdhci_cqhci_gli_resume(struct sdhci_pci_chip *chip)
-{
-       struct sdhci_pci_slot *slot = chip->slots[0];
-       int ret;
-
-       ret = sdhci_pci_gli_resume(chip);
-       if (ret)
-               return ret;
-
-       return cqhci_resume(slot->host->mmc);
-}
-
-static int sdhci_cqhci_gli_suspend(struct sdhci_pci_chip *chip)
-{
-       struct sdhci_pci_slot *slot = chip->slots[0];
-       int ret;
-
-       ret = cqhci_suspend(slot->host->mmc);
-       if (ret)
-               return ret;
-
-       return sdhci_suspend_host(slot->host);
-}
-#endif
-
 static void gl9763e_hs400_enhanced_strobe(struct mmc_host *mmc,
                                          struct mmc_ios *ios)
 {
@@ -1420,6 +1384,70 @@ static int gl9763e_runtime_resume(struct sdhci_pci_chip *chip)
 }
 #endif
 
+#ifdef CONFIG_PM_SLEEP
+static int sdhci_pci_gli_resume(struct sdhci_pci_chip *chip)
+{
+       struct sdhci_pci_slot *slot = chip->slots[0];
+
+       pci_free_irq_vectors(slot->chip->pdev);
+       gli_pcie_enable_msi(slot);
+
+       return sdhci_pci_resume_host(chip);
+}
+
+static int gl9763e_resume(struct sdhci_pci_chip *chip)
+{
+       struct sdhci_pci_slot *slot = chip->slots[0];
+       int ret;
+
+       ret = sdhci_pci_gli_resume(chip);
+       if (ret)
+               return ret;
+
+       ret = cqhci_resume(slot->host->mmc);
+       if (ret)
+               return ret;
+
+       /*
+        * Disable LPM negotiation to bring device back in sync
+        * with its runtime_pm state.
+        */
+       gl9763e_set_low_power_negotiation(slot, false);
+
+       return 0;
+}
+
+static int gl9763e_suspend(struct sdhci_pci_chip *chip)
+{
+       struct sdhci_pci_slot *slot = chip->slots[0];
+       int ret;
+
+       /*
+        * Certain SoCs can suspend only with the bus in low-
+        * power state, notably x86 SoCs when using S0ix.
+        * Re-enable LPM negotiation to allow entering L1 state
+        * and entering system suspend.
+        */
+       gl9763e_set_low_power_negotiation(slot, true);
+
+       ret = cqhci_suspend(slot->host->mmc);
+       if (ret)
+               goto err_suspend;
+
+       ret = sdhci_suspend_host(slot->host);
+       if (ret)
+               goto err_suspend_host;
+
+       return 0;
+
+err_suspend_host:
+       cqhci_resume(slot->host->mmc);
+err_suspend:
+       gl9763e_set_low_power_negotiation(slot, false);
+       return ret;
+}
+#endif
+
 static int gli_probe_slot_gl9763e(struct sdhci_pci_slot *slot)
 {
        struct pci_dev *pdev = slot->chip->pdev;
@@ -1527,8 +1555,8 @@ const struct sdhci_pci_fixes sdhci_gl9763e = {
        .probe_slot     = gli_probe_slot_gl9763e,
        .ops            = &sdhci_gl9763e_ops,
 #ifdef CONFIG_PM_SLEEP
-       .resume         = sdhci_cqhci_gli_resume,
-       .suspend        = sdhci_cqhci_gli_suspend,
+       .resume         = gl9763e_resume,
+       .suspend        = gl9763e_suspend,
 #endif
 #ifdef CONFIG_PM
        .runtime_suspend = gl9763e_runtime_suspend,
index 649ae075e229990679a81369a6fba4b04a85f352..6b84ba27e6ab0d83f5b20154c376c0e38af3c7a4 100644 (file)
@@ -644,6 +644,7 @@ static int sdhci_sprd_tuning(struct mmc_host *mmc, struct mmc_card *card,
        best_clk_sample = sdhci_sprd_get_best_clk_sample(mmc, value);
        if (best_clk_sample < 0) {
                dev_err(mmc_dev(host->mmc), "all tuning phase fail!\n");
+               err = best_clk_sample;
                goto out;
        }
 
index 78710fbc8e7f638cdd52b08286b7a6b1bfbffa71..fc872133928247de91cb810122c8fa805e569c4b 100644 (file)
@@ -551,6 +551,17 @@ static int physmap_flash_probe(struct platform_device *dev)
                if (info->probe_type) {
                        info->mtds[i] = do_map_probe(info->probe_type,
                                                     &info->maps[i]);
+
+                       /* Fall back to mapping region as ROM */
+                       if (!info->mtds[i] && IS_ENABLED(CONFIG_MTD_ROM) &&
+                           strcmp(info->probe_type, "map_rom")) {
+                               dev_warn(&dev->dev,
+                                        "map_probe() failed for type %s\n",
+                                        info->probe_type);
+
+                               info->mtds[i] = do_map_probe("map_rom",
+                                                            &info->maps[i]);
+                       }
                } else {
                        int j;
 
index 4621ec549cc79e21d2f7a0281c874917c06c25a8..a492051c46f5968cd4b0564a2eb125250ee36fc4 100644 (file)
@@ -515,6 +515,7 @@ static int anfc_write_page_hw_ecc(struct nand_chip *chip, const u8 *buf,
        struct mtd_info *mtd = nand_to_mtd(chip);
        unsigned int len = mtd->writesize + (oob_required ? mtd->oobsize : 0);
        dma_addr_t dma_addr;
+       u8 status;
        int ret;
        struct anfc_op nfc_op = {
                .pkt_reg =
@@ -561,10 +562,21 @@ static int anfc_write_page_hw_ecc(struct nand_chip *chip, const u8 *buf,
        }
 
        /* Spare data is not protected */
-       if (oob_required)
+       if (oob_required) {
                ret = nand_write_oob_std(chip, page);
+               if (ret)
+                       return ret;
+       }
 
-       return ret;
+       /* Check write status on the chip side */
+       ret = nand_status_op(chip, &status);
+       if (ret)
+               return ret;
+
+       if (status & NAND_STATUS_FAIL)
+               return -EIO;
+
+       return 0;
 }
 
 static int anfc_sel_write_page_hw_ecc(struct nand_chip *chip, const u8 *buf,
index 2c94da7a3b3a45928b67e2978f45458c68f922d9..b841a81cb12822d2fba717faf50e25f0f23d9350 100644 (file)
@@ -1165,6 +1165,7 @@ static int marvell_nfc_hw_ecc_hmg_do_write_page(struct nand_chip *chip,
                .ndcb[2] = NDCB2_ADDR5_PAGE(page),
        };
        unsigned int oob_bytes = lt->spare_bytes + (raw ? lt->ecc_bytes : 0);
+       u8 status;
        int ret;
 
        /* NFCv2 needs more information about the operation being executed */
@@ -1198,7 +1199,18 @@ static int marvell_nfc_hw_ecc_hmg_do_write_page(struct nand_chip *chip,
 
        ret = marvell_nfc_wait_op(chip,
                                  PSEC_TO_MSEC(sdr->tPROG_max));
-       return ret;
+       if (ret)
+               return ret;
+
+       /* Check write status on the chip side */
+       ret = nand_status_op(chip, &status);
+       if (ret)
+               return ret;
+
+       if (status & NAND_STATUS_FAIL)
+               return -EIO;
+
+       return 0;
 }
 
 static int marvell_nfc_hw_ecc_hmg_write_page_raw(struct nand_chip *chip,
@@ -1627,6 +1639,7 @@ static int marvell_nfc_hw_ecc_bch_write_page(struct nand_chip *chip,
        int data_len = lt->data_bytes;
        int spare_len = lt->spare_bytes;
        int chunk, ret;
+       u8 status;
 
        marvell_nfc_select_target(chip, chip->cur_cs);
 
@@ -1663,6 +1676,14 @@ static int marvell_nfc_hw_ecc_bch_write_page(struct nand_chip *chip,
        if (ret)
                return ret;
 
+       /* Check write status on the chip side */
+       ret = nand_status_op(chip, &status);
+       if (ret)
+               return ret;
+
+       if (status & NAND_STATUS_FAIL)
+               return -EIO;
+
        return 0;
 }
 
index d4b55155aeae90e8d32917917b56026c758cb5de..1fcac403cee60f70348014f41d0cea32f6fcf5b3 100644 (file)
@@ -5110,6 +5110,9 @@ static void rawnand_check_cont_read_support(struct nand_chip *chip)
 {
        struct mtd_info *mtd = nand_to_mtd(chip);
 
+       if (!chip->parameters.supports_read_cache)
+               return;
+
        if (chip->read_retries)
                return;
 
index 836757717660b92612253c1e4244c80cbe35ba57..b3cc8f360529169cd65daf38faf4be1835036745 100644 (file)
@@ -94,6 +94,9 @@ int nand_jedec_detect(struct nand_chip *chip)
                goto free_jedec_param_page;
        }
 
+       if (p->opt_cmd[0] & JEDEC_OPT_CMD_READ_CACHE)
+               chip->parameters.supports_read_cache = true;
+
        memorg->pagesize = le32_to_cpu(p->byte_per_page);
        mtd->writesize = memorg->pagesize;
 
index f15ef90aec8cd6d76f3c4da5d078d1c5ddfd1fdc..861975e44b552db0acad7e299cf15af410070602 100644 (file)
@@ -303,6 +303,9 @@ int nand_onfi_detect(struct nand_chip *chip)
                           ONFI_FEATURE_ADDR_TIMING_MODE, 1);
        }
 
+       if (le16_to_cpu(p->opt_cmd) & ONFI_OPT_CMD_READ_CACHE)
+               chip->parameters.supports_read_cache = true;
+
        onfi = kzalloc(sizeof(*onfi), GFP_KERNEL);
        if (!onfi) {
                ret = -ENOMEM;
index 8da5fee321b57110da7fbc696dea6f5c0d256d71..c506e92a3e457d857d54e68cc4b9ccc728097250 100644 (file)
@@ -511,6 +511,7 @@ static int pl35x_nand_write_page_hwecc(struct nand_chip *chip,
        u32 addr1 = 0, addr2 = 0, row;
        u32 cmd_addr;
        int i, ret;
+       u8 status;
 
        ret = pl35x_smc_set_ecc_mode(nfc, chip, PL35X_SMC_ECC_CFG_MODE_APB);
        if (ret)
@@ -563,6 +564,14 @@ static int pl35x_nand_write_page_hwecc(struct nand_chip *chip,
        if (ret)
                goto disable_ecc_engine;
 
+       /* Check write status on the chip side */
+       ret = nand_status_op(chip, &status);
+       if (ret)
+               goto disable_ecc_engine;
+
+       if (status & NAND_STATUS_FAIL)
+               ret = -EIO;
+
 disable_ecc_engine:
        pl35x_smc_set_ecc_mode(nfc, chip, PL35X_SMC_ECC_CFG_MODE_BYPASS);
 
index 64499c1b36032c476ce6db4bd3b78ffca53e7f74..b079605c84d38204971834ea2c26d2858165b506 100644 (file)
@@ -3444,7 +3444,7 @@ err_nandc_alloc:
 err_aon_clk:
        clk_disable_unprepare(nandc->core_clk);
 err_core_clk:
-       dma_unmap_resource(dev, res->start, resource_size(res),
+       dma_unmap_resource(dev, nandc->base_dma, resource_size(res),
                           DMA_BIDIRECTIONAL, 0);
        return ret;
 }
index 50b7295bc92226cabcd96eeb5515416f0b8a9f79..12601bc4227a729575eb9fb28adf9992d7961b3c 100644 (file)
@@ -12,7 +12,7 @@
 
 #define SPINAND_MFR_MICRON             0x2c
 
-#define MICRON_STATUS_ECC_MASK         GENMASK(7, 4)
+#define MICRON_STATUS_ECC_MASK         GENMASK(6, 4)
 #define MICRON_STATUS_ECC_NO_BITFLIPS  (0 << 4)
 #define MICRON_STATUS_ECC_1TO3_BITFLIPS        (1 << 4)
 #define MICRON_STATUS_ECC_4TO6_BITFLIPS        (3 << 4)
index 8b91a55ec0d28827d57fbfb42d405402f738ab71..8ee51e49fced559d3a5e561956103cb53d6fcf50 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 ed7212e61c541b20b4f07d98faa76b6e2ebc300e..51d47eda1c873debda6da094377bcb3367a78f6e 100644 (file)
@@ -4023,7 +4023,7 @@ static inline const void *bond_pull_data(struct sk_buff *skb,
        if (likely(n <= hlen))
                return data;
        else if (skb && likely(pskb_may_pull(skb, n)))
-               return skb->head;
+               return skb->data;
 
        return NULL;
 }
index 649453a3c8588b775ea18d0584252c46b2ce6000..f8cde9f9f554d5a0f7d0c48c81aef7793d9555fd 100644 (file)
@@ -190,7 +190,7 @@ config CAN_SLCAN
 
 config CAN_SUN4I
        tristate "Allwinner A10 CAN controller"
-       depends on MACH_SUN4I || MACH_SUN7I || RISCV || COMPILE_TEST
+       depends on MACH_SUN4I || MACH_SUN7I || (RISCV && ARCH_SUNXI) || COMPILE_TEST
        help
          Say Y here if you want to use CAN controller found on Allwinner
          A10/A20/D1 SoCs.
index add39e922b890b0606eef45abb8988f180d7384e..d15f85a40c1e5be5b703fbe9d27c104564f54f58 100644 (file)
@@ -348,7 +348,7 @@ static struct flexcan_devtype_data fsl_imx8mp_devtype_data = {
 static struct flexcan_devtype_data fsl_imx93_devtype_data = {
        .quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS |
                FLEXCAN_QUIRK_DISABLE_MECR | FLEXCAN_QUIRK_USE_RX_MAILBOX |
-               FLEXCAN_QUIRK_BROKEN_PERR_STATE | FLEXCAN_QUIRK_AUTO_STOP_MODE |
+               FLEXCAN_QUIRK_BROKEN_PERR_STATE | FLEXCAN_QUIRK_SETUP_STOP_MODE_GPR |
                FLEXCAN_QUIRK_SUPPORT_FD | FLEXCAN_QUIRK_SUPPORT_ECC |
                FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX |
                FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX_RTR,
@@ -544,11 +544,6 @@ static inline int flexcan_enter_stop_mode(struct flexcan_priv *priv)
        } else if (priv->devtype_data.quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE_GPR) {
                regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr,
                                   1 << priv->stm.req_bit, 1 << priv->stm.req_bit);
-       } else if (priv->devtype_data.quirks & FLEXCAN_QUIRK_AUTO_STOP_MODE) {
-               /* For the auto stop mode, software do nothing, hardware will cover
-                * all the operation automatically after system go into low power mode.
-                */
-               return 0;
        }
 
        return flexcan_low_power_enter_ack(priv);
@@ -574,12 +569,6 @@ static inline int flexcan_exit_stop_mode(struct flexcan_priv *priv)
        reg_mcr &= ~FLEXCAN_MCR_SLF_WAK;
        priv->write(reg_mcr, &regs->mcr);
 
-       /* For the auto stop mode, hardware will exist stop mode
-        * automatically after system go out of low power mode.
-        */
-       if (priv->devtype_data.quirks & FLEXCAN_QUIRK_AUTO_STOP_MODE)
-               return 0;
-
        return flexcan_low_power_exit_ack(priv);
 }
 
@@ -1994,13 +1983,18 @@ static int flexcan_setup_stop_mode(struct platform_device *pdev)
                ret = flexcan_setup_stop_mode_scfw(pdev);
        else if (priv->devtype_data.quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE_GPR)
                ret = flexcan_setup_stop_mode_gpr(pdev);
-       else if (priv->devtype_data.quirks & FLEXCAN_QUIRK_AUTO_STOP_MODE)
-               ret = 0;
        else
                /* return 0 directly if doesn't support stop mode feature */
                return 0;
 
-       if (ret)
+       /* If ret is -EINVAL, this means SoC claim to support stop mode, but
+        * dts file lack the stop mode property definition. For this case,
+        * directly return 0, this will skip the wakeup capable setting and
+        * will not block the driver probe.
+        */
+       if (ret == -EINVAL)
+               return 0;
+       else if (ret)
                return ret;
 
        device_set_wakeup_capable(&pdev->dev, true);
@@ -2320,16 +2314,8 @@ static int __maybe_unused flexcan_noirq_suspend(struct device *device)
        if (netif_running(dev)) {
                int err;
 
-               if (device_may_wakeup(device)) {
+               if (device_may_wakeup(device))
                        flexcan_enable_wakeup_irq(priv, true);
-                       /* For auto stop mode, need to keep the clock on before
-                        * system go into low power mode. After system go into
-                        * low power mode, hardware will config the flexcan into
-                        * stop mode, and gate off the clock automatically.
-                        */
-                       if (priv->devtype_data.quirks & FLEXCAN_QUIRK_AUTO_STOP_MODE)
-                               return 0;
-               }
 
                err = pm_runtime_force_suspend(device);
                if (err)
@@ -2347,15 +2333,9 @@ static int __maybe_unused flexcan_noirq_resume(struct device *device)
        if (netif_running(dev)) {
                int err;
 
-               /* For the wakeup in auto stop mode, no need to gate on the
-                * clock here, hardware will do this automatically.
-                */
-               if (!(device_may_wakeup(device) &&
-                     priv->devtype_data.quirks & FLEXCAN_QUIRK_AUTO_STOP_MODE)) {
-                       err = pm_runtime_force_resume(device);
-                       if (err)
-                               return err;
-               }
+               err = pm_runtime_force_resume(device);
+               if (err)
+                       return err;
 
                if (device_may_wakeup(device))
                        flexcan_enable_wakeup_irq(priv, false);
index 91402977780b20d27c8b8795de632b69f8a08a52..025c3417031f42b6b3865081b7407d3e4bc02af5 100644 (file)
@@ -68,8 +68,6 @@
 #define FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX_RTR BIT(15)
 /* Device supports RX via FIFO */
 #define FLEXCAN_QUIRK_SUPPORT_RX_FIFO BIT(16)
-/* auto enter stop mode to support wakeup */
-#define FLEXCAN_QUIRK_AUTO_STOP_MODE BIT(17)
 
 struct flexcan_devtype_data {
        u32 quirks;             /* quirks needed for different IP cores */
index 8a4143809d337c2147ebc0408c8b8bd8f8bee204..ae8c42f5debd4dee37d60ee8224a2ce4572e76b4 100644 (file)
@@ -125,7 +125,7 @@ static const struct tcan4x5x_version_info tcan4x5x_versions[] = {
        },
        [TCAN4553] = {
                .name = "4553",
-               .id2_register = 0x32353534,
+               .id2_register = 0x33353534,
        },
        /* generic version with no id2_register at the end */
        [TCAN4X5X] = {
index 0ada0e160e93605828db9d6e879c51e65c0e6f32..743c2eb62b877d6f48035981504d6a9556614769 100644 (file)
@@ -392,7 +392,13 @@ static irqreturn_t sja1000_reset_interrupt(int irq, void *dev_id)
        struct net_device *dev = (struct net_device *)dev_id;
 
        netdev_dbg(dev, "performing a soft reset upon overrun\n");
-       sja1000_start(dev);
+
+       netif_tx_lock(dev);
+
+       can_free_echo_skb(dev, 0, NULL);
+       sja1000_set_mode(dev, CAN_MODE_START);
+
+       netif_tx_unlock(dev);
 
        return IRQ_HANDLED;
 }
index 72374b066f64a902f0a7428daf34e79bb77521f9..cd1f240c90f3964efbb245c3494ddaaa82d394bb 100644 (file)
@@ -617,17 +617,16 @@ static int bcm_sf2_mdio_register(struct dsa_switch *ds)
        dn = of_find_compatible_node(NULL, NULL, "brcm,unimac-mdio");
        priv->master_mii_bus = of_mdio_find_bus(dn);
        if (!priv->master_mii_bus) {
-               of_node_put(dn);
-               return -EPROBE_DEFER;
+               err = -EPROBE_DEFER;
+               goto err_of_node_put;
        }
 
-       get_device(&priv->master_mii_bus->dev);
        priv->master_mii_dn = dn;
 
        priv->slave_mii_bus = mdiobus_alloc();
        if (!priv->slave_mii_bus) {
-               of_node_put(dn);
-               return -ENOMEM;
+               err = -ENOMEM;
+               goto err_put_master_mii_bus_dev;
        }
 
        priv->slave_mii_bus->priv = priv;
@@ -684,11 +683,17 @@ static int bcm_sf2_mdio_register(struct dsa_switch *ds)
        }
 
        err = mdiobus_register(priv->slave_mii_bus);
-       if (err && dn) {
-               mdiobus_free(priv->slave_mii_bus);
-               of_node_put(dn);
-       }
+       if (err && dn)
+               goto err_free_slave_mii_bus;
 
+       return 0;
+
+err_free_slave_mii_bus:
+       mdiobus_free(priv->slave_mii_bus);
+err_put_master_mii_bus_dev:
+       put_device(&priv->master_mii_bus->dev);
+err_of_node_put:
+       of_node_put(dn);
        return err;
 }
 
@@ -696,6 +701,7 @@ static void bcm_sf2_mdio_unregister(struct bcm_sf2_priv *priv)
 {
        mdiobus_unregister(priv->slave_mii_bus);
        mdiobus_free(priv->slave_mii_bus);
+       put_device(&priv->master_mii_bus->dev);
        of_node_put(priv->master_mii_dn);
 }
 
index 52a99d8bada076620312683ddeaf0f44e62db1fc..ab434a77b059a5adda955e319900b80a19298851 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 2fa55a6435910fd5d9a9c42dd28b93285b2181ba..174c773b38c2bd252c3107174886a497b3fab71e 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 c99ddd117fe6e13fa00ea29e8fe91534608794d5..1095261f5b490a8bc708f3d7a513ca633ae0080c 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 937a01f2ba75ebe0e89e419da93a0b937352cb68..b2b5f6ba438f46f2e8b39625a08e5eaae2d63d03 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 7e091965582b75254b3dd6b0fed781a77f637d75..d9434f7cae538bb887271f144f0414ae8027becc 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 de1dc22cf68317e4ce1c1364c1d08aad6804d565..4ce68e655a632d6b1630d948f02b97dbfc86208f 100644 (file)
@@ -505,8 +505,8 @@ qca8k_bulk_read(void *ctx, const void *reg_buf, size_t reg_len,
                void *val_buf, size_t val_len)
 {
        int i, count = val_len / sizeof(u32), ret;
-       u32 reg = *(u32 *)reg_buf & U16_MAX;
        struct qca8k_priv *priv = ctx;
+       u32 reg = *(u16 *)reg_buf;
 
        if (priv->mgmt_master &&
            !qca8k_read_eth(priv, reg, val_buf, val_len))
@@ -527,8 +527,8 @@ qca8k_bulk_gather_write(void *ctx, const void *reg_buf, size_t reg_len,
                        const void *val_buf, size_t val_len)
 {
        int i, count = val_len / sizeof(u32), ret;
-       u32 reg = *(u32 *)reg_buf & U16_MAX;
        struct qca8k_priv *priv = ctx;
+       u32 reg = *(u16 *)reg_buf;
        u32 *val = (u32 *)val_buf;
 
        if (priv->mgmt_master &&
@@ -666,6 +666,15 @@ qca8k_phy_eth_command(struct qca8k_priv *priv, bool read, int phy,
                goto err_read_skb;
        }
 
+       /* It seems that accessing the switch's internal PHYs via management
+        * packets still uses the MDIO bus within the switch internally, and
+        * these accesses can conflict with external MDIO accesses to other
+        * devices on the MDIO bus.
+        * We therefore need to lock the MDIO bus onto which the switch is
+        * connected.
+        */
+       mutex_lock(&priv->bus->mdio_lock);
+
        /* Actually start the request:
         * 1. Send mdio master packet
         * 2. Busy Wait for mdio master command
@@ -678,6 +687,7 @@ qca8k_phy_eth_command(struct qca8k_priv *priv, bool read, int phy,
        mgmt_master = priv->mgmt_master;
        if (!mgmt_master) {
                mutex_unlock(&mgmt_eth_data->mutex);
+               mutex_unlock(&priv->bus->mdio_lock);
                ret = -EINVAL;
                goto err_mgmt_master;
        }
@@ -765,6 +775,7 @@ exit:
                                    QCA8K_ETHERNET_TIMEOUT);
 
        mutex_unlock(&mgmt_eth_data->mutex);
+       mutex_unlock(&priv->bus->mdio_lock);
 
        return ret;
 
index ca66b747b7c5d160de5e9f70eff26ef394b67c3e..d7c274af6d4dae0d5270821c7209d3f95991554f 100644 (file)
@@ -294,7 +294,7 @@ static int adin1110_read_fifo(struct adin1110_port_priv *port_priv)
 {
        struct adin1110_priv *priv = port_priv->priv;
        u32 header_len = ADIN1110_RD_HEADER_LEN;
-       struct spi_transfer t;
+       struct spi_transfer t = {0};
        u32 frame_size_no_fcs;
        struct sk_buff *rxb;
        u32 frame_size;
index ad32ca81f7ef41365dda25dd0778e60bab2d5406..f955bde10cf90ad6375f9b97fcffc36ba174a358 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 4d4140b7c4509dbe8f84155818423cdae0398a27..f3305c434c95b188e02cf2d2f641a31e08916a3d 100644 (file)
@@ -2170,7 +2170,7 @@ static void xgene_enet_shutdown(struct platform_device *pdev)
 static struct platform_driver xgene_enet_driver = {
        .driver = {
                   .name = "xgene-enet",
-                  .of_match_table = of_match_ptr(xgene_enet_of_match),
+                  .of_match_table = xgene_enet_of_match,
                   .acpi_match_table = ACPI_PTR(xgene_enet_acpi_match),
        },
        .probe = xgene_enet_probe,
index 5cc0dbe12132727fb286a41d117a8091c346ec53..7551aa8068f8f794fc9beb9e6cbdf5bd8faaee18 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 8d719f82854a9d3acb582ba3b8af13479d29771d..76de55306c4d0182ce0e5b8d3c4f49420520242a 100644 (file)
@@ -3816,6 +3816,8 @@ int t4_load_phy_fw(struct adapter *adap, int win,
                 FW_PARAMS_PARAM_Z_V(FW_PARAMS_PARAM_DEV_PHYFW_DOWNLOAD));
        ret = t4_set_params_timeout(adap, adap->mbox, adap->pf, 0, 1,
                                    &param, &val, 30000);
+       if (ret)
+               return ret;
 
        /* If we have version number support, then check to see that the new
         * firmware got loaded properly.
index 5fc64e47568a9c55acaabb62eeb30cfa7524f876..d567e42e176011d42b9549d0cc6292a06126d61d 100644 (file)
@@ -911,7 +911,7 @@ static int csk_wait_memory(struct chtls_dev *cdev,
                           struct sock *sk, long *timeo_p)
 {
        DEFINE_WAIT_FUNC(wait, woken_wake_function);
-       int err = 0;
+       int ret, err = 0;
        long current_timeo;
        long vm_wait = 0;
        bool noblock;
@@ -942,10 +942,13 @@ static int csk_wait_memory(struct chtls_dev *cdev,
 
                set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
                sk->sk_write_pending++;
-               sk_wait_event(sk, &current_timeo, sk->sk_err ||
-                             (sk->sk_shutdown & SEND_SHUTDOWN) ||
-                             (csk_mem_free(cdev, sk) && !vm_wait), &wait);
+               ret = sk_wait_event(sk, &current_timeo, sk->sk_err ||
+                                   (sk->sk_shutdown & SEND_SHUTDOWN) ||
+                                   (csk_mem_free(cdev, sk) && !vm_wait),
+                                   &wait);
                sk->sk_write_pending--;
+               if (ret < 0)
+                       goto do_error;
 
                if (vm_wait) {
                        vm_wait -= current_timeo;
@@ -1348,6 +1351,7 @@ static int chtls_pt_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
        int copied = 0;
        int target;
        long timeo;
+       int ret;
 
        buffers_freed = 0;
 
@@ -1423,7 +1427,11 @@ static int chtls_pt_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
                if (copied >= target)
                        break;
                chtls_cleanup_rbuf(sk, copied);
-               sk_wait_data(sk, &timeo, NULL);
+               ret = sk_wait_data(sk, &timeo, NULL);
+               if (ret < 0) {
+                       copied = copied ? : ret;
+                       goto unlock;
+               }
                continue;
 found_ok_skb:
                if (!skb->len) {
@@ -1518,6 +1526,8 @@ skip_copy:
 
        if (buffers_freed)
                chtls_cleanup_rbuf(sk, copied);
+
+unlock:
        release_sock(sk);
        return copied;
 }
@@ -1534,6 +1544,7 @@ static int peekmsg(struct sock *sk, struct msghdr *msg,
        int copied = 0;
        size_t avail;          /* amount of available data in current skb */
        long timeo;
+       int ret;
 
        lock_sock(sk);
        timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
@@ -1585,7 +1596,12 @@ static int peekmsg(struct sock *sk, struct msghdr *msg,
                        release_sock(sk);
                        lock_sock(sk);
                } else {
-                       sk_wait_data(sk, &timeo, NULL);
+                       ret = sk_wait_data(sk, &timeo, NULL);
+                       if (ret < 0) {
+                               /* here 'copied' is 0 due to previous checks */
+                               copied = ret;
+                               break;
+                       }
                }
 
                if (unlikely(peek_seq != tp->copied_seq)) {
@@ -1656,6 +1672,7 @@ int chtls_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
        int copied = 0;
        long timeo;
        int target;             /* Read at least this many bytes */
+       int ret;
 
        buffers_freed = 0;
 
@@ -1747,7 +1764,11 @@ int chtls_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
                if (copied >= target)
                        break;
                chtls_cleanup_rbuf(sk, copied);
-               sk_wait_data(sk, &timeo, NULL);
+               ret = sk_wait_data(sk, &timeo, NULL);
+               if (ret < 0) {
+                       copied = copied ? : ret;
+                       goto unlock;
+               }
                continue;
 
 found_ok_skb:
@@ -1816,6 +1837,7 @@ skip_copy:
        if (buffers_freed)
                chtls_cleanup_rbuf(sk, copied);
 
+unlock:
        release_sock(sk);
        return copied;
 }
index 716815dad7d2190c29a44603e1ef342d985c1d2f..65ec1abc944211471f5eef3d564718c2c6b566fd 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 f61bd89734c588e7c5314859f7245c7e081bba87..8b992dc9bb52b499b5ced0cb24d408e705fb45b0 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 d1da7413dc4deef2abf2a2911c3cf6de3a80870e..e84a066aa1a40a1f5709852c82da3d212a91f85b 100644 (file)
@@ -146,7 +146,7 @@ static int gve_prefill_rx_pages(struct gve_rx_ring *rx)
                err = gve_rx_alloc_buffer(priv, &priv->pdev->dev, &rx->data.page_info[i],
                                          &rx->data.data_ring[i]);
                if (err)
-                       goto alloc_err;
+                       goto alloc_err_rda;
        }
 
        if (!rx->data.raw_addressing) {
@@ -171,12 +171,26 @@ static int gve_prefill_rx_pages(struct gve_rx_ring *rx)
        return slots;
 
 alloc_err_qpl:
+       /* Fully free the copy pool pages. */
        while (j--) {
                page_ref_sub(rx->qpl_copy_pool[j].page,
                             rx->qpl_copy_pool[j].pagecnt_bias - 1);
                put_page(rx->qpl_copy_pool[j].page);
        }
-alloc_err:
+
+       /* Do not fully free QPL pages - only remove the bias added in this
+        * function with gve_setup_rx_buffer.
+        */
+       while (i--)
+               page_ref_sub(rx->data.page_info[i].page,
+                            rx->data.page_info[i].pagecnt_bias - 1);
+
+       gve_unassign_qpl(priv, rx->data.qpl->id);
+       rx->data.qpl = NULL;
+
+       return err;
+
+alloc_err_rda:
        while (i--)
                gve_rx_free_buffer(&priv->pdev->dev,
                                   &rx->data.page_info[i],
index b4895c7b3efd1216209653002fca98f1d7f1c897..cf50368441b783df43cb308745d49fa58a69674c 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 8ca368424436205c00951112a2ed7abaf4700153..c42574e297476bdd1209e4a3090345c9a4e13b3c 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 7a2f9233d69548d1a5be39ccb449c3c2708e2950..a4d68fb216fb92ae4a23b24d323dade62676abea 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 9406237c461e0c3664a40231d4cd6939002c7db4..f81a43d2cdfcd92c46c69e2c7e866912657ae07e 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 832a2ae019509cbd0bde6dd87be9fd78906b4a1a..a8d79ee350f8dacd623109eebdf5e1ccaea03c76 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 6e310a53946782fec7717d3bc82b6f0ae08a2637..55bb0b5310d5b4801ebc94918ac09870b3e76cb2 100644 (file)
@@ -580,7 +580,6 @@ struct i40e_pf {
 #define I40E_FLAG_DISABLE_FW_LLDP              BIT(24)
 #define I40E_FLAG_RS_FEC                       BIT(25)
 #define I40E_FLAG_BASE_R_FEC                   BIT(26)
-#define I40E_FLAG_VF_VLAN_PRUNING              BIT(27)
 /* TOTAL_PORT_SHUTDOWN
  * Allows to physically disable the link on the NIC's port.
  * If enabled, (after link down request from the OS)
@@ -603,6 +602,7 @@ struct i40e_pf {
  *   in abilities field of i40e_aq_set_phy_config structure
  */
 #define I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENABLED  BIT(27)
+#define I40E_FLAG_VF_VLAN_PRUNING              BIT(28)
 
        struct i40e_client_instance *cinst;
        bool stat_offsets_loaded;
index eeef20f77106255d3920abbc5feee38147211e27..1b493854f52292140866cf98c6346fe3787b2e59 100644 (file)
@@ -1082,7 +1082,7 @@ void i40e_clear_hw(struct i40e_hw *hw)
                     I40E_PFLAN_QALLOC_FIRSTQ_SHIFT;
        j = (val & I40E_PFLAN_QALLOC_LASTQ_MASK) >>
            I40E_PFLAN_QALLOC_LASTQ_SHIFT;
-       if (val & I40E_PFLAN_QALLOC_VALID_MASK)
+       if (val & I40E_PFLAN_QALLOC_VALID_MASK && j >= base_queue)
                num_queues = (j - base_queue) + 1;
        else
                num_queues = 0;
@@ -1092,7 +1092,7 @@ void i40e_clear_hw(struct i40e_hw *hw)
            I40E_PF_VT_PFALLOC_FIRSTVF_SHIFT;
        j = (val & I40E_PF_VT_PFALLOC_LASTVF_MASK) >>
            I40E_PF_VT_PFALLOC_LASTVF_SHIFT;
-       if (val & I40E_PF_VT_PFALLOC_VALID_MASK)
+       if (val & I40E_PF_VT_PFALLOC_VALID_MASK && j >= i)
                num_vfs = (j - i) + 1;
        else
                num_vfs = 0;
index 0b3a27f118fb97155d14317db16764143b8af575..b047c587629b67578cf109025162b9c166b3a47d 100644 (file)
@@ -2544,7 +2544,14 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget,
                        rx_buffer = i40e_rx_bi(rx_ring, ntp);
                        i40e_inc_ntp(rx_ring);
                        i40e_reuse_rx_page(rx_ring, rx_buffer);
-                       cleaned_count++;
+                       /* Update ntc and bump cleaned count if not in the
+                        * middle of mb packet.
+                        */
+                       if (rx_ring->next_to_clean == ntp) {
+                               rx_ring->next_to_clean =
+                                       rx_ring->next_to_process;
+                               cleaned_count++;
+                       }
                        continue;
                }
 
@@ -2847,7 +2854,7 @@ tx_only:
                return budget;
        }
 
-       if (vsi->back->flags & I40E_TXR_FLAGS_WB_ON_ITR)
+       if (q_vector->tx.ring[0].flags & I40E_TXR_FLAGS_WB_ON_ITR)
                q_vector->arm_wb_state = false;
 
        /* Exit the polling mode, but don't re-enable interrupts if stack might
index 8ea1a238dcefe1145833fc387444d8ebbdea4bb3..d3d6415553ed671bd433bf15173564abd5f3f30c 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 37f41c8a682fbd573cb8cfe94ecc80b972bdb0fc..7d991e4d9b896c67d5bff178b3e38c35a290b03f 100644 (file)
@@ -437,12 +437,12 @@ int i40e_clean_rx_irq_zc(struct i40e_ring *rx_ring, int budget)
        unsigned int total_rx_bytes = 0, total_rx_packets = 0;
        u16 next_to_process = rx_ring->next_to_process;
        u16 next_to_clean = rx_ring->next_to_clean;
-       u16 count_mask = rx_ring->count - 1;
        unsigned int xdp_res, xdp_xmit = 0;
        struct xdp_buff *first = NULL;
+       u32 count = rx_ring->count;
        struct bpf_prog *xdp_prog;
+       u32 entries_to_alloc;
        bool failure = false;
-       u16 cleaned_count;
 
        if (next_to_process != next_to_clean)
                first = *i40e_rx_bi(rx_ring, next_to_clean);
@@ -475,7 +475,8 @@ int i40e_clean_rx_irq_zc(struct i40e_ring *rx_ring, int budget)
                                                      qword);
                        bi = *i40e_rx_bi(rx_ring, next_to_process);
                        xsk_buff_free(bi);
-                       next_to_process = (next_to_process + 1) & count_mask;
+                       if (++next_to_process == count)
+                               next_to_process = 0;
                        continue;
                }
 
@@ -493,7 +494,8 @@ int i40e_clean_rx_irq_zc(struct i40e_ring *rx_ring, int budget)
                else if (i40e_add_xsk_frag(rx_ring, first, bi, size))
                        break;
 
-               next_to_process = (next_to_process + 1) & count_mask;
+               if (++next_to_process == count)
+                       next_to_process = 0;
 
                if (i40e_is_non_eop(rx_ring, rx_desc))
                        continue;
@@ -513,10 +515,10 @@ int i40e_clean_rx_irq_zc(struct i40e_ring *rx_ring, int budget)
 
        rx_ring->next_to_clean = next_to_clean;
        rx_ring->next_to_process = next_to_process;
-       cleaned_count = (next_to_clean - rx_ring->next_to_use - 1) & count_mask;
 
-       if (cleaned_count >= I40E_RX_BUFFER_WRITE)
-               failure |= !i40e_alloc_rx_buffers_zc(rx_ring, cleaned_count);
+       entries_to_alloc = I40E_DESC_UNUSED(rx_ring);
+       if (entries_to_alloc >= I40E_RX_BUFFER_WRITE)
+               failure |= !i40e_alloc_rx_buffers_zc(rx_ring, entries_to_alloc);
 
        i40e_finalize_xdp_rx(rx_ring, xdp_xmit);
        i40e_update_rx_stats(rx_ring, total_rx_bytes, total_rx_packets);
@@ -752,14 +754,16 @@ int i40e_xsk_wakeup(struct net_device *dev, u32 queue_id, u32 flags)
 
 void i40e_xsk_clean_rx_ring(struct i40e_ring *rx_ring)
 {
-       u16 count_mask = rx_ring->count - 1;
        u16 ntc = rx_ring->next_to_clean;
        u16 ntu = rx_ring->next_to_use;
 
-       for ( ; ntc != ntu; ntc = (ntc + 1)  & count_mask) {
+       while (ntc != ntu) {
                struct xdp_buff *rx_bi = *i40e_rx_bi(rx_ring, ntc);
 
                xsk_buff_free(rx_bi);
+               ntc++;
+               if (ntc >= rx_ring->count)
+                       ntc = 0;
        }
 }
 
index 85fba85fbb232bf869a988892f90084d92b3629a..e110ba3461857b0abf54d872df9a55ef282f00e6 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 a34303ad057d005c7289ec161562ed916b5d7827..90397293525f7169a7bb15ae2c4866d5ffd30fdc 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 7b300c86ceda733a94222472a77aa3e9d8e68b5d..b3434dbc90d6fe9cee2417ac97e381f66755882c 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
@@ -1438,9 +1437,9 @@ void iavf_down(struct iavf_adapter *adapter)
                        adapter->aq_required |= IAVF_FLAG_AQ_DEL_FDIR_FILTER;
                if (!list_empty(&adapter->adv_rss_list_head))
                        adapter->aq_required |= IAVF_FLAG_AQ_DEL_ADV_RSS_CFG;
-               adapter->aq_required |= IAVF_FLAG_AQ_DISABLE_QUEUES;
        }
 
+       adapter->aq_required |= IAVF_FLAG_AQ_DISABLE_QUEUES;
        mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0);
 }
 
@@ -4983,8 +4982,6 @@ static int iavf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        INIT_WORK(&adapter->finish_config, iavf_finish_config);
        INIT_DELAYED_WORK(&adapter->watchdog_task, iavf_watchdog_task);
        INIT_DELAYED_WORK(&adapter->client_task, iavf_client_task);
-       queue_delayed_work(adapter->wq, &adapter->watchdog_task,
-                          msecs_to_jiffies(5 * (pdev->devfn & 0x07)));
 
        /* Setup the wait queue for indicating transition to down status */
        init_waitqueue_head(&adapter->down_waitqueue);
@@ -4995,6 +4992,9 @@ static int iavf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        /* Setup the wait queue for indicating virtchannel events */
        init_waitqueue_head(&adapter->vc_waitqueue);
 
+       queue_delayed_work(adapter->wq, &adapter->watchdog_task,
+                          msecs_to_jiffies(5 * (pdev->devfn & 0x07)));
+       /* Initialization goes on in the work. Do not add more of it below. */
        return 0;
 
 err_ioremap:
index 4f39863b5537e34f6b0a2fd9385e7ab53e0af4f1..7b1256992dcf6dda2336801778697ffa90490fd3 100644 (file)
@@ -2093,3 +2093,35 @@ lag_rebuild_out:
        }
        mutex_unlock(&pf->lag_mutex);
 }
+
+/**
+ * ice_lag_is_switchdev_running
+ * @pf: pointer to PF structure
+ *
+ * Check if switchdev is running on any of the interfaces connected to lag.
+ */
+bool ice_lag_is_switchdev_running(struct ice_pf *pf)
+{
+       struct ice_lag *lag = pf->lag;
+       struct net_device *tmp_nd;
+
+       if (!ice_is_feature_supported(pf, ICE_F_SRIOV_LAG) || !lag)
+               return false;
+
+       rcu_read_lock();
+       for_each_netdev_in_bond_rcu(lag->upper_netdev, tmp_nd) {
+               struct ice_netdev_priv *priv = netdev_priv(tmp_nd);
+
+               if (!netif_is_ice(tmp_nd) || !priv || !priv->vsi ||
+                   !priv->vsi->back)
+                       continue;
+
+               if (ice_is_switchdev_running(priv->vsi->back)) {
+                       rcu_read_unlock();
+                       return true;
+               }
+       }
+       rcu_read_unlock();
+
+       return false;
+}
index 18075b82485aa69beee467e8a875480d6d90c3df..facb6c894b6dd17ff13d92e53bcd9af2a6db726e 100644 (file)
@@ -62,4 +62,5 @@ void ice_lag_move_new_vf_nodes(struct ice_vf *vf);
 int ice_init_lag(struct ice_pf *pf);
 void ice_deinit_lag(struct ice_pf *pf);
 void ice_lag_rebuild(struct ice_pf *pf);
+bool ice_lag_is_switchdev_running(struct ice_pf *pf);
 #endif /* _ICE_LAG_H_ */
index 201570cd2e0b3c0a164368c6b51f17aba80c6a05..73bbf06a76db9db5092f21593b68254a2d4300ae 100644 (file)
@@ -1201,8 +1201,7 @@ static void ice_set_rss_vsi_ctx(struct ice_vsi_ctx *ctxt, struct ice_vsi *vsi)
 
        ctxt->info.q_opt_rss = ((lut_type << ICE_AQ_VSI_Q_OPT_RSS_LUT_S) &
                                ICE_AQ_VSI_Q_OPT_RSS_LUT_M) |
-                               ((hash_type << ICE_AQ_VSI_Q_OPT_RSS_HASH_S) &
-                                ICE_AQ_VSI_Q_OPT_RSS_HASH_M);
+                               (hash_type & ICE_AQ_VSI_Q_OPT_RSS_HASH_M);
 }
 
 static void
@@ -3575,6 +3574,12 @@ int ice_set_dflt_vsi(struct ice_vsi *vsi)
 
        dev = ice_pf_to_dev(vsi->back);
 
+       if (ice_lag_is_switchdev_running(vsi->back)) {
+               dev_dbg(dev, "VSI %d passed is a part of LAG containing interfaces in switchdev mode, nothing to do\n",
+                       vsi->vsi_num);
+               return 0;
+       }
+
        /* the VSI passed in is already the default VSI */
        if (ice_is_vsi_dflt_vsi(vsi)) {
                dev_dbg(dev, "VSI %d passed in is already the default forwarding VSI, nothing to do\n",
index c8286adae94629ec725dc1c8c94d208fd1533845..7784135160fd20c770ddbdf70f0b4e1a86899093 100644 (file)
@@ -6,6 +6,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <generated/utsrelease.h>
+#include <linux/crash_dump.h>
 #include "ice.h"
 #include "ice_base.h"
 #include "ice_lib.h"
@@ -4683,6 +4684,9 @@ static void ice_init_features(struct ice_pf *pf)
 
 static void ice_deinit_features(struct ice_pf *pf)
 {
+       if (ice_is_safe_mode(pf))
+               return;
+
        ice_deinit_lag(pf);
        if (test_bit(ICE_FLAG_DCB_CAPABLE, pf->flags))
                ice_cfg_lldp_mib_change(&pf->hw, false);
@@ -5014,6 +5018,20 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
                return -EINVAL;
        }
 
+       /* when under a kdump kernel initiate a reset before enabling the
+        * device in order to clear out any pending DMA transactions. These
+        * transactions can cause some systems to machine check when doing
+        * the pcim_enable_device() below.
+        */
+       if (is_kdump_kernel()) {
+               pci_save_state(pdev);
+               pci_clear_master(pdev);
+               err = pcie_flr(pdev);
+               if (err)
+                       return err;
+               pci_restore_state(pdev);
+       }
+
        /* this driver uses devres, see
         * Documentation/driver-api/driver-model/devres.rst
         */
index b03426ac932bc1910e7f644240feeb6c92588144..db97353efd067f496150bdf0a2213fa3b1755414 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 319ed601eaa1e9827e7fab48c6d13b01e2bedff1..4ee849985e2b8a7563c72026cabd818070795f6c 100644 (file)
@@ -2978,11 +2978,15 @@ static int igb_add_ethtool_nfc_entry(struct igb_adapter *adapter,
        if (err)
                goto err_out_w_lock;
 
-       igb_update_ethtool_nfc_entry(adapter, input, input->sw_idx);
+       err = igb_update_ethtool_nfc_entry(adapter, input, input->sw_idx);
+       if (err)
+               goto err_out_input_filter;
 
        spin_unlock(&adapter->nfc_lock);
        return 0;
 
+err_out_input_filter:
+       igb_erase_filter(adapter, input);
 err_out_w_lock:
        spin_unlock(&adapter->nfc_lock);
 err_out:
index 93bce729be76a69c562ee5523bd521466356168b..dd8a9d27a1670c9ec536278c14332a7d1b4f9391 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) {
@@ -1810,7 +1817,7 @@ igc_ethtool_set_link_ksettings(struct net_device *netdev,
        struct igc_adapter *adapter = netdev_priv(netdev);
        struct net_device *dev = adapter->netdev;
        struct igc_hw *hw = &adapter->hw;
-       u32 advertising;
+       u16 advertised = 0;
 
        /* When adapter in resetting mode, autoneg/speed/duplex
         * cannot be changed
@@ -1835,18 +1842,33 @@ igc_ethtool_set_link_ksettings(struct net_device *netdev,
        while (test_and_set_bit(__IGC_RESETTING, &adapter->state))
                usleep_range(1000, 2000);
 
-       ethtool_convert_link_mode_to_legacy_u32(&advertising,
-                                               cmd->link_modes.advertising);
-       /* Converting to legacy u32 drops ETHTOOL_LINK_MODE_2500baseT_Full_BIT.
-        * We have to check this and convert it to ADVERTISE_2500_FULL
-        * (aka ETHTOOL_LINK_MODE_2500baseX_Full_BIT) explicitly.
-        */
-       if (ethtool_link_ksettings_test_link_mode(cmd, advertising, 2500baseT_Full))
-               advertising |= ADVERTISE_2500_FULL;
+       if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
+                                                 2500baseT_Full))
+               advertised |= ADVERTISE_2500_FULL;
+
+       if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
+                                                 1000baseT_Full))
+               advertised |= ADVERTISE_1000_FULL;
+
+       if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
+                                                 100baseT_Full))
+               advertised |= ADVERTISE_100_FULL;
+
+       if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
+                                                 100baseT_Half))
+               advertised |= ADVERTISE_100_HALF;
+
+       if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
+                                                 10baseT_Full))
+               advertised |= ADVERTISE_10_FULL;
+
+       if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
+                                                 10baseT_Half))
+               advertised |= ADVERTISE_10_HALF;
 
        if (cmd->base.autoneg == AUTONEG_ENABLE) {
                hw->mac.autoneg = 1;
-               hw->phy.autoneg_advertised = advertising;
+               hw->phy.autoneg_advertised = advertised;
                if (adapter->fc_autoneg)
                        hw->fc.requested_mode = igc_fc_default;
        } else {
index 293b4571768384d2116dcc4a66c368e842436926..98de34d0ce07e1a6915f5eb5befee3a619572d9b 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 29cc6098807120aa3213f9f43704e01b55a6a120..ea88ac04ab9ade7c0929840f72f6d328218b37f8 100644 (file)
@@ -28,6 +28,9 @@ static inline void ixgbe_alloc_vf_macvlans(struct ixgbe_adapter *adapter,
        struct vf_macvlans *mv_list;
        int num_vf_macvlans, i;
 
+       /* Initialize list of VF macvlans */
+       INIT_LIST_HEAD(&adapter->vf_mvs.l);
+
        num_vf_macvlans = hw->mac.num_rar_entries -
                          (IXGBE_MAX_PF_MACVLANS + 1 + num_vfs);
        if (!num_vf_macvlans)
@@ -36,8 +39,6 @@ static inline void ixgbe_alloc_vf_macvlans(struct ixgbe_adapter *adapter,
        mv_list = kcalloc(num_vf_macvlans, sizeof(struct vf_macvlans),
                          GFP_KERNEL);
        if (mv_list) {
-               /* Initialize list of VF macvlans */
-               INIT_LIST_HEAD(&adapter->vf_mvs.l);
                for (i = 0; i < num_vf_macvlans; i++) {
                        mv_list[i].vf = -1;
                        mv_list[i].free = true;
index 4424de2ffd70ca6762cfd1666ac326163bc9527e..5b46ca47c8e5979661f95345f62c8164fe0c44b2 100644 (file)
@@ -715,32 +715,31 @@ static netdev_tx_t octep_start_xmit(struct sk_buff *skb,
                hw_desc->dptr = tx_buffer->sglist_dma;
        }
 
-       /* Flush the hw descriptor before writing to doorbell */
-       wmb();
-
-       /* Ring Doorbell to notify the NIC there is a new packet */
-       writel(1, iq->doorbell_reg);
+       netdev_tx_sent_queue(iq->netdev_q, skb->len);
+       skb_tx_timestamp(skb);
        atomic_inc(&iq->instr_pending);
        wi++;
        if (wi == iq->max_count)
                wi = 0;
        iq->host_write_index = wi;
+       /* Flush the hw descriptor before writing to doorbell */
+       wmb();
 
-       netdev_tx_sent_queue(iq->netdev_q, skb->len);
+       /* Ring Doorbell to notify the NIC there is a new packet */
+       writel(1, iq->doorbell_reg);
        iq->stats.instr_posted++;
-       skb_tx_timestamp(skb);
        return NETDEV_TX_OK;
 
 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 5a520d37bea02459815f868f889053949c4d3ce3..d0adb82d65c31eddccdb6b56522ce91e3d021fee 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 2ef57980eb47b8ee44c22c40acb9d18355f58956..21e75ff9f5e71165be04cdefd72678bd5911a663 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 59b138214af2f4e65fd26f2a974774aad4e3ef4d..6cc7a78968fc1c063a283a848ae5f8b886a19cca 100644 (file)
@@ -1357,10 +1357,12 @@ static int cn10k_mdo_upd_txsa(struct macsec_context *ctx)
 
        if (netif_running(secy->netdev)) {
                /* Keys cannot be changed after creation */
-               err = cn10k_write_tx_sa_pn(pfvf, txsc, sa_num,
-                                          sw_tx_sa->next_pn);
-               if (err)
-                       return err;
+               if (ctx->sa.update_pn) {
+                       err = cn10k_write_tx_sa_pn(pfvf, txsc, sa_num,
+                                                  sw_tx_sa->next_pn);
+                       if (err)
+                               return err;
+               }
 
                err = cn10k_mcs_link_tx_sa2sc(pfvf, secy, txsc,
                                              sa_num, sw_tx_sa->active);
@@ -1529,6 +1531,9 @@ static int cn10k_mdo_upd_rxsa(struct macsec_context *ctx)
                if (err)
                        return err;
 
+               if (!ctx->sa.update_pn)
+                       return 0;
+
                err = cn10k_mcs_write_rx_sa_pn(pfvf, rxsc, sa_num,
                                               rx_sa->next_pn);
                if (err)
index 997fedac3a98fdfeadf0f481805477ce295638db..818ce76185b2f3bab47bc59696f7afe2868d3ec7 100644 (file)
@@ -1403,6 +1403,7 @@ int otx2_pool_init(struct otx2_nic *pfvf, u16 pool_id,
                return 0;
        }
 
+       pp_params.order = get_order(buf_size);
        pp_params.flags = PP_FLAG_PAGE_FRAG | PP_FLAG_DMA_MAP;
        pp_params.pool_size = min(OTX2_PAGE_POOL_SZ, numptrs);
        pp_params.nid = NUMA_NO_NODE;
index e77d43848955796c69b45a084efa5b8e17d60dd5..53b2a4ef52985271ab6d0ee67c779af878876ba0 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 ddec1627f1a7bdcbd573400c51141de4f499a3e6..8d0bacf4e49ccceb2331f14ac2f21cba485940e9 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 3cffd1bd306777e5a79ff23a47558622d9e8d82d..20afe79f380a240c55bb6c3d06a0bd614046f70c 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 afb348579577c533dbb193df134e5c7793c4ed55..c22b0ad0c8701d55c9b4ad471fe87c7f54f125a1 100644 (file)
@@ -2186,52 +2186,23 @@ static u16 cmdif_rev(struct mlx5_core_dev *dev)
 
 int mlx5_cmd_init(struct mlx5_core_dev *dev)
 {
-       int size = sizeof(struct mlx5_cmd_prot_block);
-       int align = roundup_pow_of_two(size);
        struct mlx5_cmd *cmd = &dev->cmd;
-       u32 cmd_l;
-       int err;
-
-       cmd->pool = dma_pool_create("mlx5_cmd", mlx5_core_dma_dev(dev), size, align, 0);
-       if (!cmd->pool)
-               return -ENOMEM;
 
-       err = alloc_cmd_page(dev, cmd);
-       if (err)
-               goto err_free_pool;
-
-       cmd_l = (u32)(cmd->dma);
-       if (cmd_l & 0xfff) {
-               mlx5_core_err(dev, "invalid command queue address\n");
-               err = -ENOMEM;
-               goto err_cmd_page;
-       }
        cmd->checksum_disabled = 1;
 
        spin_lock_init(&cmd->alloc_lock);
        spin_lock_init(&cmd->token_lock);
 
-       create_msg_cache(dev);
-
        set_wqname(dev);
        cmd->wq = create_singlethread_workqueue(cmd->wq_name);
        if (!cmd->wq) {
                mlx5_core_err(dev, "failed to create command workqueue\n");
-               err = -ENOMEM;
-               goto err_cache;
+               return -ENOMEM;
        }
 
        mlx5_cmdif_debugfs_init(dev);
 
        return 0;
-
-err_cache:
-       destroy_msg_cache(dev);
-err_cmd_page:
-       free_cmd_page(dev, cmd);
-err_free_pool:
-       dma_pool_destroy(cmd->pool);
-       return err;
 }
 
 void mlx5_cmd_cleanup(struct mlx5_core_dev *dev)
@@ -2240,15 +2211,15 @@ void mlx5_cmd_cleanup(struct mlx5_core_dev *dev)
 
        mlx5_cmdif_debugfs_cleanup(dev);
        destroy_workqueue(cmd->wq);
-       destroy_msg_cache(dev);
-       free_cmd_page(dev, cmd);
-       dma_pool_destroy(cmd->pool);
 }
 
 int mlx5_cmd_enable(struct mlx5_core_dev *dev)
 {
+       int size = sizeof(struct mlx5_cmd_prot_block);
+       int align = roundup_pow_of_two(size);
        struct mlx5_cmd *cmd = &dev->cmd;
        u32 cmd_h, cmd_l;
+       int err;
 
        memset(&cmd->vars, 0, sizeof(cmd->vars));
        cmd->vars.cmdif_rev = cmdif_rev(dev);
@@ -2281,10 +2252,21 @@ int mlx5_cmd_enable(struct mlx5_core_dev *dev)
        sema_init(&cmd->vars.pages_sem, 1);
        sema_init(&cmd->vars.throttle_sem, DIV_ROUND_UP(cmd->vars.max_reg_cmds, 2));
 
+       cmd->pool = dma_pool_create("mlx5_cmd", mlx5_core_dma_dev(dev), size, align, 0);
+       if (!cmd->pool)
+               return -ENOMEM;
+
+       err = alloc_cmd_page(dev, cmd);
+       if (err)
+               goto err_free_pool;
+
        cmd_h = (u32)((u64)(cmd->dma) >> 32);
        cmd_l = (u32)(cmd->dma);
-       if (WARN_ON(cmd_l & 0xfff))
-               return -EINVAL;
+       if (cmd_l & 0xfff) {
+               mlx5_core_err(dev, "invalid command queue address\n");
+               err = -ENOMEM;
+               goto err_cmd_page;
+       }
 
        iowrite32be(cmd_h, &dev->iseg->cmdq_addr_h);
        iowrite32be(cmd_l, &dev->iseg->cmdq_addr_l_sz);
@@ -2297,17 +2279,27 @@ int mlx5_cmd_enable(struct mlx5_core_dev *dev)
        cmd->mode = CMD_MODE_POLLING;
        cmd->allowed_opcode = CMD_ALLOWED_OPCODE_ALL;
 
+       create_msg_cache(dev);
        create_debugfs_files(dev);
 
        return 0;
+
+err_cmd_page:
+       free_cmd_page(dev, cmd);
+err_free_pool:
+       dma_pool_destroy(cmd->pool);
+       return err;
 }
 
 void mlx5_cmd_disable(struct mlx5_core_dev *dev)
 {
        struct mlx5_cmd *cmd = &dev->cmd;
 
-       clean_debug_files(dev);
        flush_workqueue(cmd->wq);
+       clean_debug_files(dev);
+       destroy_msg_cache(dev);
+       free_cmd_page(dev, cmd);
+       dma_pool_destroy(cmd->pool);
 }
 
 void mlx5_cmd_set_state(struct mlx5_core_dev *dev,
index 7c0f2adbea000d2453add53348a48c49ccc75110..ad789349c06e6b50f44840dfb52eaf53d47d5f2f 100644 (file)
@@ -848,7 +848,7 @@ static void mlx5_fw_tracer_ownership_change(struct work_struct *work)
 
        mlx5_core_dbg(tracer->dev, "FWTracer: ownership changed, current=(%d)\n", tracer->owner);
        if (tracer->owner) {
-               tracer->owner = false;
+               mlx5_fw_tracer_ownership_acquire(tracer);
                return;
        }
 
index 0fef853eab6265771a0445385e17df20e453407b..5d128c5b4529af107289dd5a31f2e105277bcd03 100644 (file)
@@ -467,6 +467,17 @@ static int mlx5_esw_bridge_switchdev_event(struct notifier_block *nb,
                /* only handle the event on peers */
                if (mlx5_esw_bridge_is_local(dev, rep, esw))
                        break;
+
+               fdb_info = container_of(info,
+                                       struct switchdev_notifier_fdb_info,
+                                       info);
+               /* Mark for deletion to prevent the update wq task from
+                * spuriously refreshing the entry which would mark it again as
+                * offloaded in SW bridge. After this fallthrough to regular
+                * async delete code.
+                */
+               mlx5_esw_bridge_fdb_mark_deleted(dev, vport_num, esw_owner_vhca_id, br_offloads,
+                                                fdb_info);
                fallthrough;
        case SWITCHDEV_FDB_ADD_TO_DEVICE:
        case SWITCHDEV_FDB_DEL_TO_DEVICE:
index 1730f6a716eeabbaefcb954405c6f0e5cfd185e8..b10e40e1a9c1414c386e219b09b2c7f381d85878 100644 (file)
@@ -24,7 +24,8 @@ static int mlx5e_set_int_port_tunnel(struct mlx5e_priv *priv,
 
        route_dev = dev_get_by_index(dev_net(e->out_dev), e->route_dev_ifindex);
 
-       if (!route_dev || !netif_is_ovs_master(route_dev))
+       if (!route_dev || !netif_is_ovs_master(route_dev) ||
+           attr->parse_attr->filter_dev == e->out_dev)
                goto out;
 
        err = mlx5e_set_fwd_to_int_port_actions(priv, attr, e->route_dev_ifindex,
index 12f56d0db0af2f904866b75d159a00a05a9e2f7a..8bed17d8fe5649320a45052174377232238dd36d 100644 (file)
@@ -874,11 +874,11 @@ int mlx5e_xdp_xmit(struct net_device *dev, int n, struct xdp_frame **frames,
        }
 
 out:
-       if (flags & XDP_XMIT_FLUSH) {
-               if (sq->mpwqe.wqe)
-                       mlx5e_xdp_mpwqe_complete(sq);
+       if (sq->mpwqe.wqe)
+               mlx5e_xdp_mpwqe_complete(sq);
+
+       if (flags & XDP_XMIT_FLUSH)
                mlx5e_xmit_xdp_doorbell(sq);
-       }
 
        return nxmit;
 }
index c9c1db971652d09ace6bce451084ffa03d8fc026..d4ebd8743114573e6da44b6eb2418653ab1c4922 100644 (file)
@@ -580,7 +580,7 @@ static int mlx5e_macsec_upd_txsa(struct macsec_context *ctx)
                goto out;
        }
 
-       if (tx_sa->next_pn != ctx_tx_sa->next_pn_halves.lower) {
+       if (ctx->sa.update_pn) {
                netdev_err(netdev, "MACsec offload: update TX sa %d PN isn't supported\n",
                           assoc_num);
                err = -EINVAL;
@@ -973,7 +973,7 @@ static int mlx5e_macsec_upd_rxsa(struct macsec_context *ctx)
                goto out;
        }
 
-       if (rx_sa->next_pn != ctx_rx_sa->next_pn_halves.lower) {
+       if (ctx->sa.update_pn) {
                netdev_err(ctx->netdev,
                           "MACsec offload update RX sa %d PN isn't supported\n",
                           assoc_num);
index a2ae791538edb76401f5c4206e679e1ec8c25d99..acb40770cf0cf7ba10a91ecfc9a62576de266167 100644 (file)
@@ -3952,13 +3952,14 @@ static int set_feature_rx_fcs(struct net_device *netdev, bool enable)
        struct mlx5e_channels *chs = &priv->channels;
        struct mlx5e_params new_params;
        int err;
+       bool rx_ts_over_crc = !enable;
 
        mutex_lock(&priv->state_lock);
 
        new_params = chs->params;
        new_params.scatter_fcs_en = enable;
        err = mlx5e_safe_switch_params(priv, &new_params, mlx5e_set_rx_port_ts_wrap,
-                                      &new_params.scatter_fcs_en, true);
+                                      &rx_ts_over_crc, true);
        mutex_unlock(&priv->state_lock);
        return err;
 }
index 2fdb8895aecd7b601316ffd385e04e5b7d63d64d..fd1cce542b680f0210a32757874a7c221d0dd5eb 100644 (file)
@@ -701,7 +701,7 @@ mlx5e_rep_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats)
 
        /* update HW stats in background for next time */
        mlx5e_queue_update_stats(priv);
-       memcpy(stats, &priv->stats.vf_vport, sizeof(*stats));
+       mlx5e_stats_copy_rep_stats(stats, &priv->stats.rep_stats);
 }
 
 static int mlx5e_rep_change_mtu(struct net_device *netdev, int new_mtu)
@@ -769,6 +769,7 @@ static int mlx5e_rep_max_nch_limit(struct mlx5_core_dev *mdev)
 
 static void mlx5e_build_rep_params(struct net_device *netdev)
 {
+       const bool take_rtnl = netdev->reg_state == NETREG_REGISTERED;
        struct mlx5e_priv *priv = netdev_priv(netdev);
        struct mlx5e_rep_priv *rpriv = priv->ppriv;
        struct mlx5_eswitch_rep *rep = rpriv->rep;
@@ -794,8 +795,15 @@ static void mlx5e_build_rep_params(struct net_device *netdev)
        /* RQ */
        mlx5e_build_rq_params(mdev, params);
 
+       /* If netdev is already registered (e.g. move from nic profile to uplink,
+        * RTNL lock must be held before triggering netdev notifiers.
+        */
+       if (take_rtnl)
+               rtnl_lock();
        /* update XDP supported features */
        mlx5e_set_xdp_feature(netdev);
+       if (take_rtnl)
+               rtnl_unlock();
 
        /* CQ moderation params */
        params->rx_dim_enabled = MLX5_CAP_GEN(mdev, cq_moderation);
index 3fd11b0761e09e4af026bd82a44ee3f812261fd0..8d9743a5e42c7c203d15b1f178221cdf3bd23135 100644 (file)
@@ -457,26 +457,41 @@ static int mlx5e_alloc_rx_wqes(struct mlx5e_rq *rq, u16 ix, int wqe_bulk)
 static int mlx5e_refill_rx_wqes(struct mlx5e_rq *rq, u16 ix, int wqe_bulk)
 {
        int remaining = wqe_bulk;
-       int i = 0;
+       int total_alloc = 0;
+       int refill_alloc;
+       int refill;
 
        /* The WQE bulk is split into smaller bulks that are sized
         * according to the page pool cache refill size to avoid overflowing
         * the page pool cache due to too many page releases at once.
         */
        do {
-               int refill = min_t(u16, rq->wqe.info.refill_unit, remaining);
-               int alloc_count;
+               refill = min_t(u16, rq->wqe.info.refill_unit, remaining);
 
-               mlx5e_free_rx_wqes(rq, ix + i, refill);
-               alloc_count = mlx5e_alloc_rx_wqes(rq, ix + i, refill);
-               i += alloc_count;
-               if (unlikely(alloc_count != refill))
-                       break;
+               mlx5e_free_rx_wqes(rq, ix + total_alloc, refill);
+               refill_alloc = mlx5e_alloc_rx_wqes(rq, ix + total_alloc, refill);
+               if (unlikely(refill_alloc != refill))
+                       goto err_free;
 
+               total_alloc += refill_alloc;
                remaining -= refill;
        } while (remaining);
 
-       return i;
+       return total_alloc;
+
+err_free:
+       mlx5e_free_rx_wqes(rq, ix, total_alloc + refill_alloc);
+
+       for (int i = 0; i < total_alloc + refill; i++) {
+               int j = mlx5_wq_cyc_ctr2ix(&rq->wqe.wq, ix + i);
+               struct mlx5e_wqe_frag_info *frag;
+
+               frag = get_frag(rq, j);
+               for (int k = 0; k < rq->wqe.info.num_frags; k++, frag++)
+                       frag->flags |= BIT(MLX5E_WQE_FRAG_SKIP_RELEASE);
+       }
+
+       return 0;
 }
 
 static void
@@ -816,6 +831,8 @@ err_unmap:
                mlx5e_page_release_fragmented(rq, frag_page);
        }
 
+       bitmap_fill(wi->skip_release_bitmap, rq->mpwqe.pages_per_wqe);
+
 err:
        rq->stats->buff_alloc_err++;
 
index 176fa5976259fbf2d419ce18e7179b369e5b69e6..477c547dcc04a5734f4ec8724dd1a4ee28b67666 100644 (file)
@@ -484,11 +484,20 @@ struct mlx5e_stats {
        struct mlx5e_vnic_env_stats vnic;
        struct mlx5e_vport_stats vport;
        struct mlx5e_pport_stats pport;
-       struct rtnl_link_stats64 vf_vport;
        struct mlx5e_pcie_stats pcie;
        struct mlx5e_rep_stats rep_stats;
 };
 
+static inline void mlx5e_stats_copy_rep_stats(struct rtnl_link_stats64 *vf_vport,
+                                             struct mlx5e_rep_stats *rep_stats)
+{
+       memset(vf_vport, 0, sizeof(*vf_vport));
+       vf_vport->rx_packets = rep_stats->vport_rx_packets;
+       vf_vport->tx_packets = rep_stats->vport_tx_packets;
+       vf_vport->rx_bytes = rep_stats->vport_rx_bytes;
+       vf_vport->tx_bytes = rep_stats->vport_tx_bytes;
+}
+
 extern mlx5e_stats_grp_t mlx5e_nic_stats_grps[];
 unsigned int mlx5e_nic_stats_grps_num(struct mlx5e_priv *priv);
 
index c24828b688ac0aa049f3518aefdf21251da4e8d9..c8590483ddc64be79d0e91a5b065781ff09d7cf2 100644 (file)
@@ -4972,7 +4972,8 @@ static int scan_tc_matchall_fdb_actions(struct mlx5e_priv *priv,
                        if (err)
                                return err;
 
-                       rpriv->prev_vf_vport_stats = priv->stats.vf_vport;
+                       mlx5e_stats_copy_rep_stats(&rpriv->prev_vf_vport_stats,
+                                                  &priv->stats.rep_stats);
                        break;
                default:
                        NL_SET_ERR_MSG_MOD(extack, "mlx5 supports only police action for matchall");
@@ -5012,7 +5013,7 @@ void mlx5e_tc_stats_matchall(struct mlx5e_priv *priv,
        u64 dbytes;
        u64 dpkts;
 
-       cur_stats = priv->stats.vf_vport;
+       mlx5e_stats_copy_rep_stats(&cur_stats, &priv->stats.rep_stats);
        dpkts = cur_stats.rx_packets - rpriv->prev_vf_vport_stats.rx_packets;
        dbytes = cur_stats.rx_bytes - rpriv->prev_vf_vport_stats.rx_bytes;
        rpriv->prev_vf_vport_stats = cur_stats;
index e36294b7ade274c8f39de6fe57e216d9551258a3..1b9bc32efd6fa904c461e1345700b59fd87edf94 100644 (file)
@@ -1748,6 +1748,28 @@ void mlx5_esw_bridge_fdb_update_used(struct net_device *dev, u16 vport_num, u16
        entry->lastuse = jiffies;
 }
 
+void mlx5_esw_bridge_fdb_mark_deleted(struct net_device *dev, u16 vport_num, u16 esw_owner_vhca_id,
+                                     struct mlx5_esw_bridge_offloads *br_offloads,
+                                     struct switchdev_notifier_fdb_info *fdb_info)
+{
+       struct mlx5_esw_bridge_fdb_entry *entry;
+       struct mlx5_esw_bridge *bridge;
+
+       bridge = mlx5_esw_bridge_from_port_lookup(vport_num, esw_owner_vhca_id, br_offloads);
+       if (!bridge)
+               return;
+
+       entry = mlx5_esw_bridge_fdb_lookup(bridge, fdb_info->addr, fdb_info->vid);
+       if (!entry) {
+               esw_debug(br_offloads->esw->dev,
+                         "FDB mark deleted entry with specified key not found (MAC=%pM,vid=%u,vport=%u)\n",
+                         fdb_info->addr, fdb_info->vid, vport_num);
+               return;
+       }
+
+       entry->flags |= MLX5_ESW_BRIDGE_FLAG_DELETED;
+}
+
 void mlx5_esw_bridge_fdb_create(struct net_device *dev, u16 vport_num, u16 esw_owner_vhca_id,
                                struct mlx5_esw_bridge_offloads *br_offloads,
                                struct switchdev_notifier_fdb_info *fdb_info)
@@ -1810,7 +1832,8 @@ void mlx5_esw_bridge_update(struct mlx5_esw_bridge_offloads *br_offloads)
                        unsigned long lastuse =
                                (unsigned long)mlx5_fc_query_lastuse(entry->ingress_counter);
 
-                       if (entry->flags & MLX5_ESW_BRIDGE_FLAG_ADDED_BY_USER)
+                       if (entry->flags & (MLX5_ESW_BRIDGE_FLAG_ADDED_BY_USER |
+                                           MLX5_ESW_BRIDGE_FLAG_DELETED))
                                continue;
 
                        if (time_after(lastuse, entry->lastuse))
index c2c7c70d99eb70c48d301de06298e231193c0d71..d6f5391619930dbcbb11aa610e14f4274dadc7c3 100644 (file)
@@ -62,6 +62,9 @@ int mlx5_esw_bridge_vport_peer_unlink(struct net_device *br_netdev, u16 vport_nu
 void mlx5_esw_bridge_fdb_update_used(struct net_device *dev, u16 vport_num, u16 esw_owner_vhca_id,
                                     struct mlx5_esw_bridge_offloads *br_offloads,
                                     struct switchdev_notifier_fdb_info *fdb_info);
+void mlx5_esw_bridge_fdb_mark_deleted(struct net_device *dev, u16 vport_num, u16 esw_owner_vhca_id,
+                                     struct mlx5_esw_bridge_offloads *br_offloads,
+                                     struct switchdev_notifier_fdb_info *fdb_info);
 void mlx5_esw_bridge_fdb_create(struct net_device *dev, u16 vport_num, u16 esw_owner_vhca_id,
                                struct mlx5_esw_bridge_offloads *br_offloads,
                                struct switchdev_notifier_fdb_info *fdb_info);
index 4911cc32161b4267f7c700061afb93f65a05d9e4..7c251af566c6fad96cabe905fc2d96853064f58b 100644 (file)
@@ -133,6 +133,7 @@ struct mlx5_esw_bridge_mdb_key {
 enum {
        MLX5_ESW_BRIDGE_FLAG_ADDED_BY_USER = BIT(0),
        MLX5_ESW_BRIDGE_FLAG_PEER = BIT(1),
+       MLX5_ESW_BRIDGE_FLAG_DELETED = BIT(2),
 };
 
 enum {
index d4cde655506323deac75918aa1429b8e6ce4d721..8d0b915a31214ea83366bfdcbabcc8ec0c232eaf 100644 (file)
@@ -1038,11 +1038,8 @@ const u32 *mlx5_esw_query_functions(struct mlx5_core_dev *dev)
        return ERR_PTR(err);
 }
 
-static void mlx5_eswitch_event_handlers_register(struct mlx5_eswitch *esw)
+static void mlx5_eswitch_event_handler_register(struct mlx5_eswitch *esw)
 {
-       MLX5_NB_INIT(&esw->nb, eswitch_vport_event, NIC_VPORT_CHANGE);
-       mlx5_eq_notifier_register(esw->dev, &esw->nb);
-
        if (esw->mode == MLX5_ESWITCH_OFFLOADS && mlx5_eswitch_is_funcs_handler(esw->dev)) {
                MLX5_NB_INIT(&esw->esw_funcs.nb, mlx5_esw_funcs_changed_handler,
                             ESW_FUNCTIONS_CHANGED);
@@ -1050,13 +1047,11 @@ static void mlx5_eswitch_event_handlers_register(struct mlx5_eswitch *esw)
        }
 }
 
-static void mlx5_eswitch_event_handlers_unregister(struct mlx5_eswitch *esw)
+static void mlx5_eswitch_event_handler_unregister(struct mlx5_eswitch *esw)
 {
        if (esw->mode == MLX5_ESWITCH_OFFLOADS && mlx5_eswitch_is_funcs_handler(esw->dev))
                mlx5_eq_notifier_unregister(esw->dev, &esw->esw_funcs.nb);
 
-       mlx5_eq_notifier_unregister(esw->dev, &esw->nb);
-
        flush_workqueue(esw->work_queue);
 }
 
@@ -1483,6 +1478,9 @@ int mlx5_eswitch_enable_locked(struct mlx5_eswitch *esw, int num_vfs)
 
        mlx5_eswitch_update_num_of_vfs(esw, num_vfs);
 
+       MLX5_NB_INIT(&esw->nb, eswitch_vport_event, NIC_VPORT_CHANGE);
+       mlx5_eq_notifier_register(esw->dev, &esw->nb);
+
        if (esw->mode == MLX5_ESWITCH_LEGACY) {
                err = esw_legacy_enable(esw);
        } else {
@@ -1495,7 +1493,7 @@ int mlx5_eswitch_enable_locked(struct mlx5_eswitch *esw, int num_vfs)
 
        esw->fdb_table.flags |= MLX5_ESW_FDB_CREATED;
 
-       mlx5_eswitch_event_handlers_register(esw);
+       mlx5_eswitch_event_handler_register(esw);
 
        esw_info(esw->dev, "Enable: mode(%s), nvfs(%d), necvfs(%d), active vports(%d)\n",
                 esw->mode == MLX5_ESWITCH_LEGACY ? "LEGACY" : "OFFLOADS",
@@ -1622,7 +1620,8 @@ void mlx5_eswitch_disable_locked(struct mlx5_eswitch *esw)
         */
        mlx5_esw_mode_change_notify(esw, MLX5_ESWITCH_LEGACY);
 
-       mlx5_eswitch_event_handlers_unregister(esw);
+       mlx5_eq_notifier_unregister(esw->dev, &esw->nb);
+       mlx5_eswitch_event_handler_unregister(esw);
 
        esw_info(esw->dev, "Disable: mode(%s), nvfs(%d), necvfs(%d), active vports(%d)\n",
                 esw->mode == MLX5_ESWITCH_LEGACY ? "LEGACY" : "OFFLOADS",
index bb8eeb86edf751713b14b4a1bbcdd53cf0ac325b..52c2fe3644d4b9b27f1d589d9f7f597748339782 100644 (file)
@@ -310,8 +310,8 @@ const struct mlxsw_sp_nve_ops mlxsw_sp1_nve_vxlan_ops = {
        .fdb_clear_offload = mlxsw_sp_nve_vxlan_clear_offload,
 };
 
-static bool mlxsw_sp2_nve_vxlan_learning_set(struct mlxsw_sp *mlxsw_sp,
-                                            bool learning_en)
+static int mlxsw_sp2_nve_vxlan_learning_set(struct mlxsw_sp *mlxsw_sp,
+                                           bool learning_en)
 {
        char tnpc_pl[MLXSW_REG_TNPC_LEN];
 
index 329e374b9539c9ac684149e441b6fd1b6c4dadf8..43ba71e82260c1db39a91c64c4b3f9e68e0a5539 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 c07f25e791c7633a7cd1f4c297976cb41e6bb451..fe4e166de8a0458ffa509f2238a45ae33920743a 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 4a16ebff3d1d532a2a79f982b297a8bfd71f1fb4..48ea4aeeea5d4c95f98317d8c712b0c7fc353c13 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 f21cf1f40f98734cd2bd44835cba017cc0c3a67e..153533cd8f086a9a8c3cbf07ab7032f1a1b80295 100644 (file)
@@ -210,6 +210,7 @@ nfp_flower_cmsg_merge_hint_rx(struct nfp_app *app, struct sk_buff *skb)
        unsigned int msg_len = nfp_flower_cmsg_get_data_len(skb);
        struct nfp_flower_cmsg_merge_hint *msg;
        struct nfp_fl_payload *sub_flows[2];
+       struct nfp_flower_priv *priv;
        int err, i, flow_cnt;
 
        msg = nfp_flower_cmsg_get_data(skb);
@@ -228,14 +229,15 @@ nfp_flower_cmsg_merge_hint_rx(struct nfp_app *app, struct sk_buff *skb)
                return;
        }
 
-       rtnl_lock();
+       priv = app->priv;
+       mutex_lock(&priv->nfp_fl_lock);
        for (i = 0; i < flow_cnt; i++) {
                u32 ctx = be32_to_cpu(msg->flow[i].host_ctx);
 
                sub_flows[i] = nfp_flower_get_fl_payload_from_ctx(app, ctx);
                if (!sub_flows[i]) {
                        nfp_flower_cmsg_warn(app, "Invalid flow in merge hint\n");
-                       goto err_rtnl_unlock;
+                       goto err_mutex_unlock;
                }
        }
 
@@ -244,8 +246,8 @@ nfp_flower_cmsg_merge_hint_rx(struct nfp_app *app, struct sk_buff *skb)
        if (err == -ENOMEM)
                nfp_flower_cmsg_warn(app, "Flow merge memory fail.\n");
 
-err_rtnl_unlock:
-       rtnl_unlock();
+err_mutex_unlock:
+       mutex_unlock(&priv->nfp_fl_lock);
 }
 
 static void
index 2643c4b3ff1f4e58c0c0754b165b882bfb5d675d..2967bab72505617abcf59f0b16f5a1d5bb9d127c 100644 (file)
@@ -2131,8 +2131,6 @@ nfp_fl_ct_offload_nft_flow(struct nfp_fl_ct_zone_entry *zt, struct flow_cls_offl
        struct nfp_fl_ct_flow_entry *ct_entry;
        struct netlink_ext_ack *extack = NULL;
 
-       ASSERT_RTNL();
-
        extack = flow->common.extack;
        switch (flow->command) {
        case FLOW_CLS_REPLACE:
@@ -2178,9 +2176,13 @@ int nfp_fl_ct_handle_nft_flow(enum tc_setup_type type, void *type_data, void *cb
 
        switch (type) {
        case TC_SETUP_CLSFLOWER:
-               rtnl_lock();
+               while (!mutex_trylock(&zt->priv->nfp_fl_lock)) {
+                       if (!zt->nft) /* avoid deadlock */
+                               return err;
+                       msleep(20);
+               }
                err = nfp_fl_ct_offload_nft_flow(zt, flow);
-               rtnl_unlock();
+               mutex_unlock(&zt->priv->nfp_fl_lock);
                break;
        default:
                return -EOPNOTSUPP;
@@ -2208,6 +2210,7 @@ int nfp_fl_ct_del_flow(struct nfp_fl_ct_map_entry *ct_map_ent)
        struct nfp_fl_ct_flow_entry *ct_entry;
        struct nfp_fl_ct_zone_entry *zt;
        struct rhashtable *m_table;
+       struct nf_flowtable *nft;
 
        if (!ct_map_ent)
                return -ENOENT;
@@ -2226,8 +2229,12 @@ int nfp_fl_ct_del_flow(struct nfp_fl_ct_map_entry *ct_map_ent)
                if (ct_map_ent->cookie > 0)
                        kfree(ct_map_ent);
 
-               if (!zt->pre_ct_count) {
-                       zt->nft = NULL;
+               if (!zt->pre_ct_count && zt->nft) {
+                       nft = zt->nft;
+                       zt->nft = NULL; /* avoid deadlock */
+                       nf_flow_table_offload_del_cb(nft,
+                                                    nfp_fl_ct_handle_nft_flow,
+                                                    zt);
                        nfp_fl_ct_clean_nft_entries(zt);
                }
                break;
index 40372545148ef0d0d410369580a9f91ac8c057ec..2b7c947ff4f2ab3402199edebe329b1a6a189d86 100644 (file)
@@ -297,6 +297,7 @@ struct nfp_fl_internal_ports {
  * @predt_list:                List to keep track of decap pretun flows
  * @neigh_table:       Table to keep track of neighbor entries
  * @predt_lock:                Lock to serialise predt/neigh table updates
+ * @nfp_fl_lock:       Lock to protect the flow offload operation
  */
 struct nfp_flower_priv {
        struct nfp_app *app;
@@ -339,6 +340,7 @@ struct nfp_flower_priv {
        struct list_head predt_list;
        struct rhashtable neigh_table;
        spinlock_t predt_lock; /* Lock to serialise predt/neigh table updates */
+       struct mutex nfp_fl_lock; /* Protect the flow operation */
 };
 
 /**
index 0f06ef6e24bf41e0eaf3170b7f75b03d97ba7329..80e4675582bfbab6ea407d30db909905f6381196 100644 (file)
@@ -528,6 +528,8 @@ int nfp_flower_metadata_init(struct nfp_app *app, u64 host_ctx_count,
        if (err)
                goto err_free_stats_ctx_table;
 
+       mutex_init(&priv->nfp_fl_lock);
+
        err = rhashtable_init(&priv->ct_zone_table, &nfp_zone_table_params);
        if (err)
                goto err_free_merge_table;
index c153f0575b924f846fcaeeeed46b331be1c9a5e5..0aceef9fe58267564afee1c179e7731a3c615482 100644 (file)
@@ -1009,8 +1009,6 @@ int nfp_flower_merge_offloaded_flows(struct nfp_app *app,
        u64 parent_ctx = 0;
        int err;
 
-       ASSERT_RTNL();
-
        if (sub_flow1 == sub_flow2 ||
            nfp_flower_is_merge_flow(sub_flow1) ||
            nfp_flower_is_merge_flow(sub_flow2))
@@ -1727,19 +1725,30 @@ static int
 nfp_flower_repr_offload(struct nfp_app *app, struct net_device *netdev,
                        struct flow_cls_offload *flower)
 {
+       struct nfp_flower_priv *priv = app->priv;
+       int ret;
+
        if (!eth_proto_is_802_3(flower->common.protocol))
                return -EOPNOTSUPP;
 
+       mutex_lock(&priv->nfp_fl_lock);
        switch (flower->command) {
        case FLOW_CLS_REPLACE:
-               return nfp_flower_add_offload(app, netdev, flower);
+               ret = nfp_flower_add_offload(app, netdev, flower);
+               break;
        case FLOW_CLS_DESTROY:
-               return nfp_flower_del_offload(app, netdev, flower);
+               ret = nfp_flower_del_offload(app, netdev, flower);
+               break;
        case FLOW_CLS_STATS:
-               return nfp_flower_get_stats(app, netdev, flower);
+               ret = nfp_flower_get_stats(app, netdev, flower);
+               break;
        default:
-               return -EOPNOTSUPP;
+               ret = -EOPNOTSUPP;
+               break;
        }
+       mutex_unlock(&priv->nfp_fl_lock);
+
+       return ret;
 }
 
 static int nfp_flower_setup_tc_block_cb(enum tc_setup_type type,
@@ -1778,6 +1787,7 @@ static int nfp_flower_setup_tc_block(struct net_device *netdev,
        repr_priv = repr->app_priv;
        repr_priv->block_shared = f->block_shared;
        f->driver_block_list = &nfp_block_cb_list;
+       f->unlocked_driver_cb = true;
 
        switch (f->command) {
        case FLOW_BLOCK_BIND:
@@ -1876,6 +1886,8 @@ nfp_flower_setup_indr_tc_block(struct net_device *netdev, struct Qdisc *sch, str
             nfp_flower_internal_port_can_offload(app, netdev)))
                return -EOPNOTSUPP;
 
+       f->unlocked_driver_cb = true;
+
        switch (f->command) {
        case FLOW_BLOCK_BIND:
                cb_priv = nfp_flower_indr_block_cb_priv_lookup(app, netdev);
index 99052a925d9ecac75afdca263becf70b005a891d..e7180b4793c7d510dc2846717471b7aaa4f5c457 100644 (file)
@@ -523,25 +523,31 @@ int nfp_flower_setup_qos_offload(struct nfp_app *app, struct net_device *netdev,
 {
        struct netlink_ext_ack *extack = flow->common.extack;
        struct nfp_flower_priv *fl_priv = app->priv;
+       int ret;
 
        if (!(fl_priv->flower_ext_feats & NFP_FL_FEATS_VF_RLIM)) {
                NL_SET_ERR_MSG_MOD(extack, "unsupported offload: loaded firmware does not support qos rate limit offload");
                return -EOPNOTSUPP;
        }
 
+       mutex_lock(&fl_priv->nfp_fl_lock);
        switch (flow->command) {
        case TC_CLSMATCHALL_REPLACE:
-               return nfp_flower_install_rate_limiter(app, netdev, flow,
-                                                      extack);
+               ret = nfp_flower_install_rate_limiter(app, netdev, flow, extack);
+               break;
        case TC_CLSMATCHALL_DESTROY:
-               return nfp_flower_remove_rate_limiter(app, netdev, flow,
-                                                     extack);
+               ret = nfp_flower_remove_rate_limiter(app, netdev, flow, extack);
+               break;
        case TC_CLSMATCHALL_STATS:
-               return nfp_flower_stats_rate_limiter(app, netdev, flow,
-                                                    extack);
+               ret = nfp_flower_stats_rate_limiter(app, netdev, flow, extack);
+               break;
        default:
-               return -EOPNOTSUPP;
+               ret = -EOPNOTSUPP;
+               break;
        }
+       mutex_unlock(&fl_priv->nfp_fl_lock);
+
+       return ret;
 }
 
 /* Offload tc action, currently only for tc police */
index 6aac98bcb9f4b9f2e16503acc28590ce598779f4..aae4131f146a88fb9b447b80f2dd4617211bed64 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 26798fc635dbddf04947fb585ab2df4e26c7452f..44466e8c5d77bb819e783135c33651af5f2b9e79 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 717a0b3f89bd53a8779d60a54038ad9af19de08e..ab5ef254a74832948eb46180cdd3ad2dcc51d939 100644 (file)
@@ -113,7 +113,10 @@ static void qed_ll2b_complete_tx_packet(void *cxt,
 static int qed_ll2_alloc_buffer(struct qed_dev *cdev,
                                u8 **data, dma_addr_t *phys_addr)
 {
-       *data = kmalloc(cdev->ll2->rx_size, GFP_ATOMIC);
+       size_t size = cdev->ll2->rx_size + NET_SKB_PAD +
+                     SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+
+       *data = kmalloc(size, GFP_ATOMIC);
        if (!(*data)) {
                DP_INFO(cdev, "Failed to allocate LL2 buffer data\n");
                return -ENOMEM;
@@ -2589,7 +2592,7 @@ static int qed_ll2_start(struct qed_dev *cdev, struct qed_ll2_params *params)
        INIT_LIST_HEAD(&cdev->ll2->list);
        spin_lock_init(&cdev->ll2->lock);
 
-       cdev->ll2->rx_size = NET_SKB_PAD + ETH_HLEN +
+       cdev->ll2->rx_size = PRM_DMA_PAD_BYTES_NUM + ETH_HLEN +
                             L1_CACHE_BYTES + params->mtu;
 
        /* Allocate memory for LL2.
index 0bfc375161ed658b0166fef560016d6a1072603d..a174c6fc626acb0f0a6f255108bf0e24fd52418f 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 6351a2dc13bce6ee921ca8f8a6acec9ffb6bfb02..361b90007148b0ba620f7e5ad5e83d0b50db4a13 100644 (file)
@@ -4364,7 +4364,7 @@ static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp,
                unsigned int entry = dirty_tx % NUM_TX_DESC;
                u32 status;
 
-               status = le32_to_cpu(tp->TxDescArray[entry].opts1);
+               status = le32_to_cpu(READ_ONCE(tp->TxDescArray[entry].opts1));
                if (status & DescOwn)
                        break;
 
@@ -4394,7 +4394,7 @@ static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp,
                 * If skb is NULL then we come here again once a tx irq is
                 * triggered after the last fragment is marked transmitted.
                 */
-               if (tp->cur_tx != dirty_tx && skb)
+               if (READ_ONCE(tp->cur_tx) != dirty_tx && skb)
                        rtl8169_doorbell(tp);
        }
 }
@@ -4427,7 +4427,7 @@ static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, int budget
                dma_addr_t addr;
                u32 status;
 
-               status = le32_to_cpu(desc->opts1);
+               status = le32_to_cpu(READ_ONCE(desc->opts1));
                if (status & DescOwn)
                        break;
 
index 7df9f9f8e134025f62c4bf658a059075e359219c..0ef0b88b714590cef4ae0dbbc6dad2eee0579ee8 100644 (file)
@@ -2167,6 +2167,8 @@ static int ravb_close(struct net_device *ndev)
                        of_phy_deregister_fixed_link(np);
        }
 
+       cancel_work_sync(&priv->work);
+
        if (info->multi_irqs) {
                free_irq(priv->tx_irqs[RAVB_NC], ndev);
                free_irq(priv->rx_irqs[RAVB_NC], ndev);
@@ -2891,8 +2893,6 @@ static int ravb_remove(struct platform_device *pdev)
        clk_disable_unprepare(priv->gptp_clk);
        clk_disable_unprepare(priv->refclk);
 
-       dma_free_coherent(ndev->dev.parent, priv->desc_bat_size, priv->desc_bat,
-                         priv->desc_bat_dma);
        /* Set reset mode */
        ravb_write(ndev, CCC_OPC_RESET, CCC);
        unregister_netdev(ndev);
@@ -2900,6 +2900,8 @@ static int ravb_remove(struct platform_device *pdev)
                netif_napi_del(&priv->napi[RAVB_NC]);
        netif_napi_del(&priv->napi[RAVB_BE]);
        ravb_mdio_release(priv);
+       dma_free_coherent(ndev->dev.parent, priv->desc_bat_size, priv->desc_bat,
+                         priv->desc_bat_dma);
        pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
        reset_control_assert(priv->rstc);
index ea9186178091d5165ffcf14f5231a84d990a8e61..0fc0b6bea75305f253b14bc16d91da3d809f31d6 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);
 }
 
@@ -1253,7 +1254,7 @@ static void rswitch_adjust_link(struct net_device *ndev)
                phy_print_status(phydev);
                if (phydev->link)
                        phy_power_on(rdev->serdes);
-               else
+               else if (rdev->serdes->power_count)
                        phy_power_off(rdev->serdes);
 
                rdev->etha->link = phydev->link;
@@ -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;
@@ -1953,15 +1964,17 @@ static void rswitch_deinit(struct rswitch_private *priv)
        rswitch_gwca_hw_deinit(priv);
        rcar_gen4_ptp_unregister(priv->ptp_priv);
 
-       for (i = 0; i < RSWITCH_NUM_PORTS; i++) {
+       rswitch_for_each_enabled_port(priv, i) {
                struct rswitch_device *rdev = priv->rdev[i];
 
-               phy_exit(priv->rdev[i]->serdes);
-               rswitch_ether_port_deinit_one(rdev);
                unregister_netdev(rdev->ndev);
-               rswitch_device_free(priv, i);
+               rswitch_ether_port_deinit_one(rdev);
+               phy_exit(priv->rdev[i]->serdes);
        }
 
+       for (i = 0; i < RSWITCH_NUM_PORTS; i++)
+               rswitch_device_free(priv, i);
+
        rswitch_gwca_ts_queue_free(priv);
        rswitch_gwca_linkfix_free(priv);
 
index f0c16a37ea55858002a51a4984e77a34dd94e512..04f49a7a58435600c6a5f2aa801755e7f4906142 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 047322b04d4f52725c01a3db3e3e3788f9fb5e02..30ebef88248de3e22694c7eccc7d219859711406 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:
@@ -625,14 +629,14 @@ static int efx_tc_flower_record_encap_match(struct efx_nic *efx,
                        }
                        if (child_ip_tos_mask != old->child_ip_tos_mask) {
                                NL_SET_ERR_MSG_FMT_MOD(extack,
-                                                      "Pseudo encap match for TOS mask %#04x conflicts with existing pseudo(MASK) entry for TOS mask %#04x",
+                                                      "Pseudo encap match for TOS mask %#04x conflicts with existing mask %#04x",
                                                       child_ip_tos_mask,
                                                       old->child_ip_tos_mask);
                                return -EEXIST;
                        }
                        if (child_udp_sport_mask != old->child_udp_sport_mask) {
                                NL_SET_ERR_MSG_FMT_MOD(extack,
-                                                      "Pseudo encap match for UDP src port mask %#x conflicts with existing pseudo(MASK) entry for mask %#x",
+                                                      "Pseudo encap match for UDP src port mask %#x conflicts with existing mask %#x",
                                                       child_udp_sport_mask,
                                                       old->child_udp_sport_mask);
                                return -EEXIST;
@@ -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 */
@@ -1075,7 +1081,7 @@ static int efx_tc_pedit_add(struct efx_nic *efx, struct efx_tc_action_set *act,
                        /* check that we do not decrement ttl twice */
                        if (!efx_tc_flower_action_order_ok(act,
                                                           EFX_TC_AO_DEC_TTL)) {
-                               NL_SET_ERR_MSG_MOD(extack, "Unsupported: multiple dec ttl");
+                               NL_SET_ERR_MSG_MOD(extack, "multiple dec ttl are not supported");
                                return -EOPNOTSUPP;
                        }
                        act->do_ttl_dec = 1;
@@ -1100,7 +1106,7 @@ static int efx_tc_pedit_add(struct efx_nic *efx, struct efx_tc_action_set *act,
                        /* check that we do not decrement hoplimit twice */
                        if (!efx_tc_flower_action_order_ok(act,
                                                           EFX_TC_AO_DEC_TTL)) {
-                               NL_SET_ERR_MSG_MOD(extack, "Unsupported: multiple dec ttl");
+                               NL_SET_ERR_MSG_MOD(extack, "multiple dec ttl are not supported");
                                return -EOPNOTSUPP;
                        }
                        act->do_ttl_dec = 1;
@@ -1114,7 +1120,7 @@ static int efx_tc_pedit_add(struct efx_nic *efx, struct efx_tc_action_set *act,
        }
 
        NL_SET_ERR_MSG_FMT_MOD(extack,
-                              "Unsupported: ttl add action type %x %x %x/%x",
+                              "ttl add action type %x %x %x/%x is not supported",
                               fa->mangle.htype, fa->mangle.offset,
                               fa->mangle.val, fa->mangle.mask);
        return -EOPNOTSUPP;
@@ -1158,7 +1164,7 @@ static int efx_tc_mangle(struct efx_nic *efx, struct efx_tc_action_set *act,
                case 0:
                        if (fa->mangle.mask) {
                                NL_SET_ERR_MSG_FMT_MOD(extack,
-                                                      "Unsupported: mask (%#x) of eth.dst32 mangle",
+                                                      "mask (%#x) of eth.dst32 mangle is not supported",
                                                       fa->mangle.mask);
                                return -EOPNOTSUPP;
                        }
@@ -1178,7 +1184,7 @@ static int efx_tc_mangle(struct efx_nic *efx, struct efx_tc_action_set *act,
                                mung->dst_mac_16 = 1;
                        } else {
                                NL_SET_ERR_MSG_FMT_MOD(extack,
-                                                      "Unsupported: mask (%#x) of eth+4 mangle is not high or low 16b",
+                                                      "mask (%#x) of eth+4 mangle is not high or low 16b",
                                                       fa->mangle.mask);
                                return -EOPNOTSUPP;
                        }
@@ -1186,7 +1192,7 @@ static int efx_tc_mangle(struct efx_nic *efx, struct efx_tc_action_set *act,
                case 8:
                        if (fa->mangle.mask) {
                                NL_SET_ERR_MSG_FMT_MOD(extack,
-                                                      "Unsupported: mask (%#x) of eth.src32 mangle",
+                                                      "mask (%#x) of eth.src32 mangle is not supported",
                                                       fa->mangle.mask);
                                return -EOPNOTSUPP;
                        }
@@ -1195,7 +1201,7 @@ static int efx_tc_mangle(struct efx_nic *efx, struct efx_tc_action_set *act,
                        mung->src_mac_32 = 1;
                        return efx_tc_complete_mac_mangle(efx, act, mung, extack);
                default:
-                       NL_SET_ERR_MSG_FMT_MOD(extack, "Unsupported: mangle eth+%u %x/%x",
+                       NL_SET_ERR_MSG_FMT_MOD(extack, "mangle eth+%u %x/%x is not supported",
                                               fa->mangle.offset, fa->mangle.val, fa->mangle.mask);
                        return -EOPNOTSUPP;
                }
@@ -1211,7 +1217,7 @@ static int efx_tc_mangle(struct efx_nic *efx, struct efx_tc_action_set *act,
                        /* check that pedit applies to ttl only */
                        if (fa->mangle.mask != ~EFX_TC_HDR_TYPE_TTL_MASK) {
                                NL_SET_ERR_MSG_FMT_MOD(extack,
-                                                      "Unsupported: mask (%#x) out of range, only support mangle action on ipv4.ttl",
+                                                      "mask (%#x) out of range, only support mangle action on ipv4.ttl",
                                                       fa->mangle.mask);
                                return -EOPNOTSUPP;
                        }
@@ -1221,7 +1227,7 @@ static int efx_tc_mangle(struct efx_nic *efx, struct efx_tc_action_set *act,
                         */
                        if (match->mask.ip_ttl != U8_MAX) {
                                NL_SET_ERR_MSG_FMT_MOD(extack,
-                                                      "Unsupported: only support mangle ipv4.ttl when we have an exact match on ttl, mask used for match (%#x)",
+                                                      "only support mangle ttl when we have an exact match, current mask (%#x)",
                                                       match->mask.ip_ttl);
                                return -EOPNOTSUPP;
                        }
@@ -1231,7 +1237,7 @@ static int efx_tc_mangle(struct efx_nic *efx, struct efx_tc_action_set *act,
                         */
                        if (match->value.ip_ttl == 0) {
                                NL_SET_ERR_MSG_MOD(extack,
-                                                  "Unsupported: we cannot decrement ttl past 0");
+                                                  "decrement ttl past 0 is not supported");
                                return -EOPNOTSUPP;
                        }
 
@@ -1239,7 +1245,7 @@ static int efx_tc_mangle(struct efx_nic *efx, struct efx_tc_action_set *act,
                        if (!efx_tc_flower_action_order_ok(act,
                                                           EFX_TC_AO_DEC_TTL)) {
                                NL_SET_ERR_MSG_MOD(extack,
-                                                  "Unsupported: multiple dec ttl");
+                                                  "multiple dec ttl is not supported");
                                return -EOPNOTSUPP;
                        }
 
@@ -1253,7 +1259,7 @@ static int efx_tc_mangle(struct efx_nic *efx, struct efx_tc_action_set *act,
                        fallthrough;
                default:
                        NL_SET_ERR_MSG_FMT_MOD(extack,
-                                              "Unsupported: only support mangle on the ttl field (offset is %u)",
+                                              "only support mangle on the ttl field (offset is %u)",
                                               fa->mangle.offset);
                        return -EOPNOTSUPP;
                }
@@ -1269,7 +1275,7 @@ static int efx_tc_mangle(struct efx_nic *efx, struct efx_tc_action_set *act,
                        /* check that pedit applies to ttl only */
                        if (fa->mangle.mask != EFX_TC_HDR_TYPE_HLIMIT_MASK) {
                                NL_SET_ERR_MSG_FMT_MOD(extack,
-                                                      "Unsupported: mask (%#x) out of range, only support mangle action on ipv6.hop_limit",
+                                                      "mask (%#x) out of range, only support mangle action on ipv6.hop_limit",
                                                       fa->mangle.mask);
 
                                return -EOPNOTSUPP;
@@ -1280,7 +1286,7 @@ static int efx_tc_mangle(struct efx_nic *efx, struct efx_tc_action_set *act,
                         */
                        if (match->mask.ip_ttl != U8_MAX) {
                                NL_SET_ERR_MSG_FMT_MOD(extack,
-                                                      "Unsupported: only support mangle ipv6.hop_limit when we have an exact match on ttl, mask used for match (%#x)",
+                                                      "only support hop_limit when we have an exact match, current mask (%#x)",
                                                       match->mask.ip_ttl);
                                return -EOPNOTSUPP;
                        }
@@ -1290,7 +1296,7 @@ static int efx_tc_mangle(struct efx_nic *efx, struct efx_tc_action_set *act,
                         */
                        if (match->value.ip_ttl == 0) {
                                NL_SET_ERR_MSG_MOD(extack,
-                                                  "Unsupported: we cannot decrement hop_limit past 0");
+                                                  "decrementing hop_limit past 0 is not supported");
                                return -EOPNOTSUPP;
                        }
 
@@ -1298,7 +1304,7 @@ static int efx_tc_mangle(struct efx_nic *efx, struct efx_tc_action_set *act,
                        if (!efx_tc_flower_action_order_ok(act,
                                                           EFX_TC_AO_DEC_TTL)) {
                                NL_SET_ERR_MSG_MOD(extack,
-                                                  "Unsupported: multiple dec ttl");
+                                                  "multiple dec ttl is not supported");
                                return -EOPNOTSUPP;
                        }
 
@@ -1312,7 +1318,7 @@ static int efx_tc_mangle(struct efx_nic *efx, struct efx_tc_action_set *act,
                        fallthrough;
                default:
                        NL_SET_ERR_MSG_FMT_MOD(extack,
-                                              "Unsupported: only support mangle on the hop_limit field");
+                                              "only support mangle on the hop_limit field");
                        return -EOPNOTSUPP;
                }
        default:
@@ -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 8e06bfbcbea17cc5c3984d37a41725e61c895433..44bb57670340dae06cad31fde1deaa60a1ae6e90 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 0fafb47ea0824b450de43520430e41816aab9d12..c4408842432363d02bcbd64d5ab4807a444ae15e 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 7e8bcdb222ad18b4f175d5312613402d169dfbcd..87443f9dfd22b8b82564efc31bb0d8497d3757a1 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 403cb397d4d36ca6c841b19efb733468422616cf..1e996c29043dcbdc40bfb1e030f93b70d989e4a4 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 26ea8c687881cce9de2dbc1a3778f969a4838076..a0e276783e65f7f37be7e8e9bbb94a0ad2ccec18 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 01e77368eef1c1845b3c9b8fb610b62d61bd84dc..465ff1fd478554963cf339999c1768825b81aa97 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 980e5f8a37ec520ebb4116e812b2cd70afa1c22f..9470d3fd2dede2bb436c05f6a92d87824c2db733 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 aaa09b16b016f21a12725f053296086ac21b0111..7907d62d343759d661e00452198ef8e6cfef3601 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 fa69d64a86943160449d6ac8012d82544104f126..3cde695fec91bd7592e23e725517f0cccee08a42 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 3401e888a9f6860b835a115a80102d01ea44ebff..cd7a9768de5f12960cd88167a5483fbc24cf06d8 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 b7ac7abecdd3518001378039f63d9f0624bc9fd9..6aa5c0556d2203fcc2edd0307974f6e0d40ffccc 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 2206789802bf78d9068bc7dc6cc2e46be423649c..5801f4d50f95123a6389c72298b99009ea632d55 100644 (file)
@@ -1197,6 +1197,17 @@ static int stmmac_init_phy(struct net_device *dev)
        return ret;
 }
 
+static void stmmac_set_half_duplex(struct stmmac_priv *priv)
+{
+       /* Half-Duplex can only work with single tx queue */
+       if (priv->plat->tx_queues_to_use > 1)
+               priv->phylink_config.mac_capabilities &=
+                       ~(MAC_10HD | MAC_100HD | MAC_1000HD);
+       else
+               priv->phylink_config.mac_capabilities |=
+                       (MAC_10HD | MAC_100HD | MAC_1000HD);
+}
+
 static int stmmac_phy_setup(struct stmmac_priv *priv)
 {
        struct stmmac_mdio_bus_data *mdio_bus_data;
@@ -1228,10 +1239,7 @@ static int stmmac_phy_setup(struct stmmac_priv *priv)
                                                MAC_10FD | MAC_100FD |
                                                MAC_1000FD;
 
-       /* Half-Duplex can only work with single queue */
-       if (priv->plat->tx_queues_to_use <= 1)
-               priv->phylink_config.mac_capabilities |= MAC_10HD | MAC_100HD |
-                                                        MAC_1000HD;
+       stmmac_set_half_duplex(priv);
 
        /* Get the MAC specific capabilities */
        stmmac_mac_phylink_get_caps(priv);
@@ -2426,6 +2434,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 +2514,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 +2556,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 +2716,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 +4124,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 +4135,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 +4294,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 +4371,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 +4381,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 +4533,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 +4744,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 +4804,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 +4951,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 +4981,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 +5057,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 +5221,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 +5251,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 +5513,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 +5530,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 +5557,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 +5587,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 +6010,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 +6916,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 +6931,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 +6970,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,
@@ -7193,6 +7180,7 @@ int stmmac_reinit_queues(struct net_device *dev, u32 rx_cnt, u32 tx_cnt)
                        priv->rss.table[i] = ethtool_rxfh_indir_default(i,
                                                                        rx_cnt);
 
+       stmmac_set_half_duplex(priv);
        stmmac_napi_add(dev);
 
        if (netif_running(dev))
@@ -7342,9 +7330,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 0f28795e581c23957fba5c81c83ba9d248521a97..2f0678f15fb7e71f42a5727a4e36887592b3fbf2 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 88b5b1b47779a54c6970bc29bac47bfe35c35fbe..cac61f5d3fd41016500415348f6b907d1401eb82 100644 (file)
@@ -90,12 +90,16 @@ config TI_CPTS
          The unit can time stamp PTP UDP/IPv4 and Layer 2 packets, and the
          driver offers a PTP Hardware Clock.
 
+config TI_K3_CPPI_DESC_POOL
+       tristate
+
 config TI_K3_AM65_CPSW_NUSS
        tristate "TI K3 AM654x/J721E CPSW Ethernet driver"
        depends on ARCH_K3 && OF && TI_K3_UDMA_GLUE_LAYER
        select NET_DEVLINK
        select TI_DAVINCI_MDIO
        select PHYLINK
+       select TI_K3_CPPI_DESC_POOL
        imply PHY_TI_GMII_SEL
        depends on TI_K3_AM65_CPTS || !TI_K3_AM65_CPTS
        help
@@ -187,6 +191,7 @@ config TI_ICSSG_PRUETH
        tristate "TI Gigabit PRU Ethernet driver"
        select PHYLIB
        select TI_ICSS_IEP
+       select TI_K3_CPPI_DESC_POOL
        depends on PRU_REMOTEPROC
        depends on ARCH_K3 && OF && TI_K3_UDMA_GLUE_LAYER
        help
@@ -199,6 +204,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 34fd7a716ba6ec4b53018e8b2390b32bb04f0e86..67bed861f31d047ef473993d3c060cc7b1c42356 100644 (file)
@@ -24,14 +24,15 @@ keystone_netcp-y := netcp_core.o cpsw_ale.o
 obj-$(CONFIG_TI_KEYSTONE_NETCP_ETHSS) += keystone_netcp_ethss.o
 keystone_netcp_ethss-y := netcp_ethss.o netcp_sgmii.o netcp_xgbepcsr.o cpsw_ale.o
 
+obj-$(CONFIG_TI_K3_CPPI_DESC_POOL) += k3-cppi-desc-pool.o
+
 obj-$(CONFIG_TI_K3_AM65_CPSW_NUSS) += ti-am65-cpsw-nuss.o
-ti-am65-cpsw-nuss-y := am65-cpsw-nuss.o cpsw_sl.o am65-cpsw-ethtool.o cpsw_ale.o k3-cppi-desc-pool.o am65-cpsw-qos.o
+ti-am65-cpsw-nuss-y := am65-cpsw-nuss.o cpsw_sl.o am65-cpsw-ethtool.o cpsw_ale.o am65-cpsw-qos.o
 ti-am65-cpsw-nuss-$(CONFIG_TI_K3_AM65_CPSW_SWITCHDEV) += am65-cpsw-switchdev.o
 obj-$(CONFIG_TI_K3_AM65_CPTS) += am65-cpts.o
 
 obj-$(CONFIG_TI_ICSSG_PRUETH) += icssg-prueth.o
-icssg-prueth-y := k3-cppi-desc-pool.o \
-                 icssg/icssg_prueth.o \
+icssg-prueth-y := icssg/icssg_prueth.o \
                  icssg/icssg_classifier.o \
                  icssg/icssg_queues.o \
                  icssg/icssg_config.o \
index bea6fc0f324ce9a42e8ced4bd3a12a770e20f7ea..24120605502f9e8b7d3161d066902e2b8edc8a3f 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 933b846665749d28327414ac6542b0e039bc1445..b272361e378f1af532948839ef3acd78072f783c 100644 (file)
@@ -379,9 +379,9 @@ int icssg_config(struct prueth *prueth, struct prueth_emac *emac, int slice)
 
 /* Bitmask for ICSSG r30 commands */
 static const struct icssg_r30_cmd emac_r32_bitmask[] = {
-       {{0xffff0004, 0xffff0100, 0xffff0100, EMAC_NONE}},      /* EMAC_PORT_DISABLE */
+       {{0xffff0004, 0xffff0100, 0xffff0004, EMAC_NONE}},      /* EMAC_PORT_DISABLE */
        {{0xfffb0040, 0xfeff0200, 0xfeff0200, EMAC_NONE}},      /* EMAC_PORT_BLOCK */
-       {{0xffbb0000, 0xfcff0000, 0xdcff0000, EMAC_NONE}},      /* EMAC_PORT_FORWARD */
+       {{0xffbb0000, 0xfcff0000, 0xdcfb0000, EMAC_NONE}},      /* EMAC_PORT_FORWARD */
        {{0xffbb0000, 0xfcff0000, 0xfcff2000, EMAC_NONE}},      /* EMAC_PORT_FORWARD_WO_LEARNING */
        {{0xffff0001, EMAC_NONE,  EMAC_NONE, EMAC_NONE}},       /* ACCEPT ALL */
        {{0xfffe0002, EMAC_NONE,  EMAC_NONE, EMAC_NONE}},       /* ACCEPT TAGGED */
index 410612f43cbd0a5c979c50f021a4e6dff63a58a5..4914d0ef58e9b969dc82401be4922a0d13b4e9ad 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 bb0b33927e3b8253619b031ecf11d843d80fe293..3dbadddd7e355bc5381e65c64827b6f372778cbb 100644 (file)
@@ -9,6 +9,9 @@
 #include "icssg_stats.h"
 #include <linux/regmap.h>
 
+#define ICSSG_TX_PACKET_OFFSET 0xA0
+#define ICSSG_TX_BYTE_OFFSET   0xEC
+
 static u32 stats_base[] = {    0x54c,  /* Slice 0 stats start */
                                0xb18,  /* Slice 1 stats start */
 };
@@ -18,6 +21,7 @@ void emac_update_hardware_stats(struct prueth_emac *emac)
        struct prueth *prueth = emac->prueth;
        int slice = prueth_emac_slice(emac);
        u32 base = stats_base[slice];
+       u32 tx_pkt_cnt = 0;
        u32 val;
        int i;
 
@@ -29,7 +33,12 @@ void emac_update_hardware_stats(struct prueth_emac *emac)
                             base + icssg_all_stats[i].offset,
                             val);
 
+               if (icssg_all_stats[i].offset == ICSSG_TX_PACKET_OFFSET)
+                       tx_pkt_cnt = val;
+
                emac->stats[i] += val;
+               if (icssg_all_stats[i].offset == ICSSG_TX_BYTE_OFFSET)
+                       emac->stats[i] -= tx_pkt_cnt * 8;
        }
 }
 
index 38cc12f9f13324036948be2b6b67b9386fbb1a2d..05cc7aab1ec86402b7e327c5cc1a599f4883262b 100644 (file)
@@ -39,6 +39,7 @@ void k3_cppi_desc_pool_destroy(struct k3_cppi_desc_pool *pool)
 
        gen_pool_destroy(pool->gen_pool);       /* frees pool->name */
 }
+EXPORT_SYMBOL_GPL(k3_cppi_desc_pool_destroy);
 
 struct k3_cppi_desc_pool *
 k3_cppi_desc_pool_create_name(struct device *dev, size_t size,
@@ -98,29 +99,38 @@ gen_pool_create_fail:
        devm_kfree(pool->dev, pool);
        return ERR_PTR(ret);
 }
+EXPORT_SYMBOL_GPL(k3_cppi_desc_pool_create_name);
 
 dma_addr_t k3_cppi_desc_pool_virt2dma(struct k3_cppi_desc_pool *pool,
                                      void *addr)
 {
        return addr ? pool->dma_addr + (addr - pool->cpumem) : 0;
 }
+EXPORT_SYMBOL_GPL(k3_cppi_desc_pool_virt2dma);
 
 void *k3_cppi_desc_pool_dma2virt(struct k3_cppi_desc_pool *pool, dma_addr_t dma)
 {
        return dma ? pool->cpumem + (dma - pool->dma_addr) : NULL;
 }
+EXPORT_SYMBOL_GPL(k3_cppi_desc_pool_dma2virt);
 
 void *k3_cppi_desc_pool_alloc(struct k3_cppi_desc_pool *pool)
 {
        return (void *)gen_pool_alloc(pool->gen_pool, pool->desc_size);
 }
+EXPORT_SYMBOL_GPL(k3_cppi_desc_pool_alloc);
 
 void k3_cppi_desc_pool_free(struct k3_cppi_desc_pool *pool, void *addr)
 {
        gen_pool_free(pool->gen_pool, (unsigned long)addr, pool->desc_size);
 }
+EXPORT_SYMBOL_GPL(k3_cppi_desc_pool_free);
 
 size_t k3_cppi_desc_pool_avail(struct k3_cppi_desc_pool *pool)
 {
        return gen_pool_avail(pool->gen_pool) / pool->desc_size;
 }
+EXPORT_SYMBOL_GPL(k3_cppi_desc_pool_avail);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("TI K3 CPPI5 descriptors pool API");
index dc14a66583ff37680f85619762f5cf504b2c7f66..44488c153ea25fa9431f4a94e7225c909a3241d1 100644 (file)
@@ -1217,7 +1217,7 @@ static int gelic_wl_set_encodeext(struct net_device *netdev,
                key_index = wl->current_key;
 
        if (!enc->length && (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)) {
-               /* reques to change default key index */
+               /* request to change default key index */
                pr_debug("%s: request to change default key to %d\n",
                         __func__, key_index);
                wl->current_key = key_index;
index 144ec626230d6b0c4b60e9404d985aa569839309..b22596b18ee8c52a17df7859fddb9ddb5de9a213 100644 (file)
@@ -872,8 +872,9 @@ static int gtp_build_skb_ip4(struct sk_buff *skb, struct net_device *dev,
 
        skb_dst_update_pmtu_no_confirm(skb, mtu);
 
-       if (!skb_is_gso(skb) && (iph->frag_off & htons(IP_DF)) &&
-           mtu < ntohs(iph->tot_len)) {
+       if (iph->frag_off & htons(IP_DF) &&
+           ((!skb_is_gso(skb) && skb->len > mtu) ||
+            (skb_is_gso(skb) && !skb_gso_validate_network_len(skb, mtu)))) {
                netdev_dbg(dev, "packet too big, fragmentation needed\n");
                icmp_ndo_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
                              htonl(mtu));
index a03490ba2e5b38a798fbd6cee5a451d16990de60..cc7ddc40020fd7e4b7f78d073a2705fcc39754bd 100644 (file)
@@ -1162,9 +1162,10 @@ static int adf7242_stats_show(struct seq_file *file, void *offset)
 
 static void adf7242_debugfs_init(struct adf7242_local *lp)
 {
-       char debugfs_dir_name[DNAME_INLINE_LEN + 1] = "adf7242-";
+       char debugfs_dir_name[DNAME_INLINE_LEN + 1];
 
-       strncat(debugfs_dir_name, dev_name(&lp->spi->dev), DNAME_INLINE_LEN);
+       snprintf(debugfs_dir_name, sizeof(debugfs_dir_name),
+                "adf7242-%s", dev_name(&lp->spi->dev));
 
        lp->debugfs_root = debugfs_create_dir(debugfs_dir_name, NULL);
 
index aebb19f1b3a41ee2d3a39590715df63d85a983ff..4ec0dab388729950b79093d18236639d0583cd2a 100644 (file)
@@ -2740,7 +2740,6 @@ static int ca8210_register_ext_clock(struct spi_device *spi)
        struct device_node *np = spi->dev.of_node;
        struct ca8210_priv *priv = spi_get_drvdata(spi);
        struct ca8210_platform_data *pdata = spi->dev.platform_data;
-       int ret = 0;
 
        if (!np)
                return -EFAULT;
@@ -2757,18 +2756,8 @@ static int ca8210_register_ext_clock(struct spi_device *spi)
                dev_crit(&spi->dev, "Failed to register external clk\n");
                return PTR_ERR(priv->clk);
        }
-       ret = of_clk_add_provider(np, of_clk_src_simple_get, priv->clk);
-       if (ret) {
-               clk_unregister(priv->clk);
-               dev_crit(
-                       &spi->dev,
-                       "Failed to register external clock as clock provider\n"
-               );
-       } else {
-               dev_info(&spi->dev, "External clock set as clock provider\n");
-       }
 
-       return ret;
+       return of_clk_add_provider(np, of_clk_src_simple_get, priv->clk);
 }
 
 /**
@@ -2780,8 +2769,8 @@ static void ca8210_unregister_ext_clock(struct spi_device *spi)
 {
        struct ca8210_priv *priv = spi_get_drvdata(spi);
 
-       if (!priv->clk)
-               return
+       if (IS_ERR_OR_NULL(priv->clk))
+               return;
 
        of_clk_del_provider(spi->dev.of_node);
        clk_unregister(priv->clk);
index b7e151439c4886f851ba87e27a34e33cd834069a..c5cd4551c67ca38590ec1c7af9bbe3b9596b6490 100644 (file)
@@ -2383,6 +2383,7 @@ static int macsec_upd_txsa(struct sk_buff *skb, struct genl_info *info)
 
                ctx.sa.assoc_num = assoc_num;
                ctx.sa.tx_sa = tx_sa;
+               ctx.sa.update_pn = !!prev_pn.full64;
                ctx.secy = secy;
 
                ret = macsec_offload(ops->mdo_upd_txsa, &ctx);
@@ -2476,6 +2477,7 @@ static int macsec_upd_rxsa(struct sk_buff *skb, struct genl_info *info)
 
                ctx.sa.assoc_num = assoc_num;
                ctx.sa.rx_sa = rx_sa;
+               ctx.sa.update_pn = !!prev_pn.full64;
                ctx.secy = secy;
 
                ret = macsec_offload(ops->mdo_upd_rxsa, &ctx);
index a881e3523328313f3e98fb539693745b2f815e27..bef4cce71287cea465fc0301b0a12b10bbf0ab15 100644 (file)
@@ -55,6 +55,27 @@ out:
        return r;
 }
 
+static int mdio_mux_read_c45(struct mii_bus *bus, int phy_id, int dev_addr,
+                            int regnum)
+{
+       struct mdio_mux_child_bus *cb = bus->priv;
+       struct mdio_mux_parent_bus *pb = cb->parent;
+       int r;
+
+       mutex_lock_nested(&pb->mii_bus->mdio_lock, MDIO_MUTEX_MUX);
+       r = pb->switch_fn(pb->current_child, cb->bus_number, pb->switch_data);
+       if (r)
+               goto out;
+
+       pb->current_child = cb->bus_number;
+
+       r = pb->mii_bus->read_c45(pb->mii_bus, phy_id, dev_addr, regnum);
+out:
+       mutex_unlock(&pb->mii_bus->mdio_lock);
+
+       return r;
+}
+
 /*
  * The parent bus' lock is used to order access to the switch_fn.
  */
@@ -80,6 +101,28 @@ out:
        return r;
 }
 
+static int mdio_mux_write_c45(struct mii_bus *bus, int phy_id, int dev_addr,
+                             int regnum, u16 val)
+{
+       struct mdio_mux_child_bus *cb = bus->priv;
+       struct mdio_mux_parent_bus *pb = cb->parent;
+
+       int r;
+
+       mutex_lock_nested(&pb->mii_bus->mdio_lock, MDIO_MUTEX_MUX);
+       r = pb->switch_fn(pb->current_child, cb->bus_number, pb->switch_data);
+       if (r)
+               goto out;
+
+       pb->current_child = cb->bus_number;
+
+       r = pb->mii_bus->write_c45(pb->mii_bus, phy_id, dev_addr, regnum, val);
+out:
+       mutex_unlock(&pb->mii_bus->mdio_lock);
+
+       return r;
+}
+
 static int parent_count;
 
 static void mdio_mux_uninit_children(struct mdio_mux_parent_bus *pb)
@@ -173,6 +216,10 @@ int mdio_mux_init(struct device *dev,
                cb->mii_bus->parent = dev;
                cb->mii_bus->read = mdio_mux_read;
                cb->mii_bus->write = mdio_mux_write;
+               if (parent_bus->read_c45)
+                       cb->mii_bus->read_c45 = mdio_mux_read_c45;
+               if (parent_bus->write_c45)
+                       cb->mii_bus->write_c45 = mdio_mux_write_c45;
                r = of_mdiobus_register(cb->mii_bus, child_bus_node);
                if (r) {
                        mdiobus_free(cb->mii_bus);
index 8478b081c058da1022454b7d8f54f7b87147b479..97638ba7ae851d693710e2b508b658bb81ad2c28 100644 (file)
@@ -894,6 +894,9 @@ static int bcm7xxx_28nm_probe(struct phy_device *phydev)
        .name           = _name,                                        \
        /* PHY_BASIC_FEATURES */                                        \
        .flags          = PHY_IS_INTERNAL,                              \
+       .get_sset_count = bcm_phy_get_sset_count,                       \
+       .get_strings    = bcm_phy_get_strings,                          \
+       .get_stats      = bcm7xxx_28nm_get_phy_stats,                   \
        .probe          = bcm7xxx_28nm_probe,                           \
        .config_init    = bcm7xxx_16nm_ephy_config_init,                \
        .config_aneg    = genphy_config_aneg,                           \
index 018253a573b888c4312677f18bfeca6098e59316..4f39ba63a9a912caee8e1b59c6f21d55f91fabf4 100644 (file)
@@ -849,6 +849,9 @@ static int vsc8584_macsec_upd_rxsa(struct macsec_context *ctx)
        struct macsec_flow *flow;
        int ret;
 
+       if (ctx->sa.update_pn)
+               return -EINVAL;
+
        flow = vsc8584_macsec_find_flow(ctx, MACSEC_INGR);
        if (IS_ERR(flow))
                return PTR_ERR(flow);
@@ -900,6 +903,9 @@ static int vsc8584_macsec_upd_txsa(struct macsec_context *ctx)
        struct macsec_flow *flow;
        int ret;
 
+       if (ctx->sa.update_pn)
+               return -EINVAL;
+
        flow = vsc8584_macsec_find_flow(ctx, MACSEC_EGR);
        if (IS_ERR(flow))
                return PTR_ERR(flow);
index e8b94580194e719184527cf8d2fc9e138afdebb2..508d9a392ab182c4809019e73fd2b658fd1d66de 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 0c1e8970ee589fde200ba494f79ed48ce499ae7a..0a53ec293d0408b591467baca93e1e1ff0999191 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 89ab9efe522c30bd167d690f60c6b18fc29680a5..afa5497f7c35c3ab5682e66440afc8a888d14414 100644 (file)
@@ -3073,10 +3073,11 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
        struct net *net = sock_net(&tfile->sk);
        struct tun_struct *tun;
        void __user* argp = (void __user*)arg;
-       unsigned int ifindex, carrier;
+       unsigned int carrier;
        struct ifreq ifr;
        kuid_t owner;
        kgid_t group;
+       int ifindex;
        int sndbuf;
        int vnet_hdr_sz;
        int le;
@@ -3132,7 +3133,9 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
                ret = -EFAULT;
                if (copy_from_user(&ifindex, argp, sizeof(ifindex)))
                        goto unlock;
-
+               ret = -EINVAL;
+               if (ifindex < 0)
+                       goto unlock;
                ret = 0;
                tfile->ifindex = ifindex;
                goto unlock;
index 48d7d278631e9188e354250cc4922dc9846b5d24..99ec1d4a972db8c1232ce8ee8eb8d97385a9b5f0 100644 (file)
@@ -222,13 +222,18 @@ static int dm9601_mdio_read(struct net_device *netdev, int phy_id, int loc)
        struct usbnet *dev = netdev_priv(netdev);
 
        __le16 res;
+       int err;
 
        if (phy_id) {
                netdev_dbg(dev->net, "Only internal phy supported\n");
                return 0;
        }
 
-       dm_read_shared_word(dev, 1, loc, &res);
+       err = dm_read_shared_word(dev, 1, loc, &res);
+       if (err < 0) {
+               netdev_err(dev->net, "MDIO read error: %d\n", err);
+               return err;
+       }
 
        netdev_dbg(dev->net,
                   "dm9601_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n",
index 0c13d9950cd85502e35c1c26da43d95582a08314..afb20c0ed688d8dd8f5b4ca0688489a00db935b4 100644 (file)
@@ -764,7 +764,7 @@ enum rtl_register_content {
 
 /* rtl8152 flags */
 enum rtl8152_flags {
-       RTL8152_UNPLUG = 0,
+       RTL8152_INACCESSIBLE = 0,
        RTL8152_SET_RX_MODE,
        WORK_ENABLE,
        RTL8152_LINK_CHG,
@@ -773,6 +773,9 @@ enum rtl8152_flags {
        SCHEDULE_TASKLET,
        GREEN_ETHERNET,
        RX_EPROTO,
+       IN_PRE_RESET,
+       PROBED_WITH_NO_ERRORS,
+       PROBE_SHOULD_RETRY,
 };
 
 #define DEVICE_ID_LENOVO_USB_C_TRAVEL_HUB              0x721e
@@ -953,6 +956,8 @@ struct r8152 {
        u8 version;
        u8 duplex;
        u8 autoneg;
+
+       unsigned int reg_access_reset_count;
 };
 
 /**
@@ -1200,6 +1205,96 @@ static unsigned int agg_buf_sz = 16384;
 
 #define RTL_LIMITED_TSO_SIZE   (size_to_mtu(agg_buf_sz) - sizeof(struct tx_desc))
 
+/* If register access fails then we block access and issue a reset. If this
+ * happens too many times in a row without a successful access then we stop
+ * trying to reset and just leave access blocked.
+ */
+#define REGISTER_ACCESS_MAX_RESETS     3
+
+static void rtl_set_inaccessible(struct r8152 *tp)
+{
+       set_bit(RTL8152_INACCESSIBLE, &tp->flags);
+       smp_mb__after_atomic();
+}
+
+static void rtl_set_accessible(struct r8152 *tp)
+{
+       clear_bit(RTL8152_INACCESSIBLE, &tp->flags);
+       smp_mb__after_atomic();
+}
+
+static
+int r8152_control_msg(struct r8152 *tp, unsigned int pipe, __u8 request,
+                     __u8 requesttype, __u16 value, __u16 index, void *data,
+                     __u16 size, const char *msg_tag)
+{
+       struct usb_device *udev = tp->udev;
+       int ret;
+
+       if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
+               return -ENODEV;
+
+       ret = usb_control_msg(udev, pipe, request, requesttype,
+                             value, index, data, size,
+                             USB_CTRL_GET_TIMEOUT);
+
+       /* No need to issue a reset to report an error if the USB device got
+        * unplugged; just return immediately.
+        */
+       if (ret == -ENODEV)
+               return ret;
+
+       /* If the write was successful then we're done */
+       if (ret >= 0) {
+               tp->reg_access_reset_count = 0;
+               return ret;
+       }
+
+       dev_err(&udev->dev,
+               "Failed to %s %d bytes at %#06x/%#06x (%d)\n",
+               msg_tag, size, value, index, ret);
+
+       /* Block all future register access until we reset. Much of the code
+        * in the driver doesn't check for errors. Notably, many parts of the
+        * driver do a read/modify/write of a register value without
+        * confirming that the read succeeded. Writing back modified garbage
+        * like this can fully wedge the adapter, requiring a power cycle.
+        */
+       rtl_set_inaccessible(tp);
+
+       /* If probe hasn't yet finished, then we'll request a retry of the
+        * whole probe routine if we get any control transfer errors. We
+        * never have to clear this bit since we free/reallocate the whole "tp"
+        * structure if we retry probe.
+        */
+       if (!test_bit(PROBED_WITH_NO_ERRORS, &tp->flags)) {
+               set_bit(PROBE_SHOULD_RETRY, &tp->flags);
+               return ret;
+       }
+
+       /* Failing to access registers in pre-reset is not surprising since we
+        * wouldn't be resetting if things were behaving normally. The register
+        * access we do in pre-reset isn't truly mandatory--we're just reusing
+        * the disable() function and trying to be nice by powering the
+        * adapter down before resetting it. Thus, if we're in pre-reset,
+        * we'll return right away and not try to queue up yet another reset.
+        * We know the post-reset is already coming.
+        */
+       if (test_bit(IN_PRE_RESET, &tp->flags))
+               return ret;
+
+       if (tp->reg_access_reset_count < REGISTER_ACCESS_MAX_RESETS) {
+               usb_queue_reset_device(tp->intf);
+               tp->reg_access_reset_count++;
+       } else if (tp->reg_access_reset_count == REGISTER_ACCESS_MAX_RESETS) {
+               dev_err(&udev->dev,
+                       "Tried to reset %d times; giving up.\n",
+                       REGISTER_ACCESS_MAX_RESETS);
+       }
+
+       return ret;
+}
+
 static
 int get_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data)
 {
@@ -1210,9 +1305,10 @@ int get_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data)
        if (!tmp)
                return -ENOMEM;
 
-       ret = usb_control_msg(tp->udev, tp->pipe_ctrl_in,
-                             RTL8152_REQ_GET_REGS, RTL8152_REQT_READ,
-                             value, index, tmp, size, 500);
+       ret = r8152_control_msg(tp, tp->pipe_ctrl_in,
+                               RTL8152_REQ_GET_REGS, RTL8152_REQT_READ,
+                               value, index, tmp, size, "read");
+
        if (ret < 0)
                memset(data, 0xff, size);
        else
@@ -1233,9 +1329,9 @@ int set_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data)
        if (!tmp)
                return -ENOMEM;
 
-       ret = usb_control_msg(tp->udev, tp->pipe_ctrl_out,
-                             RTL8152_REQ_SET_REGS, RTL8152_REQT_WRITE,
-                             value, index, tmp, size, 500);
+       ret = r8152_control_msg(tp, tp->pipe_ctrl_out,
+                               RTL8152_REQ_SET_REGS, RTL8152_REQT_WRITE,
+                               value, index, tmp, size, "write");
 
        kfree(tmp);
 
@@ -1244,10 +1340,8 @@ int set_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data)
 
 static void rtl_set_unplug(struct r8152 *tp)
 {
-       if (tp->udev->state == USB_STATE_NOTATTACHED) {
-               set_bit(RTL8152_UNPLUG, &tp->flags);
-               smp_mb__after_atomic();
-       }
+       if (tp->udev->state == USB_STATE_NOTATTACHED)
+               rtl_set_inaccessible(tp);
 }
 
 static int generic_ocp_read(struct r8152 *tp, u16 index, u16 size,
@@ -1256,7 +1350,7 @@ static int generic_ocp_read(struct r8152 *tp, u16 index, u16 size,
        u16 limit = 64;
        int ret = 0;
 
-       if (test_bit(RTL8152_UNPLUG, &tp->flags))
+       if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
                return -ENODEV;
 
        /* both size and indix must be 4 bytes align */
@@ -1300,7 +1394,7 @@ static int generic_ocp_write(struct r8152 *tp, u16 index, u16 byteen,
        u16 byteen_start, byteen_end, byen;
        u16 limit = 512;
 
-       if (test_bit(RTL8152_UNPLUG, &tp->flags))
+       if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
                return -ENODEV;
 
        /* both size and indix must be 4 bytes align */
@@ -1537,7 +1631,7 @@ static int read_mii_word(struct net_device *netdev, int phy_id, int reg)
        struct r8152 *tp = netdev_priv(netdev);
        int ret;
 
-       if (test_bit(RTL8152_UNPLUG, &tp->flags))
+       if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
                return -ENODEV;
 
        if (phy_id != R8152_PHY_ID)
@@ -1553,7 +1647,7 @@ void write_mii_word(struct net_device *netdev, int phy_id, int reg, int val)
 {
        struct r8152 *tp = netdev_priv(netdev);
 
-       if (test_bit(RTL8152_UNPLUG, &tp->flags))
+       if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
                return;
 
        if (phy_id != R8152_PHY_ID)
@@ -1758,7 +1852,7 @@ static void read_bulk_callback(struct urb *urb)
        if (!tp)
                return;
 
-       if (test_bit(RTL8152_UNPLUG, &tp->flags))
+       if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
                return;
 
        if (!test_bit(WORK_ENABLE, &tp->flags))
@@ -1850,7 +1944,7 @@ static void write_bulk_callback(struct urb *urb)
        if (!test_bit(WORK_ENABLE, &tp->flags))
                return;
 
-       if (test_bit(RTL8152_UNPLUG, &tp->flags))
+       if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
                return;
 
        if (!skb_queue_empty(&tp->tx_queue))
@@ -1871,7 +1965,7 @@ static void intr_callback(struct urb *urb)
        if (!test_bit(WORK_ENABLE, &tp->flags))
                return;
 
-       if (test_bit(RTL8152_UNPLUG, &tp->flags))
+       if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
                return;
 
        switch (status) {
@@ -2615,7 +2709,7 @@ static void bottom_half(struct tasklet_struct *t)
 {
        struct r8152 *tp = from_tasklet(tp, t, tx_tl);
 
-       if (test_bit(RTL8152_UNPLUG, &tp->flags))
+       if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
                return;
 
        if (!test_bit(WORK_ENABLE, &tp->flags))
@@ -2658,7 +2752,7 @@ int r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags)
        int ret;
 
        /* The rx would be stopped, so skip submitting */
-       if (test_bit(RTL8152_UNPLUG, &tp->flags) ||
+       if (test_bit(RTL8152_INACCESSIBLE, &tp->flags) ||
            !test_bit(WORK_ENABLE, &tp->flags) || !netif_carrier_ok(tp->netdev))
                return 0;
 
@@ -3058,7 +3152,7 @@ static int rtl_enable(struct r8152 *tp)
 
 static int rtl8152_enable(struct r8152 *tp)
 {
-       if (test_bit(RTL8152_UNPLUG, &tp->flags))
+       if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
                return -ENODEV;
 
        set_tx_qlen(tp);
@@ -3145,7 +3239,7 @@ static int rtl8153_enable(struct r8152 *tp)
 {
        u32 ocp_data;
 
-       if (test_bit(RTL8152_UNPLUG, &tp->flags))
+       if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
                return -ENODEV;
 
        set_tx_qlen(tp);
@@ -3177,7 +3271,7 @@ static void rtl_disable(struct r8152 *tp)
        u32 ocp_data;
        int i;
 
-       if (test_bit(RTL8152_UNPLUG, &tp->flags)) {
+       if (test_bit(RTL8152_INACCESSIBLE, &tp->flags)) {
                rtl_drop_queued_tx(tp);
                return;
        }
@@ -3631,7 +3725,7 @@ static u16 r8153_phy_status(struct r8152 *tp, u16 desired)
                }
 
                msleep(20);
-               if (test_bit(RTL8152_UNPLUG, &tp->flags))
+               if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
                        break;
        }
 
@@ -3663,6 +3757,8 @@ static void r8153b_ups_en(struct r8152 *tp, bool enable)
                        int i;
 
                        for (i = 0; i < 500; i++) {
+                               if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
+                                       return;
                                if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_BOOT_CTRL) &
                                    AUTOLOAD_DONE)
                                        break;
@@ -3703,6 +3799,8 @@ static void r8153c_ups_en(struct r8152 *tp, bool enable)
                        int i;
 
                        for (i = 0; i < 500; i++) {
+                               if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
+                                       return;
                                if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_BOOT_CTRL) &
                                    AUTOLOAD_DONE)
                                        break;
@@ -4046,6 +4144,9 @@ static int rtl_phy_patch_request(struct r8152 *tp, bool request, bool wait)
        for (i = 0; wait && i < 5000; i++) {
                u32 ocp_data;
 
+               if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
+                       return -ENODEV;
+
                usleep_range(1000, 2000);
                ocp_data = ocp_reg_read(tp, OCP_PHY_PATCH_STAT);
                if ((ocp_data & PATCH_READY) ^ check)
@@ -6002,7 +6103,7 @@ static int rtl8156_enable(struct r8152 *tp)
        u32 ocp_data;
        u16 speed;
 
-       if (test_bit(RTL8152_UNPLUG, &tp->flags))
+       if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
                return -ENODEV;
 
        r8156_fc_parameter(tp);
@@ -6060,7 +6161,7 @@ static int rtl8156b_enable(struct r8152 *tp)
        u32 ocp_data;
        u16 speed;
 
-       if (test_bit(RTL8152_UNPLUG, &tp->flags))
+       if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
                return -ENODEV;
 
        set_tx_qlen(tp);
@@ -6246,7 +6347,7 @@ out:
 
 static void rtl8152_up(struct r8152 *tp)
 {
-       if (test_bit(RTL8152_UNPLUG, &tp->flags))
+       if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
                return;
 
        r8152_aldps_en(tp, false);
@@ -6256,7 +6357,7 @@ static void rtl8152_up(struct r8152 *tp)
 
 static void rtl8152_down(struct r8152 *tp)
 {
-       if (test_bit(RTL8152_UNPLUG, &tp->flags)) {
+       if (test_bit(RTL8152_INACCESSIBLE, &tp->flags)) {
                rtl_drop_queued_tx(tp);
                return;
        }
@@ -6271,7 +6372,7 @@ static void rtl8153_up(struct r8152 *tp)
 {
        u32 ocp_data;
 
-       if (test_bit(RTL8152_UNPLUG, &tp->flags))
+       if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
                return;
 
        r8153_u1u2en(tp, false);
@@ -6311,7 +6412,7 @@ static void rtl8153_down(struct r8152 *tp)
 {
        u32 ocp_data;
 
-       if (test_bit(RTL8152_UNPLUG, &tp->flags)) {
+       if (test_bit(RTL8152_INACCESSIBLE, &tp->flags)) {
                rtl_drop_queued_tx(tp);
                return;
        }
@@ -6332,7 +6433,7 @@ static void rtl8153b_up(struct r8152 *tp)
 {
        u32 ocp_data;
 
-       if (test_bit(RTL8152_UNPLUG, &tp->flags))
+       if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
                return;
 
        r8153b_u1u2en(tp, false);
@@ -6356,7 +6457,7 @@ static void rtl8153b_down(struct r8152 *tp)
 {
        u32 ocp_data;
 
-       if (test_bit(RTL8152_UNPLUG, &tp->flags)) {
+       if (test_bit(RTL8152_INACCESSIBLE, &tp->flags)) {
                rtl_drop_queued_tx(tp);
                return;
        }
@@ -6393,7 +6494,7 @@ static void rtl8153c_up(struct r8152 *tp)
 {
        u32 ocp_data;
 
-       if (test_bit(RTL8152_UNPLUG, &tp->flags))
+       if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
                return;
 
        r8153b_u1u2en(tp, false);
@@ -6474,7 +6575,7 @@ static void rtl8156_up(struct r8152 *tp)
 {
        u32 ocp_data;
 
-       if (test_bit(RTL8152_UNPLUG, &tp->flags))
+       if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
                return;
 
        r8153b_u1u2en(tp, false);
@@ -6547,7 +6648,7 @@ static void rtl8156_down(struct r8152 *tp)
 {
        u32 ocp_data;
 
-       if (test_bit(RTL8152_UNPLUG, &tp->flags)) {
+       if (test_bit(RTL8152_INACCESSIBLE, &tp->flags)) {
                rtl_drop_queued_tx(tp);
                return;
        }
@@ -6685,7 +6786,7 @@ static void rtl_work_func_t(struct work_struct *work)
        /* If the device is unplugged or !netif_running(), the workqueue
         * doesn't need to wake the device, and could return directly.
         */
-       if (test_bit(RTL8152_UNPLUG, &tp->flags) || !netif_running(tp->netdev))
+       if (test_bit(RTL8152_INACCESSIBLE, &tp->flags) || !netif_running(tp->netdev))
                return;
 
        if (usb_autopm_get_interface(tp->intf) < 0)
@@ -6724,7 +6825,7 @@ static void rtl_hw_phy_work_func_t(struct work_struct *work)
 {
        struct r8152 *tp = container_of(work, struct r8152, hw_phy_work.work);
 
-       if (test_bit(RTL8152_UNPLUG, &tp->flags))
+       if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
                return;
 
        if (usb_autopm_get_interface(tp->intf) < 0)
@@ -6851,7 +6952,7 @@ static int rtl8152_close(struct net_device *netdev)
        netif_stop_queue(netdev);
 
        res = usb_autopm_get_interface(tp->intf);
-       if (res < 0 || test_bit(RTL8152_UNPLUG, &tp->flags)) {
+       if (res < 0 || test_bit(RTL8152_INACCESSIBLE, &tp->flags)) {
                rtl_drop_queued_tx(tp);
                rtl_stop_rx(tp);
        } else {
@@ -6884,7 +6985,7 @@ static void r8152b_init(struct r8152 *tp)
        u32 ocp_data;
        u16 data;
 
-       if (test_bit(RTL8152_UNPLUG, &tp->flags))
+       if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
                return;
 
        data = r8152_mdio_read(tp, MII_BMCR);
@@ -6928,7 +7029,7 @@ static void r8153_init(struct r8152 *tp)
        u16 data;
        int i;
 
-       if (test_bit(RTL8152_UNPLUG, &tp->flags))
+       if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
                return;
 
        r8153_u1u2en(tp, false);
@@ -6939,7 +7040,7 @@ static void r8153_init(struct r8152 *tp)
                        break;
 
                msleep(20);
-               if (test_bit(RTL8152_UNPLUG, &tp->flags))
+               if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
                        break;
        }
 
@@ -7068,7 +7169,7 @@ static void r8153b_init(struct r8152 *tp)
        u16 data;
        int i;
 
-       if (test_bit(RTL8152_UNPLUG, &tp->flags))
+       if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
                return;
 
        r8153b_u1u2en(tp, false);
@@ -7079,7 +7180,7 @@ static void r8153b_init(struct r8152 *tp)
                        break;
 
                msleep(20);
-               if (test_bit(RTL8152_UNPLUG, &tp->flags))
+               if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
                        break;
        }
 
@@ -7150,7 +7251,7 @@ static void r8153c_init(struct r8152 *tp)
        u16 data;
        int i;
 
-       if (test_bit(RTL8152_UNPLUG, &tp->flags))
+       if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
                return;
 
        r8153b_u1u2en(tp, false);
@@ -7170,7 +7271,7 @@ static void r8153c_init(struct r8152 *tp)
                        break;
 
                msleep(20);
-               if (test_bit(RTL8152_UNPLUG, &tp->flags))
+               if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
                        return;
        }
 
@@ -7999,7 +8100,7 @@ static void r8156_init(struct r8152 *tp)
        u16 data;
        int i;
 
-       if (test_bit(RTL8152_UNPLUG, &tp->flags))
+       if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
                return;
 
        ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_ECM_OP);
@@ -8020,7 +8121,7 @@ static void r8156_init(struct r8152 *tp)
                        break;
 
                msleep(20);
-               if (test_bit(RTL8152_UNPLUG, &tp->flags))
+               if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
                        return;
        }
 
@@ -8095,7 +8196,7 @@ static void r8156b_init(struct r8152 *tp)
        u16 data;
        int i;
 
-       if (test_bit(RTL8152_UNPLUG, &tp->flags))
+       if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
                return;
 
        ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_ECM_OP);
@@ -8129,7 +8230,7 @@ static void r8156b_init(struct r8152 *tp)
                        break;
 
                msleep(20);
-               if (test_bit(RTL8152_UNPLUG, &tp->flags))
+               if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
                        return;
        }
 
@@ -8255,7 +8356,7 @@ static int rtl8152_pre_reset(struct usb_interface *intf)
        struct r8152 *tp = usb_get_intfdata(intf);
        struct net_device *netdev;
 
-       if (!tp)
+       if (!tp || !test_bit(PROBED_WITH_NO_ERRORS, &tp->flags))
                return 0;
 
        netdev = tp->netdev;
@@ -8270,7 +8371,9 @@ static int rtl8152_pre_reset(struct usb_interface *intf)
        napi_disable(&tp->napi);
        if (netif_carrier_ok(netdev)) {
                mutex_lock(&tp->control);
+               set_bit(IN_PRE_RESET, &tp->flags);
                tp->rtl_ops.disable(tp);
+               clear_bit(IN_PRE_RESET, &tp->flags);
                mutex_unlock(&tp->control);
        }
 
@@ -8283,9 +8386,11 @@ static int rtl8152_post_reset(struct usb_interface *intf)
        struct net_device *netdev;
        struct sockaddr sa;
 
-       if (!tp)
+       if (!tp || !test_bit(PROBED_WITH_NO_ERRORS, &tp->flags))
                return 0;
 
+       rtl_set_accessible(tp);
+
        /* reset the MAC address in case of policy change */
        if (determine_ethernet_addr(tp, &sa) >= 0) {
                rtnl_lock();
@@ -9158,7 +9263,7 @@ static int rtl8152_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
        struct mii_ioctl_data *data = if_mii(rq);
        int res;
 
-       if (test_bit(RTL8152_UNPLUG, &tp->flags))
+       if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
                return -ENODEV;
 
        res = usb_autopm_get_interface(tp->intf);
@@ -9260,7 +9365,7 @@ static const struct net_device_ops rtl8152_netdev_ops = {
 
 static void rtl8152_unload(struct r8152 *tp)
 {
-       if (test_bit(RTL8152_UNPLUG, &tp->flags))
+       if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
                return;
 
        if (tp->version != RTL_VER_01)
@@ -9269,7 +9374,7 @@ static void rtl8152_unload(struct r8152 *tp)
 
 static void rtl8153_unload(struct r8152 *tp)
 {
-       if (test_bit(RTL8152_UNPLUG, &tp->flags))
+       if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
                return;
 
        r8153_power_cut_en(tp, false);
@@ -9277,7 +9382,7 @@ static void rtl8153_unload(struct r8152 *tp)
 
 static void rtl8153b_unload(struct r8152 *tp)
 {
-       if (test_bit(RTL8152_UNPLUG, &tp->flags))
+       if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
                return;
 
        r8153b_power_cut_en(tp, false);
@@ -9487,16 +9592,29 @@ static u8 __rtl_get_hw_ver(struct usb_device *udev)
        __le32 *tmp;
        u8 version;
        int ret;
+       int i;
 
        tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
        if (!tmp)
                return 0;
 
-       ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
-                             RTL8152_REQ_GET_REGS, RTL8152_REQT_READ,
-                             PLA_TCR0, MCU_TYPE_PLA, tmp, sizeof(*tmp), 500);
-       if (ret > 0)
-               ocp_data = (__le32_to_cpu(*tmp) >> 16) & VERSION_MASK;
+       /* Retry up to 3 times in case there is a transitory error. We do this
+        * since retrying a read of the version is always safe and this
+        * function doesn't take advantage of r8152_control_msg().
+        */
+       for (i = 0; i < 3; i++) {
+               ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+                                     RTL8152_REQ_GET_REGS, RTL8152_REQT_READ,
+                                     PLA_TCR0, MCU_TYPE_PLA, tmp, sizeof(*tmp),
+                                     USB_CTRL_GET_TIMEOUT);
+               if (ret > 0) {
+                       ocp_data = (__le32_to_cpu(*tmp) >> 16) & VERSION_MASK;
+                       break;
+               }
+       }
+
+       if (i != 0 && ret > 0)
+               dev_warn(&udev->dev, "Needed %d retries to read version\n", i);
 
        kfree(tmp);
 
@@ -9595,25 +9713,14 @@ static bool rtl8152_supports_lenovo_macpassthru(struct usb_device *udev)
        return 0;
 }
 
-static int rtl8152_probe(struct usb_interface *intf,
-                        const struct usb_device_id *id)
+static int rtl8152_probe_once(struct usb_interface *intf,
+                             const struct usb_device_id *id, u8 version)
 {
        struct usb_device *udev = interface_to_usbdev(intf);
        struct r8152 *tp;
        struct net_device *netdev;
-       u8 version;
        int ret;
 
-       if (intf->cur_altsetting->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC)
-               return -ENODEV;
-
-       if (!rtl_check_vendor_ok(intf))
-               return -ENODEV;
-
-       version = rtl8152_get_version(intf);
-       if (version == RTL_VER_UNKNOWN)
-               return -ENODEV;
-
        usb_reset_device(udev);
        netdev = alloc_etherdev(sizeof(struct r8152));
        if (!netdev) {
@@ -9776,18 +9883,68 @@ static int rtl8152_probe(struct usb_interface *intf,
        else
                device_set_wakeup_enable(&udev->dev, false);
 
+       /* If we saw a control transfer error while probing then we may
+        * want to try probe() again. Consider this an error.
+        */
+       if (test_bit(PROBE_SHOULD_RETRY, &tp->flags))
+               goto out2;
+
+       set_bit(PROBED_WITH_NO_ERRORS, &tp->flags);
        netif_info(tp, probe, netdev, "%s\n", DRIVER_VERSION);
 
        return 0;
 
+out2:
+       unregister_netdev(netdev);
+
 out1:
        tasklet_kill(&tp->tx_tl);
+       cancel_delayed_work_sync(&tp->hw_phy_work);
+       if (tp->rtl_ops.unload)
+               tp->rtl_ops.unload(tp);
+       rtl8152_release_firmware(tp);
        usb_set_intfdata(intf, NULL);
 out:
+       if (test_bit(PROBE_SHOULD_RETRY, &tp->flags))
+               ret = -EAGAIN;
+
        free_netdev(netdev);
        return ret;
 }
 
+#define RTL8152_PROBE_TRIES    3
+
+static int rtl8152_probe(struct usb_interface *intf,
+                        const struct usb_device_id *id)
+{
+       u8 version;
+       int ret;
+       int i;
+
+       if (intf->cur_altsetting->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC)
+               return -ENODEV;
+
+       if (!rtl_check_vendor_ok(intf))
+               return -ENODEV;
+
+       version = rtl8152_get_version(intf);
+       if (version == RTL_VER_UNKNOWN)
+               return -ENODEV;
+
+       for (i = 0; i < RTL8152_PROBE_TRIES; i++) {
+               ret = rtl8152_probe_once(intf, id, version);
+               if (ret != -EAGAIN)
+                       break;
+       }
+       if (ret == -EAGAIN) {
+               dev_err(&intf->dev,
+                       "r8152 failed probe after %d tries; giving up\n", i);
+               return -ENODEV;
+       }
+
+       return ret;
+}
+
 static void rtl8152_disconnect(struct usb_interface *intf)
 {
        struct r8152 *tp = usb_get_intfdata(intf);
index 5d6454fedb3f17707f7cd8a3b963da08e67c76c9..78ad2da3ee29b225f41eddc90b08d43257d01e8f 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 563ecd27b93ea56441daf150aecfa2f51219e6cc..a530f20ee257550141e5ec7c17b5fba0087db248 100644 (file)
@@ -95,7 +95,9 @@ static int __must_check smsc95xx_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 (ret < 0) {
+       if (ret < 4) {
+               ret = ret < 0 ? ret : -ENODATA;
+
                if (ret != -ENODEV)
                        netdev_warn(dev->net, "Failed to read reg index 0x%08x: %d\n",
                                    index, ret);
@@ -897,7 +899,7 @@ static int smsc95xx_reset(struct usbnet *dev)
 
        if (timeout >= 100) {
                netdev_warn(dev->net, "timeout waiting for completion of Lite Reset\n");
-               return ret;
+               return -ETIMEDOUT;
        }
 
        ret = smsc95xx_set_mac_address(dev);
index fe7f314d65c971fcad826fa0b3e44a956ef88940..d67f742fbd4c561d4b86ae37fbb62755628870fc 100644 (file)
@@ -607,16 +607,16 @@ static void virtnet_rq_unmap(struct receive_queue *rq, void *buf, u32 len)
 
        --dma->ref;
 
-       if (dma->ref) {
-               if (dma->need_sync && len) {
-                       offset = buf - (head + sizeof(*dma));
+       if (dma->need_sync && len) {
+               offset = buf - (head + sizeof(*dma));
 
-                       virtqueue_dma_sync_single_range_for_cpu(rq->vq, dma->addr, offset,
-                                                               len, DMA_FROM_DEVICE);
-               }
+               virtqueue_dma_sync_single_range_for_cpu(rq->vq, dma->addr,
+                                                       offset, len,
+                                                       DMA_FROM_DEVICE);
+       }
 
+       if (dma->ref)
                return;
-       }
 
        virtqueue_dma_unmap_single_attrs(rq->vq, dma->addr, dma->len,
                                         DMA_FROM_DEVICE, DMA_ATTR_SKIP_CPU_SYNC);
index e463f59e95c2535cef645939b156de7ae428ceb2..5b5597073b004c911f88b472748447804594c752 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 47c2ad7a3e429ae03fc732024728b113fe77d87e..fd50bb313b92448d6de580271d5cf76a0f717d15 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 bece26741d3a350a6e6eb08bf80c1478a4781751..611d1a6aabb9e5f9cf6787e23434665df0819e67 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 f5e08988dc7bfb24a2eecfb84917630427e6b0da..06d6f7f6643089a63ffbb458ab7f3be69aebc2b6 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 1f5db65a088d3b657dde7344b3bb2202358f760d..1d5ee4330f29f334475886c6b6e466dff2f65c44 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 8b6c641772ee6f697529cbd5eb9ff373b6639f22..b719843e94576e35e7ce2270136c15d5756ce4e4 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 c1d9ce75346882033495d1fbf3e42a59a0662ff2..3cbe2c0b8d6bcddd5416eae3d0c3524e0e149843 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 36d70d589aedda6511f3274cacc411cf5b483b38..898dca3936435cb162a61aa776e6999eed7f112f 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 391793a16adca3d40817ef1674219cbb43ca6d14..10690e82358b892f04327d41981d5eb7f5791309 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 f2168fac95ed1a82aa89fe53b9deb8ccae4e4bd3..8e6db904e5b2d895bb9aaad6a2431c1be2c2cc4c 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 65420ad6741679ec7c2cd8d24004c1ab1f8334db..257737137cd70fb1ed28737db7acafd364378464 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 05d9ab3ce819bbeb92f0457a5e36400c8ecf039e..dc8f4e157eb291bb0a38820c1bd1040a8356ee6f 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 0acabba2d1a50c5653f5866108998dac9f046632..5d402cf2951cb35c2aa5bd1dde0ca20a142a56dc 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 d5809408d1d3720fbfb7f7396242b5e5cae1301a..8c01855885ce3949a16e63fe4169db3345a62044 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 3642a2c7f80c984dc2111880b7ac3729cdaaea5a..2434e2480cbe27acb67b0d35514a6243727c44e8 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 635301d677e1869ee6c1cd70daf7fc2d7662ff58..829515a601b379d3acb57927b67076a35ebf16c9 100644 (file)
@@ -4,7 +4,6 @@
  */
 
 #include <linux/delay.h>
-#include <linux/pm_runtime.h>
 
 #include "iosm_ipc_chnl_cfg.h"
 #include "iosm_ipc_devlink.h"
@@ -632,11 +631,6 @@ static void ipc_imem_run_state_worker(struct work_struct *instance)
        /* Complete all memory stores after setting bit */
        smp_mb__after_atomic();
 
-       if (ipc_imem->pcie->pci->device == INTEL_CP_DEVICE_7560_ID) {
-               pm_runtime_mark_last_busy(ipc_imem->dev);
-               pm_runtime_put_autosuspend(ipc_imem->dev);
-       }
-
        return;
 
 err_ipc_mux_deinit:
@@ -1240,7 +1234,6 @@ void ipc_imem_cleanup(struct iosm_imem *ipc_imem)
 
        /* forward MDM_NOT_READY to listeners */
        ipc_uevent_send(ipc_imem->dev, UEVENT_MDM_NOT_READY);
-       pm_runtime_get_sync(ipc_imem->dev);
 
        hrtimer_cancel(&ipc_imem->td_alloc_timer);
        hrtimer_cancel(&ipc_imem->tdupdate_timer);
@@ -1426,16 +1419,6 @@ struct iosm_imem *ipc_imem_init(struct iosm_pcie *pcie, unsigned int device_id,
 
                set_bit(IOSM_DEVLINK_INIT, &ipc_imem->flag);
        }
-
-       if (!pm_runtime_enabled(ipc_imem->dev))
-               pm_runtime_enable(ipc_imem->dev);
-
-       pm_runtime_set_autosuspend_delay(ipc_imem->dev,
-                                        IPC_MEM_AUTO_SUSPEND_DELAY_MS);
-       pm_runtime_use_autosuspend(ipc_imem->dev);
-       pm_runtime_allow(ipc_imem->dev);
-       pm_runtime_mark_last_busy(ipc_imem->dev);
-
        return ipc_imem;
 devlink_channel_fail:
        ipc_devlink_deinit(ipc_imem->ipc_devlink);
index 0144b45e2afb39a7971ccfa5ecadf9a4ff396a8a..5664ac507c902e462073590593ecc8606086e41d 100644 (file)
@@ -103,8 +103,6 @@ struct ipc_chnl_cfg;
 #define FULLY_FUNCTIONAL 0
 #define IOSM_DEVLINK_INIT 1
 
-#define IPC_MEM_AUTO_SUSPEND_DELAY_MS 5000
-
 /* List of the supported UL/DL pipes. */
 enum ipc_mem_pipes {
        IPC_MEM_PIPE_0 = 0,
index 3a259c9abefdfaadce0afbac97ab26638aef3dfc..04517bd3325a2abb3871f640aab0666d53467352 100644 (file)
@@ -6,7 +6,6 @@
 #include <linux/acpi.h>
 #include <linux/bitfield.h>
 #include <linux/module.h>
-#include <linux/pm_runtime.h>
 #include <net/rtnetlink.h>
 
 #include "iosm_ipc_imem.h"
@@ -438,8 +437,7 @@ static int __maybe_unused ipc_pcie_resume_cb(struct device *dev)
        return 0;
 }
 
-static DEFINE_RUNTIME_DEV_PM_OPS(iosm_ipc_pm, ipc_pcie_suspend_cb,
-                                ipc_pcie_resume_cb, NULL);
+static SIMPLE_DEV_PM_OPS(iosm_ipc_pm, ipc_pcie_suspend_cb, ipc_pcie_resume_cb);
 
 static struct pci_driver iosm_ipc_driver = {
        .name = KBUILD_MODNAME,
index 2ba1ddca3945b2bb62c1f42fdee6f334a2afe35a..5d5b4183e14a3a1a50f9f7f9669779e3e8d1dc0d 100644 (file)
@@ -3,8 +3,6 @@
  * Copyright (C) 2020-21 Intel Corporation.
  */
 
-#include <linux/pm_runtime.h>
-
 #include "iosm_ipc_chnl_cfg.h"
 #include "iosm_ipc_imem_ops.h"
 #include "iosm_ipc_port.h"
@@ -15,16 +13,12 @@ static int ipc_port_ctrl_start(struct wwan_port *port)
        struct iosm_cdev *ipc_port = wwan_port_get_drvdata(port);
        int ret = 0;
 
-       pm_runtime_get_sync(ipc_port->ipc_imem->dev);
        ipc_port->channel = ipc_imem_sys_port_open(ipc_port->ipc_imem,
                                                   ipc_port->chl_id,
                                                   IPC_HP_CDEV_OPEN);
        if (!ipc_port->channel)
                ret = -EIO;
 
-       pm_runtime_mark_last_busy(ipc_port->ipc_imem->dev);
-       pm_runtime_put_autosuspend(ipc_port->ipc_imem->dev);
-
        return ret;
 }
 
@@ -33,24 +27,15 @@ static void ipc_port_ctrl_stop(struct wwan_port *port)
 {
        struct iosm_cdev *ipc_port = wwan_port_get_drvdata(port);
 
-       pm_runtime_get_sync(ipc_port->ipc_imem->dev);
        ipc_imem_sys_port_close(ipc_port->ipc_imem, ipc_port->channel);
-       pm_runtime_mark_last_busy(ipc_port->ipc_imem->dev);
-       pm_runtime_put_autosuspend(ipc_port->ipc_imem->dev);
 }
 
 /* transfer control data to modem */
 static int ipc_port_ctrl_tx(struct wwan_port *port, struct sk_buff *skb)
 {
        struct iosm_cdev *ipc_port = wwan_port_get_drvdata(port);
-       int ret;
 
-       pm_runtime_get_sync(ipc_port->ipc_imem->dev);
-       ret = ipc_imem_sys_cdev_write(ipc_port, skb);
-       pm_runtime_mark_last_busy(ipc_port->ipc_imem->dev);
-       pm_runtime_put_autosuspend(ipc_port->ipc_imem->dev);
-
-       return ret;
+       return ipc_imem_sys_cdev_write(ipc_port, skb);
 }
 
 static const struct wwan_port_ops ipc_wwan_ctrl_ops = {
index 4368373797b69bd92c26b68b2c6eea8ac8e1d4b2..eeecfa3d10c5abcaaea901280641fb2e39ec7f99 100644 (file)
@@ -3,9 +3,7 @@
  * Copyright (C) 2020-2021 Intel Corporation.
  */
 
-#include <linux/pm_runtime.h>
 #include <linux/wwan.h>
-
 #include "iosm_ipc_trace.h"
 
 /* sub buffer size and number of sub buffer */
@@ -99,8 +97,6 @@ static ssize_t ipc_trace_ctrl_file_write(struct file *filp,
        if (ret)
                return ret;
 
-       pm_runtime_get_sync(ipc_trace->ipc_imem->dev);
-
        mutex_lock(&ipc_trace->trc_mutex);
        if (val == TRACE_ENABLE && ipc_trace->mode != TRACE_ENABLE) {
                ipc_trace->channel = ipc_imem_sys_port_open(ipc_trace->ipc_imem,
@@ -121,10 +117,6 @@ static ssize_t ipc_trace_ctrl_file_write(struct file *filp,
        ret = count;
 unlock:
        mutex_unlock(&ipc_trace->trc_mutex);
-
-       pm_runtime_mark_last_busy(ipc_trace->ipc_imem->dev);
-       pm_runtime_put_autosuspend(ipc_trace->ipc_imem->dev);
-
        return ret;
 }
 
index 93d17de08786c209035af9d01cbf484cc9c1662a..ff747fc79aaf80f964a9513f524fb36c20907c0a 100644 (file)
@@ -6,7 +6,6 @@
 #include <linux/etherdevice.h>
 #include <linux/if_arp.h>
 #include <linux/if_link.h>
-#include <linux/pm_runtime.h>
 #include <linux/rtnetlink.h>
 #include <linux/wwan.h>
 #include <net/pkt_sched.h>
@@ -52,13 +51,11 @@ static int ipc_wwan_link_open(struct net_device *netdev)
        struct iosm_netdev_priv *priv = wwan_netdev_drvpriv(netdev);
        struct iosm_wwan *ipc_wwan = priv->ipc_wwan;
        int if_id = priv->if_id;
-       int ret = 0;
 
        if (if_id < IP_MUX_SESSION_START ||
            if_id >= ARRAY_SIZE(ipc_wwan->sub_netlist))
                return -EINVAL;
 
-       pm_runtime_get_sync(ipc_wwan->ipc_imem->dev);
        /* get channel id */
        priv->ch_id = ipc_imem_sys_wwan_open(ipc_wwan->ipc_imem, if_id);
 
@@ -66,8 +63,7 @@ static int ipc_wwan_link_open(struct net_device *netdev)
                dev_err(ipc_wwan->dev,
                        "cannot connect wwan0 & id %d to the IPC mem layer",
                        if_id);
-               ret = -ENODEV;
-               goto err_out;
+               return -ENODEV;
        }
 
        /* enable tx path, DL data may follow */
@@ -76,11 +72,7 @@ static int ipc_wwan_link_open(struct net_device *netdev)
        dev_dbg(ipc_wwan->dev, "Channel id %d allocated to if_id %d",
                priv->ch_id, priv->if_id);
 
-err_out:
-       pm_runtime_mark_last_busy(ipc_wwan->ipc_imem->dev);
-       pm_runtime_put_autosuspend(ipc_wwan->ipc_imem->dev);
-
-       return ret;
+       return 0;
 }
 
 /* Bring-down the wwan net link */
@@ -90,12 +82,9 @@ static int ipc_wwan_link_stop(struct net_device *netdev)
 
        netif_stop_queue(netdev);
 
-       pm_runtime_get_sync(priv->ipc_wwan->ipc_imem->dev);
        ipc_imem_sys_wwan_close(priv->ipc_wwan->ipc_imem, priv->if_id,
                                priv->ch_id);
        priv->ch_id = -1;
-       pm_runtime_mark_last_busy(priv->ipc_wwan->ipc_imem->dev);
-       pm_runtime_put_autosuspend(priv->ipc_wwan->ipc_imem->dev);
 
        return 0;
 }
@@ -117,7 +106,6 @@ static netdev_tx_t ipc_wwan_link_transmit(struct sk_buff *skb,
            if_id >= ARRAY_SIZE(ipc_wwan->sub_netlist))
                return -EINVAL;
 
-       pm_runtime_get(ipc_wwan->ipc_imem->dev);
        /* Send the SKB to device for transmission */
        ret = ipc_imem_sys_wwan_transmit(ipc_wwan->ipc_imem,
                                         if_id, priv->ch_id, skb);
@@ -131,14 +119,9 @@ static netdev_tx_t ipc_wwan_link_transmit(struct sk_buff *skb,
                ret = NETDEV_TX_BUSY;
                dev_err(ipc_wwan->dev, "unable to push packets");
        } else {
-               pm_runtime_mark_last_busy(ipc_wwan->ipc_imem->dev);
-               pm_runtime_put_autosuspend(ipc_wwan->ipc_imem->dev);
                goto exit;
        }
 
-       pm_runtime_mark_last_busy(ipc_wwan->ipc_imem->dev);
-       pm_runtime_put_autosuspend(ipc_wwan->ipc_imem->dev);
-
        return ret;
 
 exit:
index f3f2c07423a6ac34f7266d68c65b52c38c961727..fc3bb63b9ac3e5f916811c819dd4ca3a03b9bce0 100644 (file)
@@ -41,8 +41,6 @@
 #include <asm/xen/hypercall.h>
 #include <xen/balloon.h>
 
-#define XENVIF_QUEUE_LENGTH 32
-
 /* Number of bytes allowed on the internal guest Rx queue. */
 #define XENVIF_RX_QUEUE_BYTES (XEN_NETIF_RX_RING_SIZE/2 * PAGE_SIZE)
 
@@ -530,8 +528,6 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t domid,
        dev->features = dev->hw_features | NETIF_F_RXCSUM;
        dev->ethtool_ops = &xenvif_ethtool_ops;
 
-       dev->tx_queue_len = XENVIF_QUEUE_LENGTH;
-
        dev->min_mtu = ETH_MIN_MTU;
        dev->max_mtu = ETH_MAX_MTU - VLAN_ETH_HLEN;
 
index daf5d144a8eaf79f75feae225af1a57ea586ad81..064592a5d546a6fee06c7b6f99a8edef9cbc48b7 100644 (file)
@@ -341,7 +341,7 @@ static int nvme_auth_process_dhchap_success1(struct nvme_ctrl *ctrl,
        struct nvmf_auth_dhchap_success1_data *data = chap->buf;
        size_t size = sizeof(*data);
 
-       if (chap->ctrl_key)
+       if (chap->s2)
                size += chap->hash_len;
 
        if (size > CHAP_BUF_SIZE) {
@@ -825,7 +825,7 @@ static void nvme_queue_auth_work(struct work_struct *work)
                goto fail2;
        }
 
-       if (chap->ctrl_key) {
+       if (chap->s2) {
                /* DH-HMAC-CHAP Step 5: send success2 */
                dev_dbg(ctrl->device, "%s: qid %d send success2\n",
                        __func__, chap->qid);
index d8ff796fd5f21d17c8a213cfdd07699a6e7523ec..747c879e8982b803525238afd1572fc90197fd6d 100644 (file)
@@ -108,9 +108,13 @@ static void *nvme_add_user_metadata(struct request *req, void __user *ubuf,
        if (!buf)
                goto out;
 
-       ret = -EFAULT;
-       if ((req_op(req) == REQ_OP_DRV_OUT) && copy_from_user(buf, ubuf, len))
-               goto out_free_meta;
+       if (req_op(req) == REQ_OP_DRV_OUT) {
+               ret = -EFAULT;
+               if (copy_from_user(buf, ubuf, len))
+                       goto out_free_meta;
+       } else {
+               memset(buf, 0, len);
+       }
 
        bip = bio_integrity_alloc(bio, GFP_KERNEL, 1);
        if (IS_ERR(bip)) {
index 347cb5daebc3cedefc09dac49a10960f00aa1ead..3f0c9ee09a12bb756792459e02a443219825003e 100644 (file)
@@ -3329,7 +3329,8 @@ static const struct pci_device_id nvme_id_table[] = {
        { PCI_VDEVICE(INTEL, 0x0a54),   /* Intel P4500/P4600 */
                .driver_data = NVME_QUIRK_STRIPE_SIZE |
                                NVME_QUIRK_DEALLOCATE_ZEROES |
-                               NVME_QUIRK_IGNORE_DEV_SUBNQN, },
+                               NVME_QUIRK_IGNORE_DEV_SUBNQN |
+                               NVME_QUIRK_BOGUS_NID, },
        { PCI_VDEVICE(INTEL, 0x0a55),   /* Dell Express Flash P4600 */
                .driver_data = NVME_QUIRK_STRIPE_SIZE |
                                NVME_QUIRK_DEALLOCATE_ZEROES, },
index 337a624a537ce14f764667e02a55607b54ca0e66..a7fea4cbacd753cfdf59b2a71c1420c7499b561e 100644 (file)
@@ -638,6 +638,9 @@ static void __nvme_rdma_stop_queue(struct nvme_rdma_queue *queue)
 
 static void nvme_rdma_stop_queue(struct nvme_rdma_queue *queue)
 {
+       if (!test_bit(NVME_RDMA_Q_ALLOCATED, &queue->flags))
+               return;
+
        mutex_lock(&queue->queue_lock);
        if (test_and_clear_bit(NVME_RDMA_Q_LIVE, &queue->flags))
                __nvme_rdma_stop_queue(queue);
index 586458f765f173b6ffa20b7abc58be5296c9ac91..1d9854484e2e83509b46d021f4941a583b7a34c3 100644 (file)
@@ -333,19 +333,21 @@ done:
                         __func__, ctrl->cntlid, req->sq->qid,
                         status, req->error_loc);
        req->cqe->result.u64 = 0;
-       nvmet_req_complete(req, status);
        if (req->sq->dhchap_step != NVME_AUTH_DHCHAP_MESSAGE_SUCCESS2 &&
            req->sq->dhchap_step != NVME_AUTH_DHCHAP_MESSAGE_FAILURE2) {
                unsigned long auth_expire_secs = ctrl->kato ? ctrl->kato : 120;
 
                mod_delayed_work(system_wq, &req->sq->auth_expired_work,
                                 auth_expire_secs * HZ);
-               return;
+               goto complete;
        }
        /* Final states, clear up variables */
        nvmet_auth_sq_free(req->sq);
        if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_FAILURE2)
                nvmet_ctrl_fatal_error(ctrl);
+
+complete:
+       nvmet_req_complete(req, status);
 }
 
 static int nvmet_auth_challenge(struct nvmet_req *req, void *d, int al)
@@ -514,11 +516,12 @@ void nvmet_execute_auth_receive(struct nvmet_req *req)
        kfree(d);
 done:
        req->cqe->result.u64 = 0;
-       nvmet_req_complete(req, status);
+
        if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_SUCCESS2)
                nvmet_auth_sq_free(req->sq);
        else if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_FAILURE1) {
                nvmet_auth_sq_free(req->sq);
                nvmet_ctrl_fatal_error(ctrl);
        }
+       nvmet_req_complete(req, status);
 }
index cd92d7ddf5ed15f677d9d954a43d064659ce2a36..197fc2ecb164dc8a17db8c68d2fc1adfceaf1857 100644 (file)
@@ -372,6 +372,7 @@ static void nvmet_tcp_fatal_error(struct nvmet_tcp_queue *queue)
 
 static void nvmet_tcp_socket_error(struct nvmet_tcp_queue *queue, int status)
 {
+       queue->rcv_state = NVMET_TCP_RECV_ERR;
        if (status == -EPIPE || status == -ECONNRESET)
                kernel_sock_shutdown(queue->sock, SHUT_RDWR);
        else
@@ -910,15 +911,11 @@ static int nvmet_tcp_handle_icreq(struct nvmet_tcp_queue *queue)
        iov.iov_len = sizeof(*icresp);
        ret = kernel_sendmsg(queue->sock, &msg, &iov, 1, iov.iov_len);
        if (ret < 0)
-               goto free_crypto;
+               return ret; /* queue removal will cleanup */
 
        queue->state = NVMET_TCP_Q_LIVE;
        nvmet_prepare_receive_pdu(queue);
        return 0;
-free_crypto:
-       if (queue->hdr_digest || queue->data_digest)
-               nvmet_tcp_free_crypto(queue);
-       return ret;
 }
 
 static void nvmet_tcp_handle_req_failure(struct nvmet_tcp_queue *queue,
index a223d9537f224d6b7000a426cc8c00f9828b61fb..e8b6f194925dfcefbf80b01ff7374fc33d5e578b 100644 (file)
@@ -498,7 +498,7 @@ static const struct ocotp_params imx6sl_params = {
 };
 
 static const struct ocotp_params imx6sll_params = {
-       .nregs = 128,
+       .nregs = 80,
        .bank_address_words = 0,
        .set_timing = imx_ocotp_set_imx6_timing,
        .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT,
@@ -512,14 +512,14 @@ static const struct ocotp_params imx6sx_params = {
 };
 
 static const struct ocotp_params imx6ul_params = {
-       .nregs = 128,
+       .nregs = 144,
        .bank_address_words = 0,
        .set_timing = imx_ocotp_set_imx6_timing,
        .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT,
 };
 
 static const struct ocotp_params imx6ull_params = {
-       .nregs = 64,
+       .nregs = 80,
        .bank_address_words = 0,
        .set_timing = imx_ocotp_set_imx6_timing,
        .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT,
index 0a3483e247a8932ca8ffe6ecbf0047f0c5472960..f63250c650cafdae49c7b558d47528a1af632689 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 dfb6fb962fc705ee1032d334233f89367707797d..a9a292d6d59b263ebcc7005511c01b42dbdc06f1 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 e2f29404c84eca23f59e61f7c63280fdba7da932..64420ecc24d1c38c45fc838e5b635495564172d3 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 2af64bcb7da3a3e0bc28ab0c99ca54d1d4f7b1f5..51e3dd0ea5abe02c4e9ce07d096f5ded30f26883 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 710ec35ba4a17738906f0e1aad105b702e288e2d..c2c7334152bc0522c9a8ec2a4d44e66ffae344e8 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 a79c110c7e510e73b598b48e5ac3c0daffdc2341..51ec9e7e784f0e3a82134a05b114abe5be90d07c 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 e85ff946e8c8cc338442f7dd4b4b8b52c1e44e69..9c8fd69ae5ad8ea2ed8cbe2c20c7f67216b0978f 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 58a2b1a1cae4c03c60416cf72f909c33fecf6d90..1f3803bde7ee16067d4aa801057076268dfe4b51 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 913dc04b3a400e3f1f533ba93d8de3fcf038708a..6b50bc551984626aadb25ff039f2c9ef333bac7a 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 1f9a35f724f59c4aa14f4087ebb27d77a5dbf370..0dda70e1ef90a19017c902689f970dea684b4f4c 100644 (file)
@@ -23,7 +23,8 @@ static bool riscv_perf_user_access(struct perf_event *event)
        return ((event->attr.type == PERF_TYPE_HARDWARE) ||
                (event->attr.type == PERF_TYPE_HW_CACHE) ||
                (event->attr.type == PERF_TYPE_RAW)) &&
-               !!(event->hw.flags & PERF_EVENT_FLAG_USER_READ_CNT);
+               !!(event->hw.flags & PERF_EVENT_FLAG_USER_READ_CNT) &&
+               (event->hw.idx != -1);
 }
 
 void arch_perf_update_userpage(struct perf_event *event,
index 9a51053b1f9951e7df95c68bc4f8d02af96c6b73..96c7f670c8f0d1821277a303abbdffdc517c9e25 100644 (file)
@@ -510,16 +510,18 @@ static void pmu_sbi_set_scounteren(void *arg)
 {
        struct perf_event *event = (struct perf_event *)arg;
 
-       csr_write(CSR_SCOUNTEREN,
-                 csr_read(CSR_SCOUNTEREN) | (1 << pmu_sbi_csr_index(event)));
+       if (event->hw.idx != -1)
+               csr_write(CSR_SCOUNTEREN,
+                         csr_read(CSR_SCOUNTEREN) | (1 << pmu_sbi_csr_index(event)));
 }
 
 static void pmu_sbi_reset_scounteren(void *arg)
 {
        struct perf_event *event = (struct perf_event *)arg;
 
-       csr_write(CSR_SCOUNTEREN,
-                 csr_read(CSR_SCOUNTEREN) & ~(1 << pmu_sbi_csr_index(event)));
+       if (event->hw.idx != -1)
+               csr_write(CSR_SCOUNTEREN,
+                         csr_read(CSR_SCOUNTEREN) & ~(1 << pmu_sbi_csr_index(event)));
 }
 
 static void pmu_sbi_ctr_start(struct perf_event *event, u64 ival)
@@ -541,7 +543,8 @@ static void pmu_sbi_ctr_start(struct perf_event *event, u64 ival)
 
        if ((hwc->flags & PERF_EVENT_FLAG_USER_ACCESS) &&
            (hwc->flags & PERF_EVENT_FLAG_USER_READ_CNT))
-               pmu_sbi_set_scounteren((void *)event);
+               on_each_cpu_mask(mm_cpumask(event->owner->mm),
+                                pmu_sbi_set_scounteren, (void *)event, 1);
 }
 
 static void pmu_sbi_ctr_stop(struct perf_event *event, unsigned long flag)
@@ -551,7 +554,8 @@ static void pmu_sbi_ctr_stop(struct perf_event *event, unsigned long flag)
 
        if ((hwc->flags & PERF_EVENT_FLAG_USER_ACCESS) &&
            (hwc->flags & PERF_EVENT_FLAG_USER_READ_CNT))
-               pmu_sbi_reset_scounteren((void *)event);
+               on_each_cpu_mask(mm_cpumask(event->owner->mm),
+                                pmu_sbi_reset_scounteren, (void *)event, 1);
 
        ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_STOP, hwc->idx, 1, flag, 0, 0, 0);
        if (ret.error && (ret.error != SBI_ERR_ALREADY_STOPPED) &&
index 4f036c77284e1d2255bf7796bd45927ecbe63895..e2187767ce00ce5658109e820c173a8a2fc04d12 100644 (file)
@@ -127,6 +127,10 @@ struct lynx_28g_lane {
 struct lynx_28g_priv {
        void __iomem *base;
        struct device *dev;
+       /* Serialize concurrent access to registers shared between lanes,
+        * like PCCn
+        */
+       spinlock_t pcc_lock;
        struct lynx_28g_pll pll[LYNX_28G_NUM_PLL];
        struct lynx_28g_lane lane[LYNX_28G_NUM_LANE];
 
@@ -397,6 +401,8 @@ static int lynx_28g_set_mode(struct phy *phy, enum phy_mode mode, int submode)
        if (powered_up)
                lynx_28g_power_off(phy);
 
+       spin_lock(&priv->pcc_lock);
+
        switch (submode) {
        case PHY_INTERFACE_MODE_SGMII:
        case PHY_INTERFACE_MODE_1000BASEX:
@@ -413,6 +419,8 @@ static int lynx_28g_set_mode(struct phy *phy, enum phy_mode mode, int submode)
        lane->interface = submode;
 
 out:
+       spin_unlock(&priv->pcc_lock);
+
        /* Power up the lane if necessary */
        if (powered_up)
                lynx_28g_power_on(phy);
@@ -508,11 +516,12 @@ static void lynx_28g_cdr_lock_check(struct work_struct *work)
        for (i = 0; i < LYNX_28G_NUM_LANE; i++) {
                lane = &priv->lane[i];
 
-               if (!lane->init)
-                       continue;
+               mutex_lock(&lane->phy->mutex);
 
-               if (!lane->powered_up)
+               if (!lane->init || !lane->powered_up) {
+                       mutex_unlock(&lane->phy->mutex);
                        continue;
+               }
 
                rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
                if (!(rrstctl & LYNX_28G_LNaRRSTCTL_CDR_LOCK)) {
@@ -521,6 +530,8 @@ static void lynx_28g_cdr_lock_check(struct work_struct *work)
                                rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
                        } while (!(rrstctl & LYNX_28G_LNaRRSTCTL_RST_DONE));
                }
+
+               mutex_unlock(&lane->phy->mutex);
        }
        queue_delayed_work(system_power_efficient_wq, &priv->cdr_check,
                           msecs_to_jiffies(1000));
@@ -593,6 +604,7 @@ static int lynx_28g_probe(struct platform_device *pdev)
 
        dev_set_drvdata(dev, priv);
 
+       spin_lock_init(&priv->pcc_lock);
        INIT_DELAYED_WORK(&priv->cdr_check, lynx_28g_cdr_lock_check);
 
        queue_delayed_work(system_power_efficient_wq, &priv->cdr_check,
@@ -604,6 +616,14 @@ static int lynx_28g_probe(struct platform_device *pdev)
        return PTR_ERR_OR_ZERO(provider);
 }
 
+static void lynx_28g_remove(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct lynx_28g_priv *priv = dev_get_drvdata(dev);
+
+       cancel_delayed_work_sync(&priv->cdr_check);
+}
+
 static const struct of_device_id lynx_28g_of_match_table[] = {
        { .compatible = "fsl,lynx-28g" },
        { },
@@ -612,6 +632,7 @@ MODULE_DEVICE_TABLE(of, lynx_28g_of_match_table);
 
 static struct platform_driver lynx_28g_driver = {
        .probe  = lynx_28g_probe,
+       .remove_new = lynx_28g_remove,
        .driver = {
                .name = "lynx-28g",
                .of_match_table = lynx_28g_of_match_table,
index 1d567604b650d9449d0b07da821ac6907a15d4ca..376d023a0aa9093bfa940a3b68148166950fd3ef 100644 (file)
@@ -122,16 +122,10 @@ static int phy_mdm6600_power_on(struct phy *x)
 {
        struct phy_mdm6600 *ddata = phy_get_drvdata(x);
        struct gpio_desc *enable_gpio = ddata->ctrl_gpios[PHY_MDM6600_ENABLE];
-       int error;
 
        if (!ddata->enabled)
                return -ENODEV;
 
-       error = pinctrl_pm_select_default_state(ddata->dev);
-       if (error)
-               dev_warn(ddata->dev, "%s: error with default_state: %i\n",
-                        __func__, error);
-
        gpiod_set_value_cansleep(enable_gpio, 1);
 
        /* Allow aggressive PM for USB, it's only needed for n_gsm port */
@@ -160,11 +154,6 @@ static int phy_mdm6600_power_off(struct phy *x)
 
        gpiod_set_value_cansleep(enable_gpio, 0);
 
-       error = pinctrl_pm_select_sleep_state(ddata->dev);
-       if (error)
-               dev_warn(ddata->dev, "%s: error with sleep_state: %i\n",
-                        __func__, error);
-
        return 0;
 }
 
@@ -456,6 +445,7 @@ static void phy_mdm6600_device_power_off(struct phy_mdm6600 *ddata)
 {
        struct gpio_desc *reset_gpio =
                ddata->ctrl_gpios[PHY_MDM6600_RESET];
+       int error;
 
        ddata->enabled = false;
        phy_mdm6600_cmd(ddata, PHY_MDM6600_CMD_BP_SHUTDOWN_REQ);
@@ -471,6 +461,17 @@ static void phy_mdm6600_device_power_off(struct phy_mdm6600 *ddata)
        } else {
                dev_err(ddata->dev, "Timed out powering down\n");
        }
+
+       /*
+        * Keep reset gpio high with padconf internal pull-up resistor to
+        * prevent modem from waking up during deeper SoC idle states. The
+        * gpio bank lines can have glitches if not in the always-on wkup
+        * domain.
+        */
+       error = pinctrl_pm_select_sleep_state(ddata->dev);
+       if (error)
+               dev_warn(ddata->dev, "%s: error with sleep_state: %i\n",
+                        __func__, error);
 }
 
 static void phy_mdm6600_deferred_power_on(struct work_struct *work)
@@ -571,12 +572,6 @@ static int phy_mdm6600_probe(struct platform_device *pdev)
        ddata->dev = &pdev->dev;
        platform_set_drvdata(pdev, ddata);
 
-       /* Active state selected in phy_mdm6600_power_on() */
-       error = pinctrl_pm_select_sleep_state(ddata->dev);
-       if (error)
-               dev_warn(ddata->dev, "%s: error with sleep_state: %i\n",
-                        __func__, error);
-
        error = phy_mdm6600_init_lines(ddata);
        if (error)
                return error;
@@ -627,10 +622,12 @@ idle:
        pm_runtime_put_autosuspend(ddata->dev);
 
 cleanup:
-       if (error < 0)
+       if (error < 0) {
                phy_mdm6600_device_power_off(ddata);
-       pm_runtime_disable(ddata->dev);
-       pm_runtime_dont_use_autosuspend(ddata->dev);
+               pm_runtime_disable(ddata->dev);
+               pm_runtime_dont_use_autosuspend(ddata->dev);
+       }
+
        return error;
 }
 
@@ -639,6 +636,7 @@ static void phy_mdm6600_remove(struct platform_device *pdev)
        struct phy_mdm6600 *ddata = platform_get_drvdata(pdev);
        struct gpio_desc *reset_gpio = ddata->ctrl_gpios[PHY_MDM6600_RESET];
 
+       pm_runtime_get_noresume(ddata->dev);
        pm_runtime_dont_use_autosuspend(ddata->dev);
        pm_runtime_put_sync(ddata->dev);
        pm_runtime_disable(ddata->dev);
index 8814f4322adffb99f1fd0d55af29002ab13fb97a..3642a5d4f2f3b8062cf993e49676a424a33ddd15 100644 (file)
@@ -152,7 +152,7 @@ static int qcom_apq8064_sata_phy_init(struct phy *generic_phy)
                return ret;
        }
 
-       /* SATA phy calibrated succesfully, power up to functional mode */
+       /* SATA phy calibrated successfully, power up to functional mode */
        writel_relaxed(0x3E, base + SATA_PHY_POW_DWN_CTRL1);
        writel_relaxed(0x01, base + SATA_PHY_RX_IMCAL0);
        writel_relaxed(0x01, base + SATA_PHY_TX_IMCAL0);
index ed08072ca032cac30976f0ce4d3c34bb5748ca68..5cb7e79b99b3f5622d47fe77b7a0e36187a551af 100644 (file)
@@ -82,7 +82,7 @@ struct m31_priv_data {
        unsigned int                    nregs;
 };
 
-struct m31_phy_regs m31_ipq5332_regs[] = {
+static struct m31_phy_regs m31_ipq5332_regs[] = {
        {
                USB_PHY_CFG0,
                UTMI_PHY_OVERRIDE_EN,
@@ -172,8 +172,7 @@ static int m31usb_phy_init(struct phy *phy)
 
        ret = clk_prepare_enable(qphy->clk);
        if (ret) {
-               if (qphy->vreg)
-                       regulator_disable(qphy->vreg);
+               regulator_disable(qphy->vreg);
                dev_err(&phy->dev, "failed to enable cfg ahb clock, %d\n", ret);
                return ret;
        }
@@ -256,7 +255,7 @@ static int m31usb_phy_probe(struct platform_device *pdev)
 
        qphy->vreg = devm_regulator_get(dev, "vdda-phy");
        if (IS_ERR(qphy->vreg))
-               return dev_err_probe(dev, PTR_ERR(qphy->phy),
+               return dev_err_probe(dev, PTR_ERR(qphy->vreg),
                                                "failed to get vreg\n");
 
        phy_set_drvdata(qphy->phy, qphy);
index cbb28afce1354101ab378336042edc9dd040b9c1..5e6fc8103e9d81214a8cbe175895c2c3d0125487 100644 (file)
@@ -859,10 +859,10 @@ static const struct qmp_phy_init_tbl sm8550_usb3_pcs_tbl[] = {
        QMP_PHY_INIT_CFG(QPHY_USB_V6_PCS_PCS_TX_RX_CONFIG, 0x0c),
        QMP_PHY_INIT_CFG(QPHY_USB_V6_PCS_EQ_CONFIG1, 0x4b),
        QMP_PHY_INIT_CFG(QPHY_USB_V6_PCS_EQ_CONFIG5, 0x10),
-       QMP_PHY_INIT_CFG(QPHY_USB_V6_PCS_USB3_POWER_STATE_CONFIG1, 0x68),
 };
 
 static const struct qmp_phy_init_tbl sm8550_usb3_pcs_usb_tbl[] = {
+       QMP_PHY_INIT_CFG(QPHY_USB_V6_PCS_USB3_POWER_STATE_CONFIG1, 0x68),
        QMP_PHY_INIT_CFG(QPHY_USB_V6_PCS_USB3_LFPS_DET_HIGH_COUNT_VAL, 0xf8),
        QMP_PHY_INIT_CFG(QPHY_USB_V6_PCS_USB3_RXEQTRAINING_DFE_TIME_S2, 0x07),
        QMP_PHY_INIT_CFG(QPHY_USB_V6_PCS_USB3_RCVR_DTCT_DLY_U3_L, 0x40),
@@ -2555,6 +2555,7 @@ static int qmp_combo_usb_power_on(struct phy *phy)
        void __iomem *tx2 = qmp->tx2;
        void __iomem *rx2 = qmp->rx2;
        void __iomem *pcs = qmp->pcs;
+       void __iomem *pcs_usb = qmp->pcs_usb;
        void __iomem *status;
        unsigned int val;
        int ret;
@@ -2576,6 +2577,9 @@ static int qmp_combo_usb_power_on(struct phy *phy)
 
        qmp_combo_configure(pcs, cfg->pcs_tbl, cfg->pcs_tbl_num);
 
+       if (pcs_usb)
+               qmp_combo_configure(pcs_usb, cfg->pcs_usb_tbl, cfg->pcs_usb_tbl_num);
+
        if (cfg->has_pwrdn_delay)
                usleep_range(10, 20);
 
index 9510e63ba9d8ab78bfdf42a1541b35d61d0ff234..c38530d6776b4a5022c302100626671b5669b7d6 100644 (file)
@@ -12,7 +12,7 @@
 #define QPHY_USB_V6_PCS_LOCK_DETECT_CONFIG3            0xcc
 #define QPHY_USB_V6_PCS_LOCK_DETECT_CONFIG6            0xd8
 #define QPHY_USB_V6_PCS_REFGEN_REQ_CONFIG1             0xdc
-#define QPHY_USB_V6_PCS_USB3_POWER_STATE_CONFIG1       0x90
+#define QPHY_USB_V6_PCS_POWER_STATE_CONFIG1            0x90
 #define QPHY_USB_V6_PCS_RX_SIGDET_LVL                  0x188
 #define QPHY_USB_V6_PCS_RCVR_DTCT_DLY_P1U2_L           0x190
 #define QPHY_USB_V6_PCS_RCVR_DTCT_DLY_P1U2_H           0x194
@@ -23,6 +23,7 @@
 #define QPHY_USB_V6_PCS_EQ_CONFIG1                     0x1dc
 #define QPHY_USB_V6_PCS_EQ_CONFIG5                     0x1ec
 
+#define QPHY_USB_V6_PCS_USB3_POWER_STATE_CONFIG1       0x00
 #define QPHY_USB_V6_PCS_USB3_LFPS_DET_HIGH_COUNT_VAL   0x18
 #define QPHY_USB_V6_PCS_USB3_RXEQTRAINING_DFE_TIME_S2  0x3c
 #define QPHY_USB_V6_PCS_USB3_RCVR_DTCT_DLY_U3_L                0x40
index 0130bb8e809afcd6cf78fe07ab5fff1e35ded237..c69577601ae0044d2d7a67ae2cdf8163c9165d10 100644 (file)
@@ -1112,8 +1112,6 @@ static const struct qmp_phy_init_tbl sc8280xp_usb3_uniphy_pcs_tbl[] = {
        QMP_PHY_INIT_CFG(QPHY_V5_PCS_RCVR_DTCT_DLY_P1U2_H, 0x03),
        QMP_PHY_INIT_CFG(QPHY_V5_PCS_RX_SIGDET_LVL, 0xaa),
        QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCS_TX_RX_CONFIG, 0x0c),
-       QMP_PHY_INIT_CFG(QPHY_V5_PCS_USB3_RXEQTRAINING_DFE_TIME_S2, 0x07),
-       QMP_PHY_INIT_CFG(QPHY_V5_PCS_USB3_LFPS_DET_HIGH_COUNT_VAL, 0xf8),
        QMP_PHY_INIT_CFG(QPHY_V5_PCS_CDR_RESET_TIME, 0x0a),
        QMP_PHY_INIT_CFG(QPHY_V5_PCS_ALIGN_DETECT_CONFIG1, 0x88),
        QMP_PHY_INIT_CFG(QPHY_V5_PCS_ALIGN_DETECT_CONFIG2, 0x13),
@@ -1122,6 +1120,11 @@ static const struct qmp_phy_init_tbl sc8280xp_usb3_uniphy_pcs_tbl[] = {
        QMP_PHY_INIT_CFG(QPHY_V5_PCS_REFGEN_REQ_CONFIG1, 0x21),
 };
 
+static const struct qmp_phy_init_tbl sc8280xp_usb3_uniphy_pcs_usb_tbl[] = {
+       QMP_PHY_INIT_CFG(QPHY_V5_PCS_USB3_RXEQTRAINING_DFE_TIME_S2, 0x07),
+       QMP_PHY_INIT_CFG(QPHY_V5_PCS_USB3_LFPS_DET_HIGH_COUNT_VAL, 0xf8),
+};
+
 static const struct qmp_phy_init_tbl sa8775p_usb3_uniphy_pcs_tbl[] = {
        QMP_PHY_INIT_CFG(QPHY_V5_PCS_LOCK_DETECT_CONFIG1, 0xc4),
        QMP_PHY_INIT_CFG(QPHY_V5_PCS_LOCK_DETECT_CONFIG2, 0x89),
@@ -1131,9 +1134,6 @@ static const struct qmp_phy_init_tbl sa8775p_usb3_uniphy_pcs_tbl[] = {
        QMP_PHY_INIT_CFG(QPHY_V5_PCS_RCVR_DTCT_DLY_P1U2_H, 0x03),
        QMP_PHY_INIT_CFG(QPHY_V5_PCS_RX_SIGDET_LVL, 0xaa),
        QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCS_TX_RX_CONFIG, 0x0c),
-       QMP_PHY_INIT_CFG(QPHY_V5_PCS_USB3_RXEQTRAINING_DFE_TIME_S2, 0x07),
-       QMP_PHY_INIT_CFG(QPHY_V5_PCS_USB3_LFPS_DET_HIGH_COUNT_VAL, 0xf8),
-       QMP_PHY_INIT_CFG(QPHY_V5_PCS_USB3_POWER_STATE_CONFIG1, 0x6f),
        QMP_PHY_INIT_CFG(QPHY_V5_PCS_CDR_RESET_TIME, 0x0a),
        QMP_PHY_INIT_CFG(QPHY_V5_PCS_ALIGN_DETECT_CONFIG1, 0x88),
        QMP_PHY_INIT_CFG(QPHY_V5_PCS_ALIGN_DETECT_CONFIG2, 0x13),
@@ -1142,6 +1142,12 @@ static const struct qmp_phy_init_tbl sa8775p_usb3_uniphy_pcs_tbl[] = {
        QMP_PHY_INIT_CFG(QPHY_V5_PCS_REFGEN_REQ_CONFIG1, 0x21),
 };
 
+static const struct qmp_phy_init_tbl sa8775p_usb3_uniphy_pcs_usb_tbl[] = {
+       QMP_PHY_INIT_CFG(QPHY_V5_PCS_USB3_RXEQTRAINING_DFE_TIME_S2, 0x07),
+       QMP_PHY_INIT_CFG(QPHY_V5_PCS_USB3_LFPS_DET_HIGH_COUNT_VAL, 0xf8),
+       QMP_PHY_INIT_CFG(QPHY_V5_PCS_USB3_POWER_STATE_CONFIG1, 0x6f),
+};
+
 struct qmp_usb_offsets {
        u16 serdes;
        u16 pcs;
@@ -1383,6 +1389,8 @@ static const struct qmp_phy_cfg sa8775p_usb3_uniphy_cfg = {
        .rx_tbl_num             = ARRAY_SIZE(sc8280xp_usb3_uniphy_rx_tbl),
        .pcs_tbl                = sa8775p_usb3_uniphy_pcs_tbl,
        .pcs_tbl_num            = ARRAY_SIZE(sa8775p_usb3_uniphy_pcs_tbl),
+       .pcs_usb_tbl            = sa8775p_usb3_uniphy_pcs_usb_tbl,
+       .pcs_usb_tbl_num        = ARRAY_SIZE(sa8775p_usb3_uniphy_pcs_usb_tbl),
        .clk_list               = qmp_v4_phy_clk_l,
        .num_clks               = ARRAY_SIZE(qmp_v4_phy_clk_l),
        .reset_list             = qcm2290_usb3phy_reset_l,
@@ -1405,6 +1413,8 @@ static const struct qmp_phy_cfg sc8280xp_usb3_uniphy_cfg = {
        .rx_tbl_num             = ARRAY_SIZE(sc8280xp_usb3_uniphy_rx_tbl),
        .pcs_tbl                = sc8280xp_usb3_uniphy_pcs_tbl,
        .pcs_tbl_num            = ARRAY_SIZE(sc8280xp_usb3_uniphy_pcs_tbl),
+       .pcs_usb_tbl            = sc8280xp_usb3_uniphy_pcs_usb_tbl,
+       .pcs_usb_tbl_num        = ARRAY_SIZE(sc8280xp_usb3_uniphy_pcs_usb_tbl),
        .clk_list               = qmp_v4_phy_clk_l,
        .num_clks               = ARRAY_SIZE(qmp_v4_phy_clk_l),
        .reset_list             = qcm2290_usb3phy_reset_l,
@@ -1703,6 +1713,7 @@ static int qmp_usb_power_on(struct phy *phy)
        void __iomem *tx = qmp->tx;
        void __iomem *rx = qmp->rx;
        void __iomem *pcs = qmp->pcs;
+       void __iomem *pcs_usb = qmp->pcs_usb;
        void __iomem *status;
        unsigned int val;
        int ret;
@@ -1726,6 +1737,9 @@ static int qmp_usb_power_on(struct phy *phy)
 
        qmp_usb_configure(pcs, cfg->pcs_tbl, cfg->pcs_tbl_num);
 
+       if (pcs_usb)
+               qmp_usb_configure(pcs_usb, cfg->pcs_usb_tbl, cfg->pcs_usb_tbl_num);
+
        if (cfg->has_pwrdn_delay)
                usleep_range(10, 20);
 
index 650e20ed69af41d286ed99e27a7c37edd5470b1b..75ac7e7c31aec6f2d2ed8b2720ff07b6c3558948 100644 (file)
@@ -2,6 +2,9 @@
 #
 # Phy drivers for Realtek platforms
 #
+
+if ARCH_REALTEK || COMPILE_TEST
+
 config PHY_RTK_RTD_USB2PHY
        tristate "Realtek RTD USB2 PHY Transceiver Driver"
        depends on USB_SUPPORT
@@ -25,3 +28,5 @@ config PHY_RTK_RTD_USB3PHY
          The DHC (digital home center) RTD series SoCs used the Synopsys
          DWC3 USB IP. This driver will do the PHY initialization
          of the parameters.
+
+endif # ARCH_REALTEK || COMPILE_TEST
index 5e7ee060b404faffcf9a43f6c079bd01c06673d2..aedc78bd37f73385ec3a303de25a08da8da14aeb 100644 (file)
@@ -853,17 +853,11 @@ static inline void create_debug_files(struct rtk_phy *rtk_phy)
 
        rtk_phy->debug_dir = debugfs_create_dir(dev_name(rtk_phy->dev),
                                                phy_debug_root);
-       if (!rtk_phy->debug_dir)
-               return;
 
-       if (!debugfs_create_file("parameter", 0444, rtk_phy->debug_dir, rtk_phy,
-                                &rtk_usb2_parameter_fops))
-               goto file_error;
+       debugfs_create_file("parameter", 0444, rtk_phy->debug_dir, rtk_phy,
+                           &rtk_usb2_parameter_fops);
 
        return;
-
-file_error:
-       debugfs_remove_recursive(rtk_phy->debug_dir);
 }
 
 static inline void remove_debug_files(struct rtk_phy *rtk_phy)
index 7881f908aadea8b5514e23bbce8581589f4a43de..dfb3122f3f114bdcb99d5b33f8898acdf829037e 100644 (file)
@@ -416,17 +416,11 @@ static inline void create_debug_files(struct rtk_phy *rtk_phy)
                return;
 
        rtk_phy->debug_dir = debugfs_create_dir(dev_name(rtk_phy->dev), phy_debug_root);
-       if (!rtk_phy->debug_dir)
-               return;
 
-       if (!debugfs_create_file("parameter", 0444, rtk_phy->debug_dir, rtk_phy,
-                                &rtk_usb3_parameter_fops))
-               goto file_error;
+       debugfs_create_file("parameter", 0444, rtk_phy->debug_dir, rtk_phy,
+                           &rtk_usb3_parameter_fops);
 
        return;
-
-file_error:
-       debugfs_remove_recursive(rtk_phy->debug_dir);
 }
 
 static inline void remove_debug_files(struct rtk_phy *rtk_phy)
index 2d1c1652cfd9d373dc5afde3a1a5cbddb50a4a56..8a9961ac87128d301e76fe6b247b7538be883986 100644 (file)
@@ -1062,13 +1062,13 @@ static int wpcm450_gpio_register(struct platform_device *pdev,
                if (ret < 0)
                        return ret;
 
-               gpio = &pctrl->gpio_bank[reg];
-               gpio->pctrl = pctrl;
-
                if (reg >= WPCM450_NUM_BANKS)
                        return dev_err_probe(dev, -EINVAL,
                                             "GPIO index %d out of range!\n", reg);
 
+               gpio = &pctrl->gpio_bank[reg];
+               gpio->pctrl = pctrl;
+
                bank = &wpcm450_banks[reg];
                gpio->bank = bank;
 
index efb25fc34f14991d3e628edb7c150c2c001c6d90..1ac49ae638de4b8ee60ac71b09710e92f1b8f24d 100644 (file)
@@ -198,5 +198,4 @@ enum ltq_pin {
 
 extern int ltq_pinctrl_register(struct platform_device *pdev,
                                   struct ltq_pinmux_info *info);
-extern int ltq_pinctrl_unregister(struct platform_device *pdev);
 #endif /* __PINCTRL_LANTIQ_H */
index e5a418026ba3397afe81321512c85e29e410f1cd..0b2839d27fd67137c5e1605a4ac11821d7d40d00 100644 (file)
@@ -32,7 +32,8 @@ struct lpi_pinctrl {
        char __iomem *tlmm_base;
        char __iomem *slew_base;
        struct clk_bulk_data clks[MAX_LPI_NUM_CLKS];
-       struct mutex slew_access_lock;
+       /* Protects from concurrent register updates */
+       struct mutex lock;
        DECLARE_BITMAP(ever_gpio, MAX_NR_GPIO);
        const struct lpi_pinctrl_variant_data *data;
 };
@@ -103,6 +104,7 @@ static int lpi_gpio_set_mux(struct pinctrl_dev *pctldev, unsigned int function,
        if (WARN_ON(i == g->nfuncs))
                return -EINVAL;
 
+       mutex_lock(&pctrl->lock);
        val = lpi_gpio_read(pctrl, pin, LPI_GPIO_CFG_REG);
 
        /*
@@ -128,6 +130,7 @@ static int lpi_gpio_set_mux(struct pinctrl_dev *pctldev, unsigned int function,
 
        u32p_replace_bits(&val, i, LPI_GPIO_FUNCTION_MASK);
        lpi_gpio_write(pctrl, pin, LPI_GPIO_CFG_REG, val);
+       mutex_unlock(&pctrl->lock);
 
        return 0;
 }
@@ -233,14 +236,14 @@ static int lpi_config_set(struct pinctrl_dev *pctldev, unsigned int group,
                        if (slew_offset == LPI_NO_SLEW)
                                break;
 
-                       mutex_lock(&pctrl->slew_access_lock);
+                       mutex_lock(&pctrl->lock);
 
                        sval = ioread32(pctrl->slew_base + LPI_SLEW_RATE_CTL_REG);
                        sval &= ~(LPI_SLEW_RATE_MASK << slew_offset);
                        sval |= arg << slew_offset;
                        iowrite32(sval, pctrl->slew_base + LPI_SLEW_RATE_CTL_REG);
 
-                       mutex_unlock(&pctrl->slew_access_lock);
+                       mutex_unlock(&pctrl->lock);
                        break;
                default:
                        return -EINVAL;
@@ -256,6 +259,7 @@ static int lpi_config_set(struct pinctrl_dev *pctldev, unsigned int group,
                lpi_gpio_write(pctrl, group, LPI_GPIO_VALUE_REG, val);
        }
 
+       mutex_lock(&pctrl->lock);
        val = lpi_gpio_read(pctrl, group, LPI_GPIO_CFG_REG);
 
        u32p_replace_bits(&val, pullup, LPI_GPIO_PULL_MASK);
@@ -264,6 +268,7 @@ static int lpi_config_set(struct pinctrl_dev *pctldev, unsigned int group,
        u32p_replace_bits(&val, output_enabled, LPI_GPIO_OE_MASK);
 
        lpi_gpio_write(pctrl, group, LPI_GPIO_CFG_REG, val);
+       mutex_unlock(&pctrl->lock);
 
        return 0;
 }
@@ -461,7 +466,7 @@ int lpi_pinctrl_probe(struct platform_device *pdev)
        pctrl->chip.label = dev_name(dev);
        pctrl->chip.can_sleep = false;
 
-       mutex_init(&pctrl->slew_access_lock);
+       mutex_init(&pctrl->lock);
 
        pctrl->ctrl = devm_pinctrl_register(dev, &pctrl->desc, pctrl);
        if (IS_ERR(pctrl->ctrl)) {
@@ -483,7 +488,7 @@ int lpi_pinctrl_probe(struct platform_device *pdev)
        return 0;
 
 err_pinctrl:
-       mutex_destroy(&pctrl->slew_access_lock);
+       mutex_destroy(&pctrl->lock);
        clk_bulk_disable_unprepare(MAX_LPI_NUM_CLKS, pctrl->clks);
 
        return ret;
@@ -495,7 +500,7 @@ int lpi_pinctrl_remove(struct platform_device *pdev)
        struct lpi_pinctrl *pctrl = platform_get_drvdata(pdev);
        int i;
 
-       mutex_destroy(&pctrl->slew_access_lock);
+       mutex_destroy(&pctrl->lock);
        clk_bulk_disable_unprepare(MAX_LPI_NUM_CLKS, pctrl->clks);
 
        for (i = 0; i < pctrl->data->npins; i++)
index 77730dc548ed3c7050089cac172e81895bef7f70..c8d519ca53eb7f312ce518fee0adcc9cb93e15f7 100644 (file)
@@ -235,6 +235,7 @@ config PINCTRL_RZN1
        depends on OF
        depends on ARCH_RZN1 || COMPILE_TEST
        select GENERIC_PINCONF
+       select PINMUX
        help
          This selects pinctrl driver for Renesas RZ/N1 devices.
 
index 4bfe3aa57f8a55d03928a156f908977a57bd9c0d..cf42e204cbf01bb4cde3c866cfdd8dffb8eed66d 100644 (file)
@@ -31,6 +31,8 @@
 #define JH7110_AON_NGPIO               4
 #define JH7110_AON_GC_BASE             64
 
+#define JH7110_AON_REGS_NUM            37
+
 /* registers */
 #define JH7110_AON_DOEN                        0x0
 #define JH7110_AON_DOUT                        0x4
@@ -145,6 +147,7 @@ static const struct jh7110_pinctrl_soc_info jh7110_aon_pinctrl_info = {
        .gpi_mask       = GENMASK(3, 0),
        .gpioin_reg_base           = JH7110_AON_GPIOIN,
        .irq_reg                   = &jh7110_aon_irq_reg,
+       .nsaved_regs               = JH7110_AON_REGS_NUM,
        .jh7110_set_one_pin_mux  = jh7110_aon_set_one_pin_mux,
        .jh7110_get_padcfg_base  = jh7110_aon_get_padcfg_base,
        .jh7110_gpio_irq_handler = jh7110_aon_irq_handler,
@@ -165,6 +168,7 @@ static struct platform_driver jh7110_aon_pinctrl_driver = {
        .driver = {
                .name = "starfive-jh7110-aon-pinctrl",
                .of_match_table = jh7110_aon_pinctrl_of_match,
+               .pm = pm_sleep_ptr(&jh7110_pinctrl_pm_ops),
        },
 };
 module_platform_driver(jh7110_aon_pinctrl_driver);
index 20c85db1cd3ab4521bb73bd8ee244ae170f468ab..03c2ad808d61c65d3137ef73ad6a208ec8e6ddb7 100644 (file)
@@ -31,6 +31,8 @@
 #define JH7110_SYS_NGPIO               64
 #define JH7110_SYS_GC_BASE             0
 
+#define JH7110_SYS_REGS_NUM            174
+
 /* registers */
 #define JH7110_SYS_DOEN                        0x000
 #define JH7110_SYS_DOUT                        0x040
@@ -417,6 +419,7 @@ static const struct jh7110_pinctrl_soc_info jh7110_sys_pinctrl_info = {
        .gpi_mask       = GENMASK(6, 0),
        .gpioin_reg_base           = JH7110_SYS_GPIOIN,
        .irq_reg                   = &jh7110_sys_irq_reg,
+       .nsaved_regs               = JH7110_SYS_REGS_NUM,
        .jh7110_set_one_pin_mux  = jh7110_sys_set_one_pin_mux,
        .jh7110_get_padcfg_base  = jh7110_sys_get_padcfg_base,
        .jh7110_gpio_irq_handler = jh7110_sys_irq_handler,
@@ -437,6 +440,7 @@ static struct platform_driver jh7110_sys_pinctrl_driver = {
        .driver = {
                .name = "starfive-jh7110-sys-pinctrl",
                .of_match_table = jh7110_sys_pinctrl_of_match,
+               .pm = pm_sleep_ptr(&jh7110_pinctrl_pm_ops),
        },
 };
 module_platform_driver(jh7110_sys_pinctrl_driver);
index b9081805c8f6e13cfb660f119b4f71bab3efbc85..640f827a9b2ca6c0e9e05364b00e29874f0078d9 100644 (file)
@@ -872,6 +872,13 @@ int jh7110_pinctrl_probe(struct platform_device *pdev)
        if (!sfp)
                return -ENOMEM;
 
+#if IS_ENABLED(CONFIG_PM_SLEEP)
+       sfp->saved_regs = devm_kcalloc(dev, info->nsaved_regs,
+                                      sizeof(*sfp->saved_regs), GFP_KERNEL);
+       if (!sfp->saved_regs)
+               return -ENOMEM;
+#endif
+
        sfp->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(sfp->base))
                return PTR_ERR(sfp->base);
@@ -967,14 +974,45 @@ int jh7110_pinctrl_probe(struct platform_device *pdev)
        if (ret)
                return dev_err_probe(dev, ret, "could not register gpiochip\n");
 
-       irq_domain_set_pm_device(sfp->gc.irq.domain, dev);
-
        dev_info(dev, "StarFive GPIO chip registered %d GPIOs\n", sfp->gc.ngpio);
 
        return pinctrl_enable(sfp->pctl);
 }
 EXPORT_SYMBOL_GPL(jh7110_pinctrl_probe);
 
+static int jh7110_pinctrl_suspend(struct device *dev)
+{
+       struct jh7110_pinctrl *sfp = dev_get_drvdata(dev);
+       unsigned long flags;
+       unsigned int i;
+
+       raw_spin_lock_irqsave(&sfp->lock, flags);
+       for (i = 0 ; i < sfp->info->nsaved_regs ; i++)
+               sfp->saved_regs[i] = readl_relaxed(sfp->base + 4 * i);
+
+       raw_spin_unlock_irqrestore(&sfp->lock, flags);
+       return 0;
+}
+
+static int jh7110_pinctrl_resume(struct device *dev)
+{
+       struct jh7110_pinctrl *sfp = dev_get_drvdata(dev);
+       unsigned long flags;
+       unsigned int i;
+
+       raw_spin_lock_irqsave(&sfp->lock, flags);
+       for (i = 0 ; i < sfp->info->nsaved_regs ; i++)
+               writel_relaxed(sfp->saved_regs[i], sfp->base + 4 * i);
+
+       raw_spin_unlock_irqrestore(&sfp->lock, flags);
+       return 0;
+}
+
+const struct dev_pm_ops jh7110_pinctrl_pm_ops = {
+       LATE_SYSTEM_SLEEP_PM_OPS(jh7110_pinctrl_suspend, jh7110_pinctrl_resume)
+};
+EXPORT_SYMBOL_GPL(jh7110_pinctrl_pm_ops);
+
 MODULE_DESCRIPTION("Pinctrl driver for the StarFive JH7110 SoC");
 MODULE_AUTHOR("Emil Renner Berthing <kernel@esmil.dk>");
 MODULE_AUTHOR("Jianlong Huang <jianlong.huang@starfivetech.com>");
index 3f20b7ff96dd85c605f543a90948ec54b2aae9c1..a33d0d4e13820d8ca3adfb6316ca496206562827 100644 (file)
@@ -21,6 +21,7 @@ struct jh7110_pinctrl {
        /* register read/write mutex */
        struct mutex mutex;
        const struct jh7110_pinctrl_soc_info *info;
+       u32 *saved_regs;
 };
 
 struct jh7110_gpio_irq_reg {
@@ -50,6 +51,8 @@ struct jh7110_pinctrl_soc_info {
 
        const struct jh7110_gpio_irq_reg *irq_reg;
 
+       unsigned int nsaved_regs;
+
        /* generic pinmux */
        int (*jh7110_set_one_pin_mux)(struct jh7110_pinctrl *sfp,
                                      unsigned int pin,
@@ -66,5 +69,6 @@ void jh7110_set_gpiomux(struct jh7110_pinctrl *sfp, unsigned int pin,
                        unsigned int din, u32 dout, u32 doen);
 int jh7110_pinctrl_probe(struct platform_device *pdev);
 struct jh7110_pinctrl *jh7110_from_irq_desc(struct irq_desc *desc);
+extern const struct dev_pm_ops jh7110_pinctrl_pm_ops;
 
 #endif /* __PINCTRL_STARFIVE_JH7110_H__ */
index cfeda5b3e04821bfffae995eb00291ba53dcc1ef..734c71ef005b8c4302189185025bffcd750732b4 100644 (file)
@@ -96,7 +96,6 @@ static const struct cfg_param {
        {"nvidia,slew-rate-falling",    TEGRA_PINCONF_PARAM_SLEW_RATE_FALLING},
        {"nvidia,slew-rate-rising",     TEGRA_PINCONF_PARAM_SLEW_RATE_RISING},
        {"nvidia,drive-type",           TEGRA_PINCONF_PARAM_DRIVE_TYPE},
-       {"nvidia,function",             TEGRA_PINCONF_PARAM_FUNCTION},
 };
 
 static int tegra_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
@@ -471,12 +470,6 @@ static int tegra_pinconf_reg(struct tegra_pmx *pmx,
                *bit = g->drvtype_bit;
                *width = 2;
                break;
-       case TEGRA_PINCONF_PARAM_FUNCTION:
-               *bank = g->mux_bank;
-               *reg = g->mux_reg;
-               *bit = g->mux_bit;
-               *width = 2;
-               break;
        default:
                dev_err(pmx->dev, "Invalid config param %04x\n", param);
                return -ENOTSUPP;
@@ -640,16 +633,8 @@ static void tegra_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
                val >>= bit;
                val &= (1 << width) - 1;
 
-               if (cfg_params[i].param == TEGRA_PINCONF_PARAM_FUNCTION) {
-                       u8 idx = pmx->soc->groups[group].funcs[val];
-
-                       seq_printf(s, "\n\t%s=%s",
-                                  strip_prefix(cfg_params[i].property),
-                                        pmx->functions[idx].name);
-               } else {
-                       seq_printf(s, "\n\t%s=%u",
-                                  strip_prefix(cfg_params[i].property), val);
-               }
+               seq_printf(s, "\n\t%s=%u",
+                          strip_prefix(cfg_params[i].property), val);
        }
 }
 
index e728efeaa4def2f2cbd822e88822c58727342e0a..b3289bdf727d8291ff6d23931eeb0b61ceae6576 100644 (file)
@@ -54,8 +54,6 @@ enum tegra_pinconf_param {
        TEGRA_PINCONF_PARAM_SLEW_RATE_RISING,
        /* argument: Integer, range is HW-dependant */
        TEGRA_PINCONF_PARAM_DRIVE_TYPE,
-       /* argument: pinmux settings */
-       TEGRA_PINCONF_PARAM_FUNCTION,
 };
 
 enum tegra_pinconf_pull {
index f3696a54a2bd72326556a7d6e60f6d76ce36eaa1..ab7d7a1235b8364f6d9b29e5926045e58579f0a6 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));
 
@@ -607,24 +609,25 @@ static void mlxbf_tmfifo_rxtx_word(struct mlxbf_tmfifo_vring *vring,
 
        if (vring->cur_len + sizeof(u64) <= len) {
                /* The whole word. */
-               if (!IS_VRING_DROP(vring)) {
-                       if (is_rx)
+               if (is_rx) {
+                       if (!IS_VRING_DROP(vring))
                                memcpy(addr + vring->cur_len, &data,
                                       sizeof(u64));
-                       else
-                               memcpy(&data, addr + vring->cur_len,
-                                      sizeof(u64));
+               } else {
+                       memcpy(&data, addr + vring->cur_len,
+                              sizeof(u64));
                }
                vring->cur_len += sizeof(u64);
        } else {
                /* Leftover bytes. */
-               if (!IS_VRING_DROP(vring)) {
-                       if (is_rx)
+               if (is_rx) {
+                       if (!IS_VRING_DROP(vring))
                                memcpy(addr + vring->cur_len, &data,
                                       len - vring->cur_len);
-                       else
-                               memcpy(&data, addr + vring->cur_len,
-                                      len - vring->cur_len);
+               } else {
+                       data = 0;
+                       memcpy(&data, addr + vring->cur_len,
+                              len - vring->cur_len);
                }
                vring->cur_len = len;
        }
index f433a13c3689a64608a0089354694a9569d4ff5e..a5a3941b3f43af4e07f4085d5a9dfd6f244cf193 100644 (file)
@@ -159,8 +159,7 @@ static int surface_platform_profile_probe(struct ssam_device *sdev)
        set_bit(PLATFORM_PROFILE_BALANCED_PERFORMANCE, tpd->handler.choices);
        set_bit(PLATFORM_PROFILE_PERFORMANCE, tpd->handler.choices);
 
-       platform_profile_register(&tpd->handler);
-       return 0;
+       return platform_profile_register(&tpd->handler);
 }
 
 static void surface_platform_profile_remove(struct ssam_device *sdev)
index ad702463a65d31cb70fce0e3654a6ec96f53f8fe..6bbffb081053e589147cc4a11d2d941f32aa3d13 100644 (file)
@@ -111,6 +111,79 @@ static const struct dmi_system_id fwbug_list[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "21A1"),
                }
        },
+       /* https://bugzilla.kernel.org/show_bug.cgi?id=218024 */
+       {
+               .ident = "V14 G4 AMN",
+               .driver_data = &quirk_s2idle_bug,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "82YT"),
+               }
+       },
+       {
+               .ident = "V14 G4 AMN",
+               .driver_data = &quirk_s2idle_bug,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "83GE"),
+               }
+       },
+       {
+               .ident = "V15 G4 AMN",
+               .driver_data = &quirk_s2idle_bug,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "82YU"),
+               }
+       },
+       {
+               .ident = "V15 G4 AMN",
+               .driver_data = &quirk_s2idle_bug,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "83CQ"),
+               }
+       },
+       {
+               .ident = "IdeaPad 1 14AMN7",
+               .driver_data = &quirk_s2idle_bug,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "82VF"),
+               }
+       },
+       {
+               .ident = "IdeaPad 1 15AMN7",
+               .driver_data = &quirk_s2idle_bug,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "82VG"),
+               }
+       },
+       {
+               .ident = "IdeaPad 1 15AMN7",
+               .driver_data = &quirk_s2idle_bug,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "82X5"),
+               }
+       },
+       {
+               .ident = "IdeaPad Slim 3 14AMN8",
+               .driver_data = &quirk_s2idle_bug,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "82XN"),
+               }
+       },
+       {
+               .ident = "IdeaPad Slim 3 15AMN8",
+               .driver_data = &quirk_s2idle_bug,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "82XQ"),
+               }
+       },
        /* https://gitlab.freedesktop.org/drm/amd/-/issues/2684 */
        {
                .ident = "HP Laptop 15s-eq2xxx",
index cadbb557a108b81014fefc07775117554b2d4bb8..1417e230edbd82fe3f6b1c58e11bcbe9a88599d2 100644 (file)
@@ -105,6 +105,8 @@ struct apple_gmux_config {
 #define GMUX_BRIGHTNESS_MASK           0x00ffffff
 #define GMUX_MAX_BRIGHTNESS            GMUX_BRIGHTNESS_MASK
 
+# define MMIO_GMUX_MAX_BRIGHTNESS      0xffff
+
 static u8 gmux_pio_read8(struct apple_gmux_data *gmux_data, int port)
 {
        return inb(gmux_data->iostart + port);
@@ -857,7 +859,17 @@ get_version:
 
        memset(&props, 0, sizeof(props));
        props.type = BACKLIGHT_PLATFORM;
-       props.max_brightness = gmux_read32(gmux_data, GMUX_PORT_MAX_BRIGHTNESS);
+
+       /*
+        * All MMIO gmux's have 0xffff as max brightness, but some iMacs incorrectly
+        * report 0x03ff, despite the firmware being happy to set 0xffff as the brightness
+        * at boot. Force 0xffff for all MMIO gmux's so they all have the correct brightness
+        * range.
+        */
+       if (type == APPLE_GMUX_TYPE_MMIO)
+               props.max_brightness = MMIO_GMUX_MAX_BRIGHTNESS;
+       else
+               props.max_brightness = gmux_read32(gmux_data, GMUX_PORT_MAX_BRIGHTNESS);
 
 #if IS_REACHABLE(CONFIG_ACPI_VIDEO)
        register_bdev = acpi_video_get_backlight_type() == acpi_backlight_apple_gmux;
index d85d895fee89431a42d94bfdde087f8e64183547..df1db54d4e183b8e34f6a0f4305d5d224aecba0e 100644 (file)
@@ -531,6 +531,9 @@ static void asus_nb_wmi_quirks(struct asus_wmi_driver *driver)
 static const struct key_entry asus_nb_wmi_keymap[] = {
        { KE_KEY, ASUS_WMI_BRN_DOWN, { KEY_BRIGHTNESSDOWN } },
        { KE_KEY, ASUS_WMI_BRN_UP, { KEY_BRIGHTNESSUP } },
+       { KE_KEY, 0x2a, { KEY_SELECTIVE_SCREENSHOT } },
+       { KE_IGNORE, 0x2b, }, /* PrintScreen (also send via PS/2) on newer models */
+       { KE_IGNORE, 0x2c, }, /* CapsLock (also send via PS/2) on newer models */
        { KE_KEY, 0x30, { KEY_VOLUMEUP } },
        { KE_KEY, 0x31, { KEY_VOLUMEDOWN } },
        { KE_KEY, 0x32, { KEY_MUTE } },
index 9f8cea5f9615aabe300d644eafd6d58fefcd275c..19bfd30861aa883159ae91d2beca8762eba36fbd 100644 (file)
@@ -3826,7 +3826,6 @@ static void asus_wmi_handle_event_code(int code, struct asus_wmi *asus)
 {
        unsigned int key_value = 1;
        bool autorelease = 1;
-       int orig_code = code;
 
        if (asus->driver->key_filter) {
                asus->driver->key_filter(asus->driver, &code, &key_value,
@@ -3835,16 +3834,10 @@ static void asus_wmi_handle_event_code(int code, struct asus_wmi *asus)
                        return;
        }
 
-       if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX)
-               code = ASUS_WMI_BRN_UP;
-       else if (code >= NOTIFY_BRNDOWN_MIN && code <= NOTIFY_BRNDOWN_MAX)
-               code = ASUS_WMI_BRN_DOWN;
-
-       if (code == ASUS_WMI_BRN_DOWN || code == ASUS_WMI_BRN_UP) {
-               if (acpi_video_get_backlight_type() == acpi_backlight_vendor) {
-                       asus_wmi_backlight_notify(asus, orig_code);
-                       return;
-               }
+       if (acpi_video_get_backlight_type() == acpi_backlight_vendor &&
+           code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNDOWN_MAX) {
+               asus_wmi_backlight_notify(asus, code);
+               return;
        }
 
        if (code == NOTIFY_KBD_BRTUP) {
index a478ebfd34dfadf28d0be0976df011f4fa854a7b..fc41d1b1bb7f8f2350dc52dce79ec444070fb1c0 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/i8042.h>
 
 #define ASUS_WMI_KEY_IGNORE (-1)
-#define ASUS_WMI_BRN_DOWN      0x20
+#define ASUS_WMI_BRN_DOWN      0x2e
 #define ASUS_WMI_BRN_UP                0x2f
 
 struct module;
index 8c4f9e12f0181d950dd6b38b0069298f5f96bd4d..5798b49ddaba901db74a072b123b7cfbb1e2ef0b 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 e76e5458db35095a55204848f3c7bdc8907fe09c..8ebb7be52ee7258981597e10e9f76355eaca002e 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 1061eb7ec39985e7d43ece8680eeeaa9096e7a00..43c864add778f82259a5969550f569cc393e276a 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 1152deaa0078e9b07d3c6051e795e8a6914f762b..33ab207493e3e62946dc5d76c2eda98805725888 100644 (file)
@@ -176,7 +176,7 @@ show_uncore_data(initial_max_freq_khz);
 
 static int create_attr_group(struct uncore_data *data, char *name)
 {
-       int ret, index = 0;
+       int ret, freq, index = 0;
 
        init_attribute_rw(max_freq_khz);
        init_attribute_rw(min_freq_khz);
@@ -197,7 +197,11 @@ static int create_attr_group(struct uncore_data *data, char *name)
        data->uncore_attrs[index++] = &data->min_freq_khz_dev_attr.attr;
        data->uncore_attrs[index++] = &data->initial_min_freq_khz_dev_attr.attr;
        data->uncore_attrs[index++] = &data->initial_max_freq_khz_dev_attr.attr;
-       data->uncore_attrs[index++] = &data->current_freq_khz_dev_attr.attr;
+
+       ret = uncore_read_freq(data, &freq);
+       if (!ret)
+               data->uncore_attrs[index++] = &data->current_freq_khz_dev_attr.attr;
+
        data->uncore_attrs[index] = NULL;
 
        data->uncore_attr_group.name = name;
index 6851d10d6582525509c2a3f05163abfbeb7a3802..a68df41334035185d5301006e4f70f1f3f29af49 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 3d96dbf79a7254f908c7c74b0a3603f87f02784b..a2ffe4157df10c1bcacc7fdd2db3a88b564fdc74 100644 (file)
@@ -6514,6 +6514,7 @@ static int mlxplat_i2c_main_init(struct mlxplat_priv *priv)
        return 0;
 
 fail_mlxplat_i2c_mux_topology_init:
+       platform_device_unregister(priv->pdev_i2c);
 fail_platform_i2c_register:
 fail_mlxplat_mlxcpld_verify_bus_topology:
        return err;
@@ -6521,6 +6522,7 @@ fail_mlxplat_mlxcpld_verify_bus_topology:
 
 static void mlxplat_i2c_main_exit(struct mlxplat_priv *priv)
 {
+       mlxplat_pre_exit(priv);
        mlxplat_i2c_mux_topology_exit(priv);
        if (priv->pdev_i2c)
                platform_device_unregister(priv->pdev_i2c);
@@ -6597,7 +6599,7 @@ static int mlxplat_probe(struct platform_device *pdev)
 
 fail_register_reboot_notifier:
 fail_regcache_sync:
-       mlxplat_pre_exit(priv);
+       mlxplat_i2c_main_exit(priv);
 fail_mlxplat_i2c_main_init:
 fail_regmap_write:
 fail_alloc:
@@ -6614,7 +6616,6 @@ static int mlxplat_remove(struct platform_device *pdev)
                pm_power_off = NULL;
        if (mlxplat_reboot_nb)
                unregister_reboot_notifier(mlxplat_reboot_nb);
-       mlxplat_pre_exit(priv);
        mlxplat_i2c_main_exit(priv);
        mlxplat_post_exit();
        return 0;
index f26a3121092f9790ea78567d4db97ae17211cbf2..492eb383ee7a9c4ff9181009963533c106eb8252 100644 (file)
@@ -276,14 +276,13 @@ static struct msi_ec_conf CONF2 __initdata = {
 
 static const char * const ALLOWED_FW_3[] __initconst = {
        "1592EMS1.111",
-       "E1592IMS.10C",
        NULL
 };
 
 static struct msi_ec_conf CONF3 __initdata = {
        .allowed_fw = ALLOWED_FW_3,
        .charge_control = {
-               .address      = 0xef,
+               .address      = 0xd7,
                .offset_start = 0x8a,
                .offset_end   = 0x80,
                .range_min    = 0x8a,
index 79346881cadb1291571d4c94cb2f56da93ec4175..aee869769843f5614ed373dd68df9764d816f5d4 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 d70c89d3253440b725bf32791a8f0d1a49f408d6..41584427dc323b7aafb7f214d9a35abc9b272d8d 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 f9301a9382e7412b3baab302207a30444bc082fb..0c6733772698408ef1a23b977d1a0698a19347d5 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),
@@ -1070,6 +1100,13 @@ const struct dmi_system_id touchscreen_dmi_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "ARCHOS 101 Cesium Educ"),
                },
        },
+       {
+               /* 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,
@@ -1480,6 +1517,14 @@ const struct dmi_system_id touchscreen_dmi_table[] = {
                        DMI_MATCH(DMI_BIOS_VERSION, "MOMO.G.WI71C.MABMRBA02"),
                },
        },
+       {
+               /* 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,
index 2f693b67ddb4a9215f270eaac3c94d3425464d47..891c1d925a9dea7f0ceecae089220e727766ec4e 100644 (file)
@@ -150,7 +150,8 @@ static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = {
        { "mclk-out-1", IMX_SC_R_MCLK_OUT_1, 1, false, 0 },
        { "dma0-ch", IMX_SC_R_DMA_0_CH0, 32, true, 0 },
        { "dma1-ch", IMX_SC_R_DMA_1_CH0, 16, true, 0 },
-       { "dma2-ch", IMX_SC_R_DMA_2_CH0, 32, true, 0 },
+       { "dma2-ch-0", IMX_SC_R_DMA_2_CH0, 5, true, 0 },
+       { "dma2-ch-1", IMX_SC_R_DMA_2_CH5, 27, true, 0 },
        { "dma3-ch", IMX_SC_R_DMA_3_CH0, 32, true, 0 },
        { "asrc0", IMX_SC_R_ASRC_0, 1, false, 0 },
        { "asrc1", IMX_SC_R_ASRC_1, 1, false, 0 },
index 59e1ebb7842e5e4ee6daa01cfd9cc99f845658d5..411e00b255d69751ac33e1f71cfbdde9482da54f 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 12dedf841a44016d6b7113ea99e59f7922501ae0..de35d24bb7ef3edcf22afbdf597ad3436cba0ae5 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 447ffdacddf9d0e77d96a3d07fb20a1ea61c475c..17064d7b19f61b1b778d34befbfd0d55ce571388 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 663a1c4238066eddacbab1a1f2ade63cc1e79807..a61bb1283e1978c717493b2197868d5ab78cd35b 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 6f83e99d2eb72e34b5666a76ecff1cf7ffd367ab..ce36d6ca3422674e72c82ae9c11a9df0de3150ed 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 ea4ad61d4c7e2ed66f386a29e367cefe5705a81a..2205ea0834a614c1aff346defec934aa2174a6cb 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 f27dae5043f5b41704b26a635db355eab5305ec7..a9641bd3d8cf8a413f9679dfb2ca9ee41ae45e75 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 06e5b6b0e255ce8bf159c2f5f0e012916fe12551..d483a81560ab0bd91c041a7a8cd71f0db315144a 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 de77df97b3a448109bc67382cacbd838d0a28088..ec163d1bcd189192abcecbcb4e29e0e4251b2e38 100644 (file)
@@ -105,7 +105,7 @@ struct qcom_battmgr_property_request {
 
 struct qcom_battmgr_update_request {
        struct pmic_glink_hdr hdr;
-       u32 battery_id;
+       __le32 battery_id;
 };
 
 struct qcom_battmgr_charge_time_request {
@@ -1282,9 +1282,9 @@ static void qcom_battmgr_enable_worker(struct work_struct *work)
 {
        struct qcom_battmgr *battmgr = container_of(work, struct qcom_battmgr, enable_work);
        struct qcom_battmgr_enable_request req = {
-               .hdr.owner = PMIC_GLINK_OWNER_BATTMGR,
-               .hdr.type = PMIC_GLINK_NOTIFY,
-               .hdr.opcode = BATTMGR_REQUEST_NOTIFICATION,
+               .hdr.owner = cpu_to_le32(PMIC_GLINK_OWNER_BATTMGR),
+               .hdr.type = cpu_to_le32(PMIC_GLINK_NOTIFY),
+               .hdr.opcode = cpu_to_le32(BATTMGR_REQUEST_NOTIFICATION),
        };
        int ret;
 
index 8328bcea1a29906e38e7d214d79b1ed3cae5972f..f64daf5a41d9383e8b98a71c1e423542b3644b30 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 683adb18253dd92fc05f62c6e7622cbd6f3412ec..fdfdc83ab045887299c8f0d154e23b9dc734cb9b 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 954feba6600b8aa7751386ee4ee7b515192312a9..7970843a4f480d70999cf54449360aedf85f9598 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 20a974ced8d6c30d09f6770409c9d49d0f6daa94..a7a6947ab4bc59d58d7df7320321e9318ce96b06 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 d8e1caaf207e108f124988b7a9f1ee3780a12e8c..3137e40fcd3e0586a81b1626304ab955a87695d4 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 5ad5f3b3a6b5d8fc91f1ea2e689a65fc087740be..d4926833655327d6a3494a5b6865087df80ad36d 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 b9cda2210c3308655a27914429c7ff52965cb03a..65fbd95f1dbb0c6935f66e32fa61d0664edb562d 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 3ef636935a547c9478dd1079c6c5b8bc9f42ffed..3ff46fc694f85e7632354bbd9eaf8fb0896f3745 100644 (file)
@@ -233,17 +233,19 @@ struct subchannel *css_alloc_subchannel(struct subchannel_id schid,
         */
        ret = dma_set_coherent_mask(&sch->dev, DMA_BIT_MASK(31));
        if (ret)
-               goto err;
+               goto err_lock;
        /*
         * But we don't have such restrictions imposed on the stuff that
         * is handled by the streaming API.
         */
        ret = dma_set_mask(&sch->dev, DMA_BIT_MASK(64));
        if (ret)
-               goto err;
+               goto err_lock;
 
        return sch;
 
+err_lock:
+       kfree(sch->lock);
 err:
        kfree(sch);
        return ERR_PTR(ret);
index 74760c1a163b90251f3c1a6b6a4ae7762710cbe9..4902d45e929ce2ad009cb3cc9fc00fac2f45483c 100644 (file)
@@ -102,7 +102,7 @@ config CCWGROUP
 
 config ISM
        tristate "Support for ISM vPCI Adapter"
-       depends on PCI && SMC
+       depends on PCI
        default n
        help
          Select this option if you want to use the Internal Shared Memory
index df782646e856fa8ea11e495583b3626af039ec41..ab2f35bc294da8a4655aff22c3342123f87e233f 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 93c68931a593fe0a77e57f4e95b5fca9dd551f50..22cef283b2b97e8da5bf35a82cfb7c4f63da710a 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 f4c8769df312ab97139549ce164694670436b77d..5895ead20e1420dab2792862faac28e4c021170a 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 984bc5fc55e2939583da80082fb4001841189f70..f27f9319e0b2e748d3a2094c4e9341c388500183 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 9761b2c9db485ed4f36b9b0023d30206bb6182ad..416d81954819f33e82571f68bdd50debc8d8e203 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 9ab8555180a3a0bd159b621a57c99bcb8f0413ae..8e14cea15f980829e99afa2c43bf6872fcfd965c 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 c3c1f466fe01d0cdd2ab42a5fc33c53fc361b307..605013d3ee83a4cab91c470d366fbbd71837a688 100644 (file)
@@ -12913,8 +12913,10 @@ _mpt3sas_init(void)
        mpt3sas_ctl_init(hbas_to_enumerate);
 
        error = pci_register_driver(&mpt3sas_driver);
-       if (error)
+       if (error) {
+               mpt3sas_ctl_exit(hbas_to_enumerate);
                scsih_exit();
+       }
 
        return error;
 }
index 50db08265c51fdf373bb7d9afb8ce251c000bd2d..dcae09a37d498fc4169decb9072ba8594fcfb4c6 100644 (file)
@@ -4953,7 +4953,7 @@ qla2x00_mem_free(struct qla_hw_data *ha)
        ha->gid_list = NULL;
        ha->gid_list_dma = 0;
 
-       if (!list_empty(&ha->base_qpair->dsd_list)) {
+       if (ha->base_qpair && !list_empty(&ha->base_qpair->dsd_list)) {
                struct dsd_dma *dsd_ptr, *tdsd_ptr;
 
                /* clean up allocated prev pool */
index d0911bc28663a8142d0fb0ae69dbad1348efa385..89367c4bf0ef5e8f2018fc725b6ffae1b87fa2f3 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 52014b2d39e1c5d41dc3be4e491f4280bf2f7f2a..44680f65ea1455daec91d4c6dd98d2cb2431f4e2 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 c92a317ba54756667ec83256fec4304cb725fac9..6effa13039f3945923f7feb1cfc3120e45f80aa1 100644 (file)
@@ -201,18 +201,93 @@ 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 &&
+                         sdp->manage_shutdown);
 }
+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;
+       bool v;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EACCES;
+
+       if (kstrtobool(buf, &v))
+               return -EINVAL;
+
+       sdp->manage_system_start_stop = v;
+
+       return count;
+}
+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 manage_shutdown_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_shutdown);
+}
+
+static ssize_t manage_shutdown_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 +299,11 @@ manage_start_stop_store(struct device *dev, struct device_attribute *attr,
        if (kstrtobool(buf, &v))
                return -EINVAL;
 
-       sdp->manage_start_stop = v;
+       sdp->manage_shutdown = v;
 
        return count;
 }
-static DEVICE_ATTR_RW(manage_start_stop);
+static DEVICE_ATTR_RW(manage_shutdown);
 
 static ssize_t
 allow_restart_show(struct device *dev, struct device_attribute *attr, char *buf)
@@ -560,6 +635,9 @@ 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_manage_shutdown.attr,
        &dev_attr_protection_type.attr,
        &dev_attr_protection_mode.attr,
        &dev_attr_app_tag_own.attr,
@@ -3694,7 +3772,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 +3850,22 @@ 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) ||
+           (system_state == SYSTEM_POWER_OFF &&
+            sdkp->device->manage_shutdown)) {
                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 +3897,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 +3917,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 +3933,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 +3956,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 +3983,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 5eea762f84d188e15b516b05f0f98ba3892209a5..409dda5350d10fb898b7bad49889ec165f257511 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 1dcd243df5677aa39dcbc76b876cdbbd435ceb43..ec87d9d878f30de6b2cc0c63d575059360ee8798 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 314e13bb3e01c52ce9cc1c7829eb3cc4dde2c17a..368344943a93c5c08ef93a513a6b84eb4acb48c1 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 bace4bc8e03b01a372fffd80a37a95a7244205db..9a469779eea75bd77518fe1934252d7a415a9703 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 796add6e8b63d43e86092e12e54ea5dd2c242437..b8e5e1e3528a6ee8252c24c59fc1a1cc8fafae69 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 5a75ab64d1ed33d7b28bc5e70e7b1f3a9b9a9402..acc812e490d0cbfc67598fe66bbc0f8d10f42c8c 100644 (file)
@@ -333,12 +333,15 @@ if RISCV
 
 config ARCH_R9A07G043
        bool "RISC-V Platform support for RZ/Five"
+       depends on NONPORTABLE
+       depends on RISCV_ALTERNATIVE
+       depends on !RISCV_ISA_ZICBOM
+       depends on RISCV_SBI
        select ARCH_RZG2L
-       select AX45MP_L2_CACHE if RISCV_DMA_NONCOHERENT
+       select AX45MP_L2_CACHE
        select DMA_GLOBAL_POOL
-       select ERRATA_ANDES if RISCV_SBI
-       select ERRATA_ANDES_CMO if ERRATA_ANDES
-
+       select ERRATA_ANDES
+       select ERRATA_ANDES_CMO
        help
          This enables support for the Renesas RZ/Five SoC.
 
index c3d3ab3262d3ab60a063ef28dc8fbd8606f3bb73..657f5888a77b0a5913e76dc47904caec94f68a62 100644 (file)
@@ -15,6 +15,10 @@ ifdef CONFIG_DEBUG_FS
 soundwire-bus-y += debugfs.o
 endif
 
+ifdef CONFIG_IRQ_DOMAIN
+soundwire-bus-y += irq.o
+endif
+
 #AMD driver
 soundwire-amd-y :=     amd_manager.o
 obj-$(CONFIG_SOUNDWIRE_AMD) += soundwire-amd.o
index 1720031f35a358a1defeddc656b6cc20035d38d2..0e7bc3c40f9dfeb1c79f694042652665ab1105c1 100644 (file)
@@ -3,13 +3,13 @@
 
 #include <linux/acpi.h>
 #include <linux/delay.h>
-#include <linux/irq.h>
 #include <linux/mod_devicetable.h>
 #include <linux/pm_runtime.h>
 #include <linux/soundwire/sdw_registers.h>
 #include <linux/soundwire/sdw.h>
 #include <linux/soundwire/sdw_type.h>
 #include "bus.h"
+#include "irq.h"
 #include "sysfs_local.h"
 
 static DEFINE_IDA(sdw_bus_ida);
@@ -25,23 +25,6 @@ static int sdw_get_id(struct sdw_bus *bus)
        return 0;
 }
 
-static int sdw_irq_map(struct irq_domain *h, unsigned int virq,
-                      irq_hw_number_t hw)
-{
-       struct sdw_bus *bus = h->host_data;
-
-       irq_set_chip_data(virq, bus);
-       irq_set_chip(virq, &bus->irq_chip);
-       irq_set_nested_thread(virq, 1);
-       irq_set_noprobe(virq);
-
-       return 0;
-}
-
-static const struct irq_domain_ops sdw_domain_ops = {
-       .map    = sdw_irq_map,
-};
-
 /**
  * sdw_bus_master_add() - add a bus Master instance
  * @bus: bus instance
@@ -168,13 +151,9 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent,
        bus->params.curr_bank = SDW_BANK0;
        bus->params.next_bank = SDW_BANK1;
 
-       bus->irq_chip.name = dev_name(bus->dev);
-       bus->domain = irq_domain_create_linear(fwnode, SDW_MAX_DEVICES,
-                                              &sdw_domain_ops, bus);
-       if (!bus->domain) {
-               dev_err(bus->dev, "Failed to add IRQ domain\n");
-               return -EINVAL;
-       }
+       ret = sdw_irq_create(bus, fwnode);
+       if (ret)
+               return ret;
 
        return 0;
 }
@@ -213,7 +192,7 @@ void sdw_bus_master_delete(struct sdw_bus *bus)
 {
        device_for_each_child(bus->dev, NULL, sdw_delete_slave);
 
-       irq_domain_remove(bus->domain);
+       sdw_irq_delete(bus);
 
        sdw_master_device_del(bus);
 
index fafbc284e82da48927b9ba5fa17b24eaae5746c2..9fa93bb923d70f03ff371b5e05cb4a03f0047d81 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/soundwire/sdw.h>
 #include <linux/soundwire/sdw_type.h>
 #include "bus.h"
+#include "irq.h"
 #include "sysfs_local.h"
 
 /**
@@ -122,11 +123,8 @@ static int sdw_drv_probe(struct device *dev)
        if (drv->ops && drv->ops->read_prop)
                drv->ops->read_prop(slave);
 
-       if (slave->prop.use_domain_irq) {
-               slave->irq = irq_create_mapping(slave->bus->domain, slave->dev_num);
-               if (!slave->irq)
-                       dev_warn(dev, "Failed to map IRQ\n");
-       }
+       if (slave->prop.use_domain_irq)
+               sdw_irq_create_mapping(slave);
 
        /* init the sysfs as we have properties now */
        ret = sdw_slave_sysfs_init(slave);
@@ -176,8 +174,7 @@ static int sdw_drv_remove(struct device *dev)
        slave->probed = false;
 
        if (slave->prop.use_domain_irq)
-               irq_dispose_mapping(irq_find_mapping(slave->bus->domain,
-                                                    slave->dev_num));
+               sdw_irq_dispose_mapping(slave);
 
        mutex_unlock(&slave->sdw_dev_lock);
 
diff --git a/drivers/soundwire/irq.c b/drivers/soundwire/irq.c
new file mode 100644 (file)
index 0000000..0c08ceb
--- /dev/null
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2023 Cirrus Logic, Inc. and
+//                    Cirrus Logic International Semiconductor Ltd.
+
+#include <linux/device.h>
+#include <linux/fwnode.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/soundwire/sdw.h>
+#include "irq.h"
+
+static int sdw_irq_map(struct irq_domain *h, unsigned int virq,
+                      irq_hw_number_t hw)
+{
+       struct sdw_bus *bus = h->host_data;
+
+       irq_set_chip_data(virq, bus);
+       irq_set_chip(virq, &bus->irq_chip);
+       irq_set_nested_thread(virq, 1);
+       irq_set_noprobe(virq);
+
+       return 0;
+}
+
+static const struct irq_domain_ops sdw_domain_ops = {
+       .map    = sdw_irq_map,
+};
+
+int sdw_irq_create(struct sdw_bus *bus,
+                  struct fwnode_handle *fwnode)
+{
+       bus->irq_chip.name = dev_name(bus->dev);
+
+       bus->domain = irq_domain_create_linear(fwnode, SDW_MAX_DEVICES,
+                                              &sdw_domain_ops, bus);
+       if (!bus->domain) {
+               dev_err(bus->dev, "Failed to add IRQ domain\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+void sdw_irq_delete(struct sdw_bus *bus)
+{
+       irq_domain_remove(bus->domain);
+}
+
+void sdw_irq_create_mapping(struct sdw_slave *slave)
+{
+       slave->irq = irq_create_mapping(slave->bus->domain, slave->dev_num);
+       if (!slave->irq)
+               dev_warn(&slave->dev, "Failed to map IRQ\n");
+}
+
+void sdw_irq_dispose_mapping(struct sdw_slave *slave)
+{
+       irq_dispose_mapping(irq_find_mapping(slave->bus->domain, slave->dev_num));
+}
diff --git a/drivers/soundwire/irq.h b/drivers/soundwire/irq.h
new file mode 100644 (file)
index 0000000..58a5804
--- /dev/null
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2023 Cirrus Logic, Inc. and
+ *                    Cirrus Logic International Semiconductor Ltd.
+ */
+
+#ifndef __SDW_IRQ_H
+#define __SDW_IRQ_H
+
+#include <linux/soundwire/sdw.h>
+#include <linux/fwnode.h>
+
+#if IS_ENABLED(CONFIG_IRQ_DOMAIN)
+
+int sdw_irq_create(struct sdw_bus *bus,
+                  struct fwnode_handle *fwnode);
+void sdw_irq_delete(struct sdw_bus *bus);
+void sdw_irq_create_mapping(struct sdw_slave *slave);
+void sdw_irq_dispose_mapping(struct sdw_slave *slave);
+
+#else /* CONFIG_IRQ_DOMAIN */
+
+static inline int sdw_irq_create(struct sdw_bus *bus,
+                                struct fwnode_handle *fwnode)
+{
+       return 0;
+}
+
+static inline void sdw_irq_delete(struct sdw_bus *bus)
+{
+}
+
+static inline void sdw_irq_create_mapping(struct sdw_slave *slave)
+{
+}
+
+static inline void sdw_irq_dispose_mapping(struct sdw_slave *slave)
+{
+}
+
+#endif /* CONFIG_IRQ_DOMAIN */
+
+#endif /* __SDW_IRQ_H */
index 453a9b37ce7857cc1a8709251f2591b41ef869d8..d239fc5a49ccca737f81f8756c3e826f7e04dc81 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 fd2fac236bbd887160bcf7e25bc65ded4eb4a947..3aff5a166c946c8d3b670203916441222832b082 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 a8a74c7cb79f85baf691df3bc7994030ed4c17f5..498e35c8db2c1d733cc33a197e5cb04d06fd6c43 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 a7381e774b95391b7780a2181a82ca35a73c773c..57d767a68e7b2766dcea5510809cf2f09e0bef63 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 0ca21ff0e9cc125c07fef757887d0c68d1038a82..e422485196884f1b5f513658ed10929c62401c29 100644 (file)
@@ -353,8 +353,9 @@ static int npcm_fiu_uma_read(struct spi_mem *mem,
                uma_cfg |= ilog2(op->cmd.buswidth);
                uma_cfg |= ilog2(op->addr.buswidth)
                        << NPCM_FIU_UMA_CFG_ADBPCK_SHIFT;
-               uma_cfg |= ilog2(op->dummy.buswidth)
-                       << NPCM_FIU_UMA_CFG_DBPCK_SHIFT;
+               if (op->dummy.nbytes)
+                       uma_cfg |= ilog2(op->dummy.buswidth)
+                               << NPCM_FIU_UMA_CFG_DBPCK_SHIFT;
                uma_cfg |= ilog2(op->data.buswidth)
                        << NPCM_FIU_UMA_CFG_RDBPCK_SHIFT;
                uma_cfg |= op->dummy.nbytes << NPCM_FIU_UMA_CFG_DBSIZ_SHIFT;
index 45a4acc956610a911674f811e2d7bf53492fd7a2..c964f41dcc428c100c1b3e4c56912e0eed379f7a 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 b6d66caba4c02eb3e988ad9a5f76317a4244af32..ef665f470c5b5ed3f24efbc5012e04e764d629ae 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 94d9a33d9af56e8c76bf7b14937d97bec190a3a9..9a46b2478f4e98bd38c794b17fa7a2bdae4e36f4 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 5d8917160d41bf8e162492dc1180f4a218055239..75c985da75b5c601c3eab05fc622978bb2671f5d 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 e98b3010520e2d0641a8579ae50a794a5425d7fa..94171e62dee9e4a5acb8ce17c35bad712f8dd268 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 b7ac60f4a21945b1545e7d7112f09efe2e906a69..b6523d4b9259e43c674e3796634fa4dc983f766b 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 372d64756ed64b10c3dd9096aa20886320837ff9..3c15f6a9e91c0a2c24dceecea1815b6bd2600068 100644 (file)
@@ -217,12 +217,12 @@ unlock:
        return rc;
 }
 
+/* mutex must be held by caller */
 static void destroy_session(struct kref *ref)
 {
        struct amdtee_session *sess = container_of(ref, struct amdtee_session,
                                                   refcount);
 
-       mutex_lock(&session_list_mutex);
        list_del(&sess->list_node);
        mutex_unlock(&session_list_mutex);
        kfree(sess);
@@ -272,7 +272,8 @@ int amdtee_open_session(struct tee_context *ctx,
        if (arg->ret != TEEC_SUCCESS) {
                pr_err("open_session failed %d\n", arg->ret);
                handle_unload_ta(ta_handle);
-               kref_put(&sess->refcount, destroy_session);
+               kref_put_mutex(&sess->refcount, destroy_session,
+                              &session_list_mutex);
                goto out;
        }
 
@@ -290,7 +291,8 @@ int amdtee_open_session(struct tee_context *ctx,
                pr_err("reached maximum session count %d\n", TEE_NUM_SESSIONS);
                handle_close_session(ta_handle, session_info);
                handle_unload_ta(ta_handle);
-               kref_put(&sess->refcount, destroy_session);
+               kref_put_mutex(&sess->refcount, destroy_session,
+                              &session_list_mutex);
                rc = -ENOMEM;
                goto out;
        }
@@ -331,7 +333,7 @@ int amdtee_close_session(struct tee_context *ctx, u32 session)
        handle_close_session(ta_handle, session_info);
        handle_unload_ta(ta_handle);
 
-       kref_put(&sess->refcount, destroy_session);
+       kref_put_mutex(&sess->refcount, destroy_session, &session_list_mutex);
 
        return 0;
 }
index 72685ee0d53f881cbaa8116fec69f465d81f7ca9..6bb5cae0968865910b00298474f1cd4330fe375b 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 409cadcc1cff7b41a0f7e6c7142f8d8793276585..754e11dcb240898d33e0af4af698ee81c3ff6615 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 6c20c9f90a05acb777b13019fa341fcb80e69320..4e6a97db894e9cfd19c0015a755c8638a3d1b3c6 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 dbdcad8d73bf63c6ba5d911d98719d12b65021dc..d8b9c734abd36345990da8401ebbcddbce39ff50 100644 (file)
@@ -41,6 +41,7 @@
 #define PHY_PORT_CS1_LINK_STATE_SHIFT  26
 
 #define ICM_TIMEOUT                    5000    /* ms */
+#define ICM_RETRIES                    3
 #define ICM_APPROVE_TIMEOUT            10000   /* ms */
 #define ICM_MAX_LINK                   4
 
@@ -296,10 +297,9 @@ static bool icm_copy(struct tb_cfg_request *req, const struct ctl_pkg *pkg)
 
 static int icm_request(struct tb *tb, const void *request, size_t request_size,
                       void *response, size_t response_size, size_t npackets,
-                      unsigned int timeout_msec)
+                      int retries, unsigned int timeout_msec)
 {
        struct icm *icm = tb_priv(tb);
-       int retries = 3;
 
        do {
                struct tb_cfg_request *req;
@@ -410,7 +410,7 @@ static int icm_fr_get_route(struct tb *tb, u8 link, u8 depth, u64 *route)
                return -ENOMEM;
 
        ret = icm_request(tb, &request, sizeof(request), switches,
-                         sizeof(*switches), npackets, ICM_TIMEOUT);
+                         sizeof(*switches), npackets, ICM_RETRIES, ICM_TIMEOUT);
        if (ret)
                goto err_free;
 
@@ -463,7 +463,7 @@ icm_fr_driver_ready(struct tb *tb, enum tb_security_level *security_level,
 
        memset(&reply, 0, sizeof(reply));
        ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
-                         1, ICM_TIMEOUT);
+                         1, ICM_RETRIES, ICM_TIMEOUT);
        if (ret)
                return ret;
 
@@ -488,7 +488,7 @@ static int icm_fr_approve_switch(struct tb *tb, struct tb_switch *sw)
        memset(&reply, 0, sizeof(reply));
        /* Use larger timeout as establishing tunnels can take some time */
        ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
-                         1, ICM_APPROVE_TIMEOUT);
+                         1, ICM_RETRIES, ICM_APPROVE_TIMEOUT);
        if (ret)
                return ret;
 
@@ -515,7 +515,7 @@ static int icm_fr_add_switch_key(struct tb *tb, struct tb_switch *sw)
 
        memset(&reply, 0, sizeof(reply));
        ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
-                         1, ICM_TIMEOUT);
+                         1, ICM_RETRIES, ICM_TIMEOUT);
        if (ret)
                return ret;
 
@@ -543,7 +543,7 @@ static int icm_fr_challenge_switch_key(struct tb *tb, struct tb_switch *sw,
 
        memset(&reply, 0, sizeof(reply));
        ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
-                         1, ICM_TIMEOUT);
+                         1, ICM_RETRIES, ICM_TIMEOUT);
        if (ret)
                return ret;
 
@@ -577,7 +577,7 @@ static int icm_fr_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd,
 
        memset(&reply, 0, sizeof(reply));
        ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
-                         1, ICM_TIMEOUT);
+                         1, ICM_RETRIES, ICM_TIMEOUT);
        if (ret)
                return ret;
 
@@ -1020,7 +1020,7 @@ icm_tr_driver_ready(struct tb *tb, enum tb_security_level *security_level,
 
        memset(&reply, 0, sizeof(reply));
        ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
-                         1, 20000);
+                         1, 10, 2000);
        if (ret)
                return ret;
 
@@ -1053,7 +1053,7 @@ static int icm_tr_approve_switch(struct tb *tb, struct tb_switch *sw)
 
        memset(&reply, 0, sizeof(reply));
        ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
-                         1, ICM_APPROVE_TIMEOUT);
+                         1, ICM_RETRIES, ICM_APPROVE_TIMEOUT);
        if (ret)
                return ret;
 
@@ -1081,7 +1081,7 @@ static int icm_tr_add_switch_key(struct tb *tb, struct tb_switch *sw)
 
        memset(&reply, 0, sizeof(reply));
        ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
-                         1, ICM_TIMEOUT);
+                         1, ICM_RETRIES, ICM_TIMEOUT);
        if (ret)
                return ret;
 
@@ -1110,7 +1110,7 @@ static int icm_tr_challenge_switch_key(struct tb *tb, struct tb_switch *sw,
 
        memset(&reply, 0, sizeof(reply));
        ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
-                         1, ICM_TIMEOUT);
+                         1, ICM_RETRIES, ICM_TIMEOUT);
        if (ret)
                return ret;
 
@@ -1144,7 +1144,7 @@ static int icm_tr_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd,
 
        memset(&reply, 0, sizeof(reply));
        ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
-                         1, ICM_TIMEOUT);
+                         1, ICM_RETRIES, ICM_TIMEOUT);
        if (ret)
                return ret;
 
@@ -1170,7 +1170,7 @@ static int icm_tr_xdomain_tear_down(struct tb *tb, struct tb_xdomain *xd,
 
        memset(&reply, 0, sizeof(reply));
        ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
-                         1, ICM_TIMEOUT);
+                         1, ICM_RETRIES, ICM_TIMEOUT);
        if (ret)
                return ret;
 
@@ -1496,7 +1496,7 @@ icm_ar_driver_ready(struct tb *tb, enum tb_security_level *security_level,
 
        memset(&reply, 0, sizeof(reply));
        ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
-                         1, ICM_TIMEOUT);
+                         1, ICM_RETRIES, ICM_TIMEOUT);
        if (ret)
                return ret;
 
@@ -1522,7 +1522,7 @@ static int icm_ar_get_route(struct tb *tb, u8 link, u8 depth, u64 *route)
 
        memset(&reply, 0, sizeof(reply));
        ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
-                         1, ICM_TIMEOUT);
+                         1, ICM_RETRIES, ICM_TIMEOUT);
        if (ret)
                return ret;
 
@@ -1543,7 +1543,7 @@ static int icm_ar_get_boot_acl(struct tb *tb, uuid_t *uuids, size_t nuuids)
 
        memset(&reply, 0, sizeof(reply));
        ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
-                         1, ICM_TIMEOUT);
+                         1, ICM_RETRIES, ICM_TIMEOUT);
        if (ret)
                return ret;
 
@@ -1604,7 +1604,7 @@ static int icm_ar_set_boot_acl(struct tb *tb, const uuid_t *uuids,
 
        memset(&reply, 0, sizeof(reply));
        ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
-                         1, ICM_TIMEOUT);
+                         1, ICM_RETRIES, ICM_TIMEOUT);
        if (ret)
                return ret;
 
@@ -1626,7 +1626,7 @@ icm_icl_driver_ready(struct tb *tb, enum tb_security_level *security_level,
 
        memset(&reply, 0, sizeof(reply));
        ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
-                         1, 20000);
+                         1, ICM_RETRIES, 20000);
        if (ret)
                return ret;
 
@@ -2298,7 +2298,7 @@ static int icm_usb4_switch_op(struct tb_switch *sw, u16 opcode, u32 *metadata,
 
        memset(&reply, 0, sizeof(reply));
        ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
-                         1, ICM_TIMEOUT);
+                         1, ICM_RETRIES, ICM_TIMEOUT);
        if (ret)
                return ret;
 
index 43171cc1cc2d83c223bef20dad7a18fd22841c0e..bd5815f8f23bd61a92fd45b8e263e4b8acb067f5 100644 (file)
@@ -2725,6 +2725,13 @@ int tb_switch_lane_bonding_enable(struct tb_switch *sw)
            !tb_port_is_width_supported(down, TB_LINK_WIDTH_DUAL))
                return 0;
 
+       /*
+        * Both lanes need to be in CL0. Here we assume lane 0 already be in
+        * CL0 and check just for lane 1.
+        */
+       if (tb_wait_for_port(down->dual_link_port, false) <= 0)
+               return -ENOTCONN;
+
        ret = tb_port_lane_bonding_enable(up);
        if (ret) {
                tb_port_warn(up, "failed to enable lane bonding\n");
index dd0a1ef8cf1217e2e21dc204a17b65fafc7ebd86..27bd6ca6f99e4101b8b4d8c9eab8c58cfd034726 100644 (file)
@@ -1907,14 +1907,14 @@ static void tb_handle_dp_bandwidth_request(struct work_struct *work)
        in = &sw->ports[ev->port];
        if (!tb_port_is_dpin(in)) {
                tb_port_warn(in, "bandwidth request to non-DP IN adapter\n");
-               goto unlock;
+               goto put_sw;
        }
 
        tb_port_dbg(in, "handling bandwidth allocation request\n");
 
        if (!usb4_dp_port_bandwidth_mode_enabled(in)) {
                tb_port_warn(in, "bandwidth allocation mode not enabled\n");
-               goto unlock;
+               goto put_sw;
        }
 
        ret = usb4_dp_port_requested_bandwidth(in);
@@ -1923,7 +1923,7 @@ static void tb_handle_dp_bandwidth_request(struct work_struct *work)
                        tb_port_dbg(in, "no bandwidth request active\n");
                else
                        tb_port_warn(in, "failed to read requested bandwidth\n");
-               goto unlock;
+               goto put_sw;
        }
        requested_bw = ret;
 
@@ -1932,7 +1932,7 @@ static void tb_handle_dp_bandwidth_request(struct work_struct *work)
        tunnel = tb_find_tunnel(tb, TB_TUNNEL_DP, in, NULL);
        if (!tunnel) {
                tb_port_warn(in, "failed to find tunnel\n");
-               goto unlock;
+               goto put_sw;
        }
 
        out = tunnel->dst_port;
@@ -1959,6 +1959,8 @@ static void tb_handle_dp_bandwidth_request(struct work_struct *work)
                tb_recalc_estimated_bandwidth(tb);
        }
 
+put_sw:
+       tb_switch_put(sw);
 unlock:
        mutex_unlock(&tb->lock);
 
index 747f88703d5ca118f07209ae9989fb4008802b8f..11f2aec2a5d374ede2c87215a184284009dc8e9e 100644 (file)
@@ -382,7 +382,7 @@ static int tmu_mode_init(struct tb_switch *sw)
                } else if (ucap && tb_port_tmu_is_unidirectional(up)) {
                        if (tmu_rates[TB_SWITCH_TMU_MODE_LOWRES] == rate)
                                sw->tmu.mode = TB_SWITCH_TMU_MODE_LOWRES;
-                       else if (tmu_rates[TB_SWITCH_TMU_MODE_LOWRES] == rate)
+                       else if (tmu_rates[TB_SWITCH_TMU_MODE_HIFI_UNI] == rate)
                                sw->tmu.mode = TB_SWITCH_TMU_MODE_HIFI_UNI;
                } else if (rate) {
                        sw->tmu.mode = TB_SWITCH_TMU_MODE_HIFI_BI;
index 5b5566862318b99ee6e597c2713285839ca7ddad..9803f0bbf20d14fe07efc408b99a9e7a5e6cfef8 100644 (file)
@@ -703,6 +703,27 @@ out_unlock:
        mutex_unlock(&xdomain_lock);
 }
 
+static void start_handshake(struct tb_xdomain *xd)
+{
+       xd->state = XDOMAIN_STATE_INIT;
+       queue_delayed_work(xd->tb->wq, &xd->state_work,
+                          msecs_to_jiffies(XDOMAIN_SHORT_TIMEOUT));
+}
+
+/* Can be called from state_work */
+static void __stop_handshake(struct tb_xdomain *xd)
+{
+       cancel_delayed_work_sync(&xd->properties_changed_work);
+       xd->properties_changed_retries = 0;
+       xd->state_retries = 0;
+}
+
+static void stop_handshake(struct tb_xdomain *xd)
+{
+       cancel_delayed_work_sync(&xd->state_work);
+       __stop_handshake(xd);
+}
+
 static void tb_xdp_handle_request(struct work_struct *work)
 {
        struct xdomain_request_work *xw = container_of(work, typeof(*xw), work);
@@ -765,6 +786,15 @@ static void tb_xdp_handle_request(struct work_struct *work)
        case UUID_REQUEST:
                tb_dbg(tb, "%llx: received XDomain UUID request\n", route);
                ret = tb_xdp_uuid_response(ctl, route, sequence, uuid);
+               /*
+                * If we've stopped the discovery with an error such as
+                * timing out, we will restart the handshake now that we
+                * received UUID request from the remote host.
+                */
+               if (!ret && xd && xd->state == XDOMAIN_STATE_ERROR) {
+                       dev_dbg(&xd->dev, "restarting handshake\n");
+                       start_handshake(xd);
+               }
                break;
 
        case LINK_STATE_STATUS_REQUEST:
@@ -1521,6 +1551,13 @@ static void tb_xdomain_queue_properties_changed(struct tb_xdomain *xd)
                           msecs_to_jiffies(XDOMAIN_SHORT_TIMEOUT));
 }
 
+static void tb_xdomain_failed(struct tb_xdomain *xd)
+{
+       xd->state = XDOMAIN_STATE_ERROR;
+       queue_delayed_work(xd->tb->wq, &xd->state_work,
+                          msecs_to_jiffies(XDOMAIN_DEFAULT_TIMEOUT));
+}
+
 static void tb_xdomain_state_work(struct work_struct *work)
 {
        struct tb_xdomain *xd = container_of(work, typeof(*xd), state_work.work);
@@ -1547,7 +1584,7 @@ static void tb_xdomain_state_work(struct work_struct *work)
                if (ret) {
                        if (ret == -EAGAIN)
                                goto retry_state;
-                       xd->state = XDOMAIN_STATE_ERROR;
+                       tb_xdomain_failed(xd);
                } else {
                        tb_xdomain_queue_properties_changed(xd);
                        if (xd->bonding_possible)
@@ -1612,7 +1649,7 @@ static void tb_xdomain_state_work(struct work_struct *work)
                if (ret) {
                        if (ret == -EAGAIN)
                                goto retry_state;
-                       xd->state = XDOMAIN_STATE_ERROR;
+                       tb_xdomain_failed(xd);
                } else {
                        xd->state = XDOMAIN_STATE_ENUMERATED;
                }
@@ -1623,6 +1660,8 @@ static void tb_xdomain_state_work(struct work_struct *work)
                break;
 
        case XDOMAIN_STATE_ERROR:
+               dev_dbg(&xd->dev, "discovery failed, stopping handshake\n");
+               __stop_handshake(xd);
                break;
 
        default:
@@ -1833,21 +1872,6 @@ static void tb_xdomain_release(struct device *dev)
        kfree(xd);
 }
 
-static void start_handshake(struct tb_xdomain *xd)
-{
-       xd->state = XDOMAIN_STATE_INIT;
-       queue_delayed_work(xd->tb->wq, &xd->state_work,
-                          msecs_to_jiffies(XDOMAIN_SHORT_TIMEOUT));
-}
-
-static void stop_handshake(struct tb_xdomain *xd)
-{
-       cancel_delayed_work_sync(&xd->properties_changed_work);
-       cancel_delayed_work_sync(&xd->state_work);
-       xd->properties_changed_retries = 0;
-       xd->state_retries = 0;
-}
-
 static int __maybe_unused tb_xdomain_suspend(struct device *dev)
 {
        stop_handshake(tb_to_xdomain(dev));
index b3550ff9c4942778d9d4afaa4cbcef6f692d6eb1..1f3aba607cd51dcc389d1c9ad723643e476e7d13 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 26dd089d8e82b0af90303d9a1299f5cc50252e01..ca972fd377256c997d37655c6dd634a2077695d3 100644 (file)
@@ -1617,7 +1617,7 @@ static int omap8250_suspend(struct device *dev)
 {
        struct omap8250_priv *priv = dev_get_drvdata(dev);
        struct uart_8250_port *up = serial8250_get_port(priv->line);
-       int err;
+       int err = 0;
 
        serial8250_suspend_port(priv->line);
 
@@ -1627,7 +1627,8 @@ static int omap8250_suspend(struct device *dev)
        if (!device_may_wakeup(dev))
                priv->wer = 0;
        serial_out(up, UART_OMAP_WER, priv->wer);
-       err = pm_runtime_force_suspend(dev);
+       if (uart_console(&up->port) && console_suspend_enabled)
+               err = pm_runtime_force_suspend(dev);
        flush_work(&priv->qos_work);
 
        return err;
@@ -1636,11 +1637,15 @@ static int omap8250_suspend(struct device *dev)
 static int omap8250_resume(struct device *dev)
 {
        struct omap8250_priv *priv = dev_get_drvdata(dev);
+       struct uart_8250_port *up = serial8250_get_port(priv->line);
        int err;
 
-       err = pm_runtime_force_resume(dev);
-       if (err)
-               return err;
+       if (uart_console(&up->port) && console_suspend_enabled) {
+               err = pm_runtime_force_resume(dev);
+               if (err)
+                       return err;
+       }
+
        serial8250_resume_port(priv->line);
        /* Paired with pm_runtime_resume_and_get() in omap8250_suspend() */
        pm_runtime_mark_last_busy(dev);
@@ -1717,16 +1722,6 @@ static int omap8250_runtime_suspend(struct device *dev)
 
        if (priv->line >= 0)
                up = serial8250_get_port(priv->line);
-       /*
-        * When using 'no_console_suspend', the console UART must not be
-        * suspended. Since driver suspend is managed by runtime suspend,
-        * preventing runtime suspend (by returning error) will keep device
-        * active during suspend.
-        */
-       if (priv->is_suspending && !console_suspend_enabled) {
-               if (up && uart_console(&up->port))
-                       return -EBUSY;
-       }
 
        if (priv->habit & UART_ERRATA_CLOCK_DISABLE) {
                int ret;
index fb891b67968f0fb61914293b8aeea0b00f68427b..141627370aabc334936aa560f4881ec258005fbc 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 7bdc21d5e13bce277f49e7a826f13c0d084ee252..d5ba6e90bd95ffd73b57a48eaf35210d2e563ec5 100644 (file)
@@ -156,7 +156,7 @@ static void __uart_start(struct uart_state *state)
         * enabled, serial_port_runtime_resume() calls start_tx() again
         * after enabling the device.
         */
-       if (pm_runtime_active(&port_dev->dev))
+       if (!pm_runtime_enabled(port->dev) || pm_runtime_active(port->dev))
                port->ops->start_tx(port);
        pm_runtime_mark_last_busy(&port_dev->dev);
        pm_runtime_put_autosuspend(&port_dev->dev);
@@ -1404,12 +1404,18 @@ static void uart_set_rs485_termination(struct uart_port *port,
 static int uart_rs485_config(struct uart_port *port)
 {
        struct serial_rs485 *rs485 = &port->rs485;
+       unsigned long flags;
        int ret;
 
+       if (!(rs485->flags & SER_RS485_ENABLED))
+               return 0;
+
        uart_sanitize_serial_rs485(port, rs485);
        uart_set_rs485_termination(port, rs485);
 
+       spin_lock_irqsave(&port->lock, flags);
        ret = port->rs485_config(port, NULL, rs485);
+       spin_unlock_irqrestore(&port->lock, flags);
        if (ret)
                memset(rs485, 0, sizeof(*rs485));
 
@@ -2474,11 +2480,10 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
                        if (ret == 0) {
                                if (tty)
                                        uart_change_line_settings(tty, state, NULL);
+                               uart_rs485_config(uport);
                                spin_lock_irq(&uport->lock);
                                if (!(uport->rs485.flags & SER_RS485_ENABLED))
                                        ops->set_mctrl(uport, uport->mctrl);
-                               else
-                                       uart_rs485_config(uport);
                                ops->start_tx(uport);
                                spin_unlock_irq(&uport->lock);
                                tty_port_set_initialized(port, true);
@@ -2587,10 +2592,10 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state,
                port->mctrl &= TIOCM_DTR;
                if (!(port->rs485.flags & SER_RS485_ENABLED))
                        port->ops->set_mctrl(port, port->mctrl);
-               else
-                       uart_rs485_config(port);
                spin_unlock_irqrestore(&port->lock, flags);
 
+               uart_rs485_config(port);
+
                /*
                 * If this driver supports console, and it hasn't been
                 * successfully registered yet, try to re-register it.
index c2df07545f966bb566846341bdafabb6ead242ad..8382e8cfa414a03553f114644d29b2777ec66ec1 100644 (file)
@@ -6895,7 +6895,7 @@ static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int tag)
                        mask, 0, 1000, 1000);
 
        dev_err(hba->dev, "Clearing task management function with tag %d %s\n",
-               tag, err ? "succeeded" : "failed");
+               tag, err < 0 ? "failed" : "succeeded");
 
 out:
        return err;
index fff9ec9c391fae2deb8c43cde5574455ee08540a..4b67749edb997490b3d6a37991fc76f807c36145 100644 (file)
@@ -1125,6 +1125,9 @@ static int cdnsp_gadget_ep_dequeue(struct usb_ep *ep,
        unsigned long flags;
        int ret;
 
+       if (request->status != -EINPROGRESS)
+               return 0;
+
        if (!pep->endpoint.desc) {
                dev_err(pdev->dev,
                        "%s: can't dequeue to disabled endpoint\n",
index 4a4dbc2c156151e33871276fc12c359c53c8833b..81a9c9d6be08b9faa2558f3bc5595397d313feb7 100644 (file)
@@ -131,8 +131,7 @@ void cdns_set_active(struct cdns *cdns, u8 set_active);
 #else /* CONFIG_PM_SLEEP */
 static inline int cdns_resume(struct cdns *cdns)
 { return 0; }
-static inline int cdns_set_active(struct cdns *cdns, u8 set_active)
-{ return 0; }
+static inline void cdns_set_active(struct cdns *cdns, u8 set_active) { }
 static inline int cdns_suspend(struct cdns *cdns)
 { return 0; }
 #endif /* CONFIG_PM_SLEEP */
index 3c54b218301c1630b012f48f12d3c3e7f5f603aa..0ff47eeffb490985f62725d8d42d43fb9ecd5b26 100644 (file)
@@ -151,6 +151,10 @@ int usb_device_supports_lpm(struct usb_device *udev)
        if (udev->quirks & USB_QUIRK_NO_LPM)
                return 0;
 
+       /* Skip if the device BOS descriptor couldn't be read */
+       if (!udev->bos)
+               return 0;
+
        /* USB 2.1 (and greater) devices indicate LPM support through
         * their USB 2.0 Extended Capabilities BOS descriptor.
         */
@@ -327,6 +331,10 @@ static void usb_set_lpm_parameters(struct usb_device *udev)
        if (!udev->lpm_capable || udev->speed < USB_SPEED_SUPER)
                return;
 
+       /* Skip if the device BOS descriptor couldn't be read */
+       if (!udev->bos)
+               return;
+
        hub = usb_hub_to_struct_hub(udev->parent);
        /* It doesn't take time to transition the roothub into U0, since it
         * doesn't have an upstream link.
@@ -2704,13 +2712,17 @@ out_authorized:
 static enum usb_ssp_rate get_port_ssp_rate(struct usb_device *hdev,
                                           u32 ext_portstatus)
 {
-       struct usb_ssp_cap_descriptor *ssp_cap = hdev->bos->ssp_cap;
+       struct usb_ssp_cap_descriptor *ssp_cap;
        u32 attr;
        u8 speed_id;
        u8 ssac;
        u8 lanes;
        int i;
 
+       if (!hdev->bos)
+               goto out;
+
+       ssp_cap = hdev->bos->ssp_cap;
        if (!ssp_cap)
                goto out;
 
@@ -4215,8 +4227,15 @@ static void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev,
                enum usb3_link_state state)
 {
        int timeout;
-       __u8 u1_mel = udev->bos->ss_cap->bU1devExitLat;
-       __le16 u2_mel = udev->bos->ss_cap->bU2DevExitLat;
+       __u8 u1_mel;
+       __le16 u2_mel;
+
+       /* Skip if the device BOS descriptor couldn't be read */
+       if (!udev->bos)
+               return;
+
+       u1_mel = udev->bos->ss_cap->bU1devExitLat;
+       u2_mel = udev->bos->ss_cap->bU2DevExitLat;
 
        /* If the device says it doesn't have *any* exit latency to come out of
         * U1 or U2, it's probably lying.  Assume it doesn't implement that link
index 37897afd1b64989e801953a025f3a18941521220..d44dd7f6623ee6e778f7f4b3ba0fc578ddd1b848 100644 (file)
@@ -153,7 +153,7 @@ static inline int hub_is_superspeedplus(struct usb_device *hdev)
 {
        return (hdev->descriptor.bDeviceProtocol == USB_HUB_PR_SS &&
                le16_to_cpu(hdev->descriptor.bcdUSB) >= 0x0310 &&
-               hdev->bos->ssp_cap);
+               hdev->bos && hdev->bos->ssp_cap);
 }
 
 static inline unsigned hub_power_on_good_delay(struct usb_hub *hub)
index 9c6bf054f15d463227b3fd447f2db4832a903676..343d2570189ff918234635365d15c3cb17bda0c4 100644 (file)
@@ -279,9 +279,46 @@ int dwc3_core_soft_reset(struct dwc3 *dwc)
         * XHCI driver will reset the host block. If dwc3 was configured for
         * host-only mode or current role is host, then we can return early.
         */
-       if (dwc->dr_mode == USB_DR_MODE_HOST || dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST)
+       if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST)
                return 0;
 
+       /*
+        * If the dr_mode is host and the dwc->current_dr_role is not the
+        * corresponding DWC3_GCTL_PRTCAP_HOST, then the dwc3_core_init_mode
+        * isn't executed yet. Ensure the phy is ready before the controller
+        * updates the GCTL.PRTCAPDIR or other settings by soft-resetting
+        * the phy.
+        *
+        * Note: GUSB3PIPECTL[n] and GUSB2PHYCFG[n] are port settings where n
+        * is port index. If this is a multiport host, then we need to reset
+        * all active ports.
+        */
+       if (dwc->dr_mode == USB_DR_MODE_HOST) {
+               u32 usb3_port;
+               u32 usb2_port;
+
+               usb3_port = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
+               usb3_port |= DWC3_GUSB3PIPECTL_PHYSOFTRST;
+               dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), usb3_port);
+
+               usb2_port = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+               usb2_port |= DWC3_GUSB2PHYCFG_PHYSOFTRST;
+               dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), usb2_port);
+
+               /* Small delay for phy reset assertion */
+               usleep_range(1000, 2000);
+
+               usb3_port &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST;
+               dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), usb3_port);
+
+               usb2_port &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST;
+               dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), usb2_port);
+
+               /* Wait for clock synchronization */
+               msleep(50);
+               return 0;
+       }
+
        reg = dwc3_readl(dwc->regs, DWC3_DCTL);
        reg |= DWC3_DCTL_CSFTRST;
        reg &= ~DWC3_DCTL_RUN_STOP;
index feccf4c8cc4fb3d51640d74196347c643df9d0b6..e6ab8cc225ffdc8cac3c9ba115afd2fc78d77d92 100644 (file)
@@ -1156,7 +1156,8 @@ static int ncm_unwrap_ntb(struct gether *port,
                          struct sk_buff_head *list)
 {
        struct f_ncm    *ncm = func_to_ncm(&port->func);
-       __le16          *tmp = (void *) skb->data;
+       unsigned char   *ntb_ptr = skb->data;
+       __le16          *tmp;
        unsigned        index, index2;
        int             ndp_index;
        unsigned        dg_len, dg_len2;
@@ -1169,6 +1170,10 @@ static int ncm_unwrap_ntb(struct gether *port,
        const struct ndp_parser_opts *opts = ncm->parser_opts;
        unsigned        crc_len = ncm->is_crc ? sizeof(uint32_t) : 0;
        int             dgram_counter;
+       int             to_process = skb->len;
+
+parse_ntb:
+       tmp = (__le16 *)ntb_ptr;
 
        /* dwSignature */
        if (get_unaligned_le32(tmp) != opts->nth_sign) {
@@ -1215,7 +1220,7 @@ static int ncm_unwrap_ntb(struct gether *port,
                 * walk through NDP
                 * dwSignature
                 */
-               tmp = (void *)(skb->data + ndp_index);
+               tmp = (__le16 *)(ntb_ptr + ndp_index);
                if (get_unaligned_le32(tmp) != ncm->ndp_sign) {
                        INFO(port->func.config->cdev, "Wrong NDP SIGN\n");
                        goto err;
@@ -1272,11 +1277,11 @@ static int ncm_unwrap_ntb(struct gether *port,
                        if (ncm->is_crc) {
                                uint32_t crc, crc2;
 
-                               crc = get_unaligned_le32(skb->data +
+                               crc = get_unaligned_le32(ntb_ptr +
                                                         index + dg_len -
                                                         crc_len);
                                crc2 = ~crc32_le(~0,
-                                                skb->data + index,
+                                                ntb_ptr + index,
                                                 dg_len - crc_len);
                                if (crc != crc2) {
                                        INFO(port->func.config->cdev,
@@ -1303,7 +1308,7 @@ static int ncm_unwrap_ntb(struct gether *port,
                                                         dg_len - crc_len);
                        if (skb2 == NULL)
                                goto err;
-                       skb_put_data(skb2, skb->data + index,
+                       skb_put_data(skb2, ntb_ptr + index,
                                     dg_len - crc_len);
 
                        skb_queue_tail(list, skb2);
@@ -1316,10 +1321,17 @@ static int ncm_unwrap_ntb(struct gether *port,
                } while (ndp_len > 2 * (opts->dgram_item_len * 2));
        } while (ndp_index);
 
-       dev_consume_skb_any(skb);
-
        VDBG(port->func.config->cdev,
             "Parsed NTB with %d frames\n", dgram_counter);
+
+       to_process -= block_len;
+       if (to_process != 0) {
+               ntb_ptr = (unsigned char *)(ntb_ptr + block_len);
+               goto parse_ntb;
+       }
+
+       dev_consume_skb_any(skb);
+
        return 0;
 err:
        skb_queue_purge(list);
index 56b8286a8009197e9057202d6b0e13b1c5e3125d..74590f93ea617dad1136161235bbfa789355f403 100644 (file)
@@ -497,11 +497,13 @@ static int xudc_eptxrx(struct xusb_ep *ep, struct xusb_req *req,
                /* Get the Buffer address and copy the transmit data.*/
                eprambase = (u32 __force *)(udc->addr + ep->rambase);
                if (ep->is_in) {
-                       memcpy(eprambase, bufferptr, bytestosend);
+                       memcpy_toio((void __iomem *)eprambase, bufferptr,
+                                   bytestosend);
                        udc->write_fn(udc->addr, ep->offset +
                                      XUSB_EP_BUF0COUNT_OFFSET, bufferlen);
                } else {
-                       memcpy(bufferptr, eprambase, bytestosend);
+                       memcpy_toio((void __iomem *)bufferptr, eprambase,
+                                   bytestosend);
                }
                /*
                 * Enable the buffer for transmission.
@@ -515,11 +517,13 @@ static int xudc_eptxrx(struct xusb_ep *ep, struct xusb_req *req,
                eprambase = (u32 __force *)(udc->addr + ep->rambase +
                             ep->ep_usb.maxpacket);
                if (ep->is_in) {
-                       memcpy(eprambase, bufferptr, bytestosend);
+                       memcpy_toio((void __iomem *)eprambase, bufferptr,
+                                   bytestosend);
                        udc->write_fn(udc->addr, ep->offset +
                                      XUSB_EP_BUF1COUNT_OFFSET, bufferlen);
                } else {
-                       memcpy(bufferptr, eprambase, bytestosend);
+                       memcpy_toio((void __iomem *)bufferptr, eprambase,
+                                   bytestosend);
                }
                /*
                 * Enable the buffer for transmission.
@@ -1021,7 +1025,7 @@ static int __xudc_ep0_queue(struct xusb_ep *ep0, struct xusb_req *req)
                           udc->addr);
                length = req->usb_req.actual = min_t(u32, length,
                                                     EP0_MAX_PACKET);
-               memcpy(corebuf, req->usb_req.buf, length);
+               memcpy_toio((void __iomem *)corebuf, req->usb_req.buf, length);
                udc->write_fn(udc->addr, XUSB_EP_BUF0COUNT_OFFSET, length);
                udc->write_fn(udc->addr, XUSB_BUFFREADY_OFFSET, 1);
        } else {
@@ -1752,7 +1756,7 @@ static void xudc_handle_setup(struct xusb_udc *udc)
 
        /* Load up the chapter 9 command buffer.*/
        ep0rambase = (u32 __force *) (udc->addr + XUSB_SETUP_PKT_ADDR_OFFSET);
-       memcpy(&setup, ep0rambase, 8);
+       memcpy_toio((void __iomem *)&setup, ep0rambase, 8);
 
        udc->setup = setup;
        udc->setup.wValue = cpu_to_le16((u16 __force)setup.wValue);
@@ -1839,7 +1843,7 @@ static void xudc_ep0_out(struct xusb_udc *udc)
                             (ep0->rambase << 2));
                buffer = req->usb_req.buf + req->usb_req.actual;
                req->usb_req.actual = req->usb_req.actual + bytes_to_rx;
-               memcpy(buffer, ep0rambase, bytes_to_rx);
+               memcpy_toio((void __iomem *)buffer, ep0rambase, bytes_to_rx);
 
                if (req->usb_req.length == req->usb_req.actual) {
                        /* Data transfer completed get ready for Status stage */
@@ -1915,7 +1919,7 @@ static void xudc_ep0_in(struct xusb_udc *udc)
                                     (ep0->rambase << 2));
                        buffer = req->usb_req.buf + req->usb_req.actual;
                        req->usb_req.actual = req->usb_req.actual + length;
-                       memcpy(ep0rambase, buffer, length);
+                       memcpy_toio((void __iomem *)ep0rambase, buffer, length);
                }
                udc->write_fn(udc->addr, XUSB_EP_BUF0COUNT_OFFSET, count);
                udc->write_fn(udc->addr, XUSB_BUFFREADY_OFFSET, 1);
index 0054d02239e2893646c44efc3b14e58cff3fdcc0..0df5d807a77e8f2ae2f15a3eed55415493c4ac3f 100644 (file)
@@ -1062,19 +1062,19 @@ static void xhci_get_usb3_port_status(struct xhci_port *port, u32 *status,
                *status |= USB_PORT_STAT_C_CONFIG_ERROR << 16;
 
        /* USB3 specific wPortStatus bits */
-       if (portsc & PORT_POWER) {
+       if (portsc & PORT_POWER)
                *status |= USB_SS_PORT_STAT_POWER;
-               /* link state handling */
-               if (link_state == XDEV_U0)
-                       bus_state->suspended_ports &= ~(1 << portnum);
-       }
 
-       /* remote wake resume signaling complete */
-       if (bus_state->port_remote_wakeup & (1 << portnum) &&
+       /* no longer suspended or resuming */
+       if (link_state != XDEV_U3 &&
            link_state != XDEV_RESUME &&
            link_state != XDEV_RECOVERY) {
-               bus_state->port_remote_wakeup &= ~(1 << portnum);
-               usb_hcd_end_port_resume(&hcd->self, portnum);
+               /* remote wake resume signaling complete */
+               if (bus_state->port_remote_wakeup & (1 << portnum)) {
+                       bus_state->port_remote_wakeup &= ~(1 << portnum);
+                       usb_hcd_end_port_resume(&hcd->self, portnum);
+               }
+               bus_state->suspended_ports &= ~(1 << portnum);
        }
 
        xhci_hub_report_usb3_link_state(xhci, status, portsc);
@@ -1131,6 +1131,7 @@ static void xhci_get_usb2_port_status(struct xhci_port *port, u32 *status,
                        usb_hcd_end_port_resume(&port->rhub->hcd->self, portnum);
                }
                port->rexit_active = 0;
+               bus_state->suspended_ports &= ~(1 << portnum);
        }
 }
 
index 8714ab5bf04d6b7ebf4c69d625786475d7fc27d3..0a37f0d511cf53c377ac52669573086e4d5fb577 100644 (file)
@@ -2285,8 +2285,8 @@ xhci_add_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir,
        writel(erst_size, &ir->ir_set->erst_size);
 
        erst_base = xhci_read_64(xhci, &ir->ir_set->erst_base);
-       erst_base &= ERST_PTR_MASK;
-       erst_base |= (ir->erst.erst_dma_addr & (u64) ~ERST_PTR_MASK);
+       erst_base &= ERST_BASE_RSVDP;
+       erst_base |= ir->erst.erst_dma_addr & ~ERST_BASE_RSVDP;
        xhci_write_64(xhci, erst_base, &ir->ir_set->erst_base);
 
        /* Set the event ring dequeue address of this interrupter */
index 1dde53f6eb317a246da4cc8feaa3044c9c3de04b..3e5dc0723a8fc2aa73348fd6c59c4dc442ea6989 100644 (file)
@@ -798,7 +798,7 @@ static void xhci_giveback_urb_in_irq(struct xhci_hcd *xhci,
 static void xhci_unmap_td_bounce_buffer(struct xhci_hcd *xhci,
                struct xhci_ring *ring, struct xhci_td *td)
 {
-       struct device *dev = xhci_to_hcd(xhci)->self.controller;
+       struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
        struct xhci_segment *seg = td->bounce_seg;
        struct urb *urb = td->urb;
        size_t len;
@@ -2996,7 +2996,8 @@ static int xhci_handle_event(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
  */
 static void xhci_update_erst_dequeue(struct xhci_hcd *xhci,
                                     struct xhci_interrupter *ir,
-                                    union xhci_trb *event_ring_deq)
+                                    union xhci_trb *event_ring_deq,
+                                    bool clear_ehb)
 {
        u64 temp_64;
        dma_addr_t deq;
@@ -3017,12 +3018,13 @@ static void xhci_update_erst_dequeue(struct xhci_hcd *xhci,
                        return;
 
                /* Update HC event ring dequeue pointer */
-               temp_64 &= ERST_PTR_MASK;
+               temp_64 &= ERST_DESI_MASK;
                temp_64 |= ((u64) deq & (u64) ~ERST_PTR_MASK);
        }
 
        /* Clear the event handler busy flag (RW1C) */
-       temp_64 |= ERST_EHB;
+       if (clear_ehb)
+               temp_64 |= ERST_EHB;
        xhci_write_64(xhci, temp_64, &ir->ir_set->erst_dequeue);
 }
 
@@ -3103,7 +3105,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
        while (xhci_handle_event(xhci, ir) > 0) {
                if (event_loop++ < TRBS_PER_SEGMENT / 2)
                        continue;
-               xhci_update_erst_dequeue(xhci, ir, event_ring_deq);
+               xhci_update_erst_dequeue(xhci, ir, event_ring_deq, false);
                event_ring_deq = ir->event_ring->dequeue;
 
                /* ring is half-full, force isoc trbs to interrupt more often */
@@ -3113,7 +3115,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
                event_loop = 0;
        }
 
-       xhci_update_erst_dequeue(xhci, ir, event_ring_deq);
+       xhci_update_erst_dequeue(xhci, ir, event_ring_deq, true);
        ret = IRQ_HANDLED;
 
 out:
@@ -3469,7 +3471,7 @@ static u32 xhci_td_remainder(struct xhci_hcd *xhci, int transferred,
 static int xhci_align_td(struct xhci_hcd *xhci, struct urb *urb, u32 enqd_len,
                         u32 *trb_buff_len, struct xhci_segment *seg)
 {
-       struct device *dev = xhci_to_hcd(xhci)->self.controller;
+       struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
        unsigned int unalign;
        unsigned int max_pkt;
        u32 new_buff_len;
index 7e282b4522c0aa16c15398afefb933ecec2db7e5..5df370482521f74fe8784c2b531ed3aca7371a1c 100644 (file)
@@ -514,7 +514,7 @@ struct xhci_intr_reg {
 #define        ERST_SIZE_MASK          (0xffff << 16)
 
 /* erst_base bitmasks */
-#define ERST_BASE_RSVDP                (0x3f)
+#define ERST_BASE_RSVDP                (GENMASK_ULL(5, 0))
 
 /* erst_dequeue bitmasks */
 /* Dequeue ERST Segment Index (DESI) - Segment number (or alias)
index 3da1a4659c5ff705f0f9fc6ee6d3e35c7b648d9e..57bbe130909480a688cd92634d7ee0396752f5dd 100644 (file)
@@ -434,6 +434,7 @@ static const struct usb_device_id onboard_hub_id_table[] = {
        { USB_DEVICE(VENDOR_ID_GENESYS, 0x0608) }, /* Genesys Logic GL850G USB 2.0 */
        { USB_DEVICE(VENDOR_ID_GENESYS, 0x0610) }, /* Genesys Logic GL852G USB 2.0 */
        { USB_DEVICE(VENDOR_ID_GENESYS, 0x0620) }, /* Genesys Logic GL3523 USB 3.1 */
+       { USB_DEVICE(VENDOR_ID_MICROCHIP, 0x2412) }, /* USB2412 USB 2.0 */
        { USB_DEVICE(VENDOR_ID_MICROCHIP, 0x2514) }, /* USB2514B USB 2.0 */
        { USB_DEVICE(VENDOR_ID_MICROCHIP, 0x2517) }, /* USB2517 USB 2.0 */
        { USB_DEVICE(VENDOR_ID_REALTEK, 0x0411) }, /* RTS5411 USB 3.1 */
index 4026ba64c59213c1f9fe5ad4ec9f7b94f008cfb7..2a4ab5ac0ebed94e98a10a587c0a9134ed8ccb2d 100644 (file)
@@ -47,6 +47,7 @@ static const struct onboard_hub_pdata vialab_vl817_data = {
 };
 
 static const struct of_device_id onboard_hub_match[] = {
+       { .compatible = "usb424,2412", .data = &microchip_usb424_data, },
        { .compatible = "usb424,2514", .data = &microchip_usb424_data, },
        { .compatible = "usb424,2517", .data = &microchip_usb424_data, },
        { .compatible = "usb451,8140", .data = &ti_tusb8041_data, },
index 78c726a71b17753c677b97018ab3902bc9f6c7de..2d623284edf63f4fb0c81d1b3dee60569f44d8cf 100644 (file)
@@ -39,7 +39,7 @@ static const struct musb_register_map musb_regmap[] = {
        { "IntrUsbE",   MUSB_INTRUSBE,  8 },
        { "DevCtl",     MUSB_DEVCTL,    8 },
        { "VControl",   0x68,           32 },
-       { "HWVers",     0x69,           16 },
+       { "HWVers",     MUSB_HWVERS,    16 },
        { "LinkInfo",   MUSB_LINKINFO,  8 },
        { "VPLen",      MUSB_VPLEN,     8 },
        { "HS_EOF1",    MUSB_HS_EOF1,   8 },
index a02c29216955a551cb5772dc70913f97e13eddb3..bc45077811679698388ff6366a2af8c276c56a99 100644 (file)
@@ -321,10 +321,16 @@ static void musb_advance_schedule(struct musb *musb, struct urb *urb,
        musb_giveback(musb, urb, status);
        qh->is_ready = ready;
 
+       /*
+        * musb->lock had been unlocked in musb_giveback, so qh may
+        * be freed, need to get it again
+        */
+       qh = musb_ep_get_qh(hw_ep, is_in);
+
        /* reclaim resources (and bandwidth) ASAP; deschedule it, and
         * invalidate qh as soon as list_empty(&hep->urb_list)
         */
-       if (list_empty(&qh->hep->urb_list)) {
+       if (qh && list_empty(&qh->hep->urb_list)) {
                struct list_head        *head;
                struct dma_controller   *dma = musb->dma_controller;
 
@@ -2398,6 +2404,7 @@ static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
                 * and its URB list has emptied, recycle this qh.
                 */
                if (ready && list_empty(&qh->hep->urb_list)) {
+                       musb_ep_set_qh(qh->hw_ep, is_in, NULL);
                        qh->hep->hcpriv = NULL;
                        list_del(&qh->ring);
                        kfree(qh);
index 7994a4549a6c80244eba7ce0cf63a700d2be27d7..45dcfaadaf98eb6f6216975764722228d204ea22 100644 (file)
@@ -203,6 +203,9 @@ static void option_instat_callback(struct urb *urb);
 #define DELL_PRODUCT_5829E_ESIM                        0x81e4
 #define DELL_PRODUCT_5829E                     0x81e6
 
+#define DELL_PRODUCT_FM101R                    0x8213
+#define DELL_PRODUCT_FM101R_ESIM               0x8215
+
 #define KYOCERA_VENDOR_ID                      0x0c88
 #define KYOCERA_PRODUCT_KPC650                 0x17da
 #define KYOCERA_PRODUCT_KPC680                 0x180a
@@ -1108,6 +1111,8 @@ static const struct usb_device_id option_ids[] = {
          .driver_info = RSVD(0) | RSVD(6) },
        { USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5829E_ESIM),
          .driver_info = RSVD(0) | RSVD(6) },
+       { USB_DEVICE_INTERFACE_CLASS(DELL_VENDOR_ID, DELL_PRODUCT_FM101R, 0xff) },
+       { USB_DEVICE_INTERFACE_CLASS(DELL_VENDOR_ID, DELL_PRODUCT_FM101R_ESIM, 0xff) },
        { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_E100A) },   /* ADU-E100, ADU-310 */
        { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_500A) },
        { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_620UW) },
@@ -1290,6 +1295,7 @@ static const struct usb_device_id option_ids[] = {
         .driver_info = NCTRL(0) | RSVD(3) },
        { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1033, 0xff),    /* Telit LE910C1-EUX (ECM) */
         .driver_info = NCTRL(0) },
+       { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1035, 0xff) }, /* Telit LE910C4-WWX (ECM) */
        { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG0),
          .driver_info = RSVD(0) | RSVD(1) | NCTRL(2) | RSVD(3) },
        { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG1),
@@ -2262,6 +2268,7 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1406, 0xff) },                   /* GosunCn GM500 ECM/NCM */
        { USB_DEVICE_AND_INTERFACE_INFO(OPPO_VENDOR_ID, OPPO_PRODUCT_R11, 0xff, 0xff, 0x30) },
        { USB_DEVICE_AND_INTERFACE_INFO(SIERRA_VENDOR_ID, SIERRA_PRODUCT_EM9191, 0xff, 0xff, 0x30) },
+       { USB_DEVICE_AND_INTERFACE_INFO(SIERRA_VENDOR_ID, SIERRA_PRODUCT_EM9191, 0xff, 0xff, 0x40) },
        { USB_DEVICE_AND_INTERFACE_INFO(SIERRA_VENDOR_ID, SIERRA_PRODUCT_EM9191, 0xff, 0, 0) },
        { USB_DEVICE_AND_INTERFACE_INFO(UNISOC_VENDOR_ID, TOZED_PRODUCT_LT70C, 0xff, 0, 0) },
        { } /* Terminating entry */
index 426c88a516e5112b64d4aa7ebf03bd0757993333..59e0218a8bc56f4d37af2a325de35188edaa7ace 100644 (file)
@@ -304,6 +304,11 @@ static int dp_altmode_vdm(struct typec_altmode *alt,
                        typec_altmode_update_active(alt, false);
                        dp->data.status = 0;
                        dp->data.conf = 0;
+                       if (dp->hpd) {
+                               drm_connector_oob_hotplug_event(dp->connector_fwnode);
+                               dp->hpd = false;
+                               sysfs_notify(&dp->alt->dev.kobj, "displayport", "hpd");
+                       }
                        break;
                case DP_CMD_STATUS_UPDATE:
                        dp->data.status = *vdo;
index bb0b8479d80f193f709c0136a5fb1db9e2b9ae87..52c81378e36ef4e0b58c8af5097cef7220ccc499 100644 (file)
@@ -381,10 +381,6 @@ static int qcom_pmic_typec_pdphy_enable(struct pmic_typec_pdphy *pmic_typec_pdph
        struct device *dev = pmic_typec_pdphy->dev;
        int ret;
 
-       ret = regulator_enable(pmic_typec_pdphy->vdd_pdphy);
-       if (ret)
-               return ret;
-
        /* PD 2.0, DR=TYPEC_DEVICE, PR=TYPEC_SINK */
        ret = regmap_update_bits(pmic_typec_pdphy->regmap,
                                 pmic_typec_pdphy->base + USB_PDPHY_MSG_CONFIG_REG,
@@ -422,8 +418,6 @@ static int qcom_pmic_typec_pdphy_disable(struct pmic_typec_pdphy *pmic_typec_pdp
        ret = regmap_write(pmic_typec_pdphy->regmap,
                           pmic_typec_pdphy->base + USB_PDPHY_EN_CONTROL_REG, 0);
 
-       regulator_disable(pmic_typec_pdphy->vdd_pdphy);
-
        return ret;
 }
 
@@ -447,6 +441,10 @@ int qcom_pmic_typec_pdphy_start(struct pmic_typec_pdphy *pmic_typec_pdphy,
        int i;
        int ret;
 
+       ret = regulator_enable(pmic_typec_pdphy->vdd_pdphy);
+       if (ret)
+               return ret;
+
        pmic_typec_pdphy->tcpm_port = tcpm_port;
 
        ret = pmic_typec_pdphy_reset(pmic_typec_pdphy);
@@ -467,6 +465,8 @@ void qcom_pmic_typec_pdphy_stop(struct pmic_typec_pdphy *pmic_typec_pdphy)
                disable_irq(pmic_typec_pdphy->irq_data[i].irq);
 
        qcom_pmic_typec_pdphy_reset_on(pmic_typec_pdphy);
+
+       regulator_disable(pmic_typec_pdphy->vdd_pdphy);
 }
 
 struct pmic_typec_pdphy *qcom_pmic_typec_pdphy_alloc(struct device *dev)
index 384b42267f1fceec174b6d8abc58f5d63d05a836..b35c6e07911e90cc477de02a55280c0ba421ef9e 100644 (file)
@@ -37,6 +37,15 @@ static int ucsi_psy_get_scope(struct ucsi_connector *con,
        struct device *dev = con->ucsi->dev;
 
        device_property_read_u8(dev, "scope", &scope);
+       if (scope == POWER_SUPPLY_SCOPE_UNKNOWN) {
+               u32 mask = UCSI_CAP_ATTR_POWER_AC_SUPPLY |
+                          UCSI_CAP_ATTR_BATTERY_CHARGING;
+
+               if (con->ucsi->cap.attributes & mask)
+                       scope = POWER_SUPPLY_SCOPE_SYSTEM;
+               else
+                       scope = POWER_SUPPLY_SCOPE_DEVICE;
+       }
        val->intval = scope;
        return 0;
 }
index c6dfe3dff3465eddf5e106f325a3cfac9e262968..61b64558f96c57f528d54efba0a71d3ea67a033d 100644 (file)
@@ -787,6 +787,7 @@ static void ucsi_unregister_partner(struct ucsi_connector *con)
 
        typec_set_mode(con->port, TYPEC_STATE_SAFE);
 
+       typec_partner_set_usb_power_delivery(con->partner, NULL);
        ucsi_unregister_partner_pdos(con);
        ucsi_unregister_altmodes(con, UCSI_RECIPIENT_SOP);
        typec_unregister_partner(con->partner);
@@ -884,6 +885,7 @@ static void ucsi_handle_connector_change(struct work_struct *work)
        if (ret < 0) {
                dev_err(ucsi->dev, "%s: GET_CONNECTOR_STATUS failed (%d)\n",
                        __func__, ret);
+               clear_bit(EVENT_PENDING, &con->ucsi->flags);
                goto out_unlock;
        }
 
index 60d6ac68cdc41c7bfd76c8df04619a7c9ccf44a6..9c85162c19fc49cb2e81bfca72fe4b7dae14c036 100644 (file)
@@ -146,7 +146,8 @@ void mlx5_vdpa_add_debugfs(struct mlx5_vdpa_net *ndev)
                ndev->rx_dent = debugfs_create_dir("rx", ndev->debugfs);
 }
 
-void mlx5_vdpa_remove_debugfs(struct dentry *dbg)
+void mlx5_vdpa_remove_debugfs(struct mlx5_vdpa_net *ndev)
 {
-       debugfs_remove_recursive(dbg);
+       debugfs_remove_recursive(ndev->debugfs);
+       ndev->debugfs = NULL;
 }
index 40a03b08d7cfed5e35e43a2174398cb65352cad3..946488b8989f4b379b811ad05e401527fa9ea9b3 100644 (file)
@@ -625,30 +625,70 @@ static void cq_destroy(struct mlx5_vdpa_net *ndev, u16 idx)
        mlx5_db_free(ndev->mvdev.mdev, &vcq->db);
 }
 
+static int read_umem_params(struct mlx5_vdpa_net *ndev)
+{
+       u32 in[MLX5_ST_SZ_DW(query_hca_cap_in)] = {};
+       u16 opmod = (MLX5_CAP_VDPA_EMULATION << 1) | (HCA_CAP_OPMOD_GET_CUR & 0x01);
+       struct mlx5_core_dev *mdev = ndev->mvdev.mdev;
+       int out_size;
+       void *caps;
+       void *out;
+       int err;
+
+       out_size = MLX5_ST_SZ_BYTES(query_hca_cap_out);
+       out = kzalloc(out_size, GFP_KERNEL);
+       if (!out)
+               return -ENOMEM;
+
+       MLX5_SET(query_hca_cap_in, in, opcode, MLX5_CMD_OP_QUERY_HCA_CAP);
+       MLX5_SET(query_hca_cap_in, in, op_mod, opmod);
+       err = mlx5_cmd_exec_inout(mdev, query_hca_cap, in, out);
+       if (err) {
+               mlx5_vdpa_warn(&ndev->mvdev,
+                       "Failed reading vdpa umem capabilities with err %d\n", err);
+               goto out;
+       }
+
+       caps =  MLX5_ADDR_OF(query_hca_cap_out, out, capability);
+
+       ndev->umem_1_buffer_param_a = MLX5_GET(virtio_emulation_cap, caps, umem_1_buffer_param_a);
+       ndev->umem_1_buffer_param_b = MLX5_GET(virtio_emulation_cap, caps, umem_1_buffer_param_b);
+
+       ndev->umem_2_buffer_param_a = MLX5_GET(virtio_emulation_cap, caps, umem_2_buffer_param_a);
+       ndev->umem_2_buffer_param_b = MLX5_GET(virtio_emulation_cap, caps, umem_2_buffer_param_b);
+
+       ndev->umem_3_buffer_param_a = MLX5_GET(virtio_emulation_cap, caps, umem_3_buffer_param_a);
+       ndev->umem_3_buffer_param_b = MLX5_GET(virtio_emulation_cap, caps, umem_3_buffer_param_b);
+
+out:
+       kfree(out);
+       return 0;
+}
+
 static void set_umem_size(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq, int num,
                          struct mlx5_vdpa_umem **umemp)
 {
-       struct mlx5_core_dev *mdev = ndev->mvdev.mdev;
-       int p_a;
-       int p_b;
+       u32 p_a;
+       u32 p_b;
 
        switch (num) {
        case 1:
-               p_a = MLX5_CAP_DEV_VDPA_EMULATION(mdev, umem_1_buffer_param_a);
-               p_b = MLX5_CAP_DEV_VDPA_EMULATION(mdev, umem_1_buffer_param_b);
+               p_a = ndev->umem_1_buffer_param_a;
+               p_b = ndev->umem_1_buffer_param_b;
                *umemp = &mvq->umem1;
                break;
        case 2:
-               p_a = MLX5_CAP_DEV_VDPA_EMULATION(mdev, umem_2_buffer_param_a);
-               p_b = MLX5_CAP_DEV_VDPA_EMULATION(mdev, umem_2_buffer_param_b);
+               p_a = ndev->umem_2_buffer_param_a;
+               p_b = ndev->umem_2_buffer_param_b;
                *umemp = &mvq->umem2;
                break;
        case 3:
-               p_a = MLX5_CAP_DEV_VDPA_EMULATION(mdev, umem_3_buffer_param_a);
-               p_b = MLX5_CAP_DEV_VDPA_EMULATION(mdev, umem_3_buffer_param_b);
+               p_a = ndev->umem_3_buffer_param_a;
+               p_b = ndev->umem_3_buffer_param_b;
                *umemp = &mvq->umem3;
                break;
        }
+
        (*umemp)->size = p_a * mvq->num_ent + p_b;
 }
 
@@ -2679,6 +2719,11 @@ static int setup_driver(struct mlx5_vdpa_dev *mvdev)
                goto out;
        }
        mlx5_vdpa_add_debugfs(ndev);
+
+       err = read_umem_params(ndev);
+       if (err)
+               goto err_setup;
+
        err = setup_virtqueues(mvdev);
        if (err) {
                mlx5_vdpa_warn(mvdev, "setup_virtqueues\n");
@@ -2713,7 +2758,7 @@ err_tir:
 err_rqt:
        teardown_virtqueues(ndev);
 err_setup:
-       mlx5_vdpa_remove_debugfs(ndev->debugfs);
+       mlx5_vdpa_remove_debugfs(ndev);
 out:
        return err;
 }
@@ -2727,8 +2772,7 @@ static void teardown_driver(struct mlx5_vdpa_net *ndev)
        if (!ndev->setup)
                return;
 
-       mlx5_vdpa_remove_debugfs(ndev->debugfs);
-       ndev->debugfs = NULL;
+       mlx5_vdpa_remove_debugfs(ndev);
        teardown_steering(ndev);
        destroy_tir(ndev);
        destroy_rqt(ndev);
@@ -3489,8 +3533,6 @@ static void mlx5_vdpa_dev_del(struct vdpa_mgmt_dev *v_mdev, struct vdpa_device *
        struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev);
        struct workqueue_struct *wq;
 
-       mlx5_vdpa_remove_debugfs(ndev->debugfs);
-       ndev->debugfs = NULL;
        unregister_link_notifier(ndev);
        _vdpa_unregister_device(dev);
        wq = mvdev->wq;
index 36c44d9fdd166b52c83557c66793acee1dbb2ae4..90b556a57971334c16677a2b3658fa825026dbd0 100644 (file)
@@ -65,6 +65,15 @@ struct mlx5_vdpa_net {
        struct hlist_head macvlan_hash[MLX5V_MACVLAN_SIZE];
        struct mlx5_vdpa_irq_pool irqp;
        struct dentry *debugfs;
+
+       u32 umem_1_buffer_param_a;
+       u32 umem_1_buffer_param_b;
+
+       u32 umem_2_buffer_param_a;
+       u32 umem_2_buffer_param_b;
+
+       u32 umem_3_buffer_param_a;
+       u32 umem_3_buffer_param_b;
 };
 
 struct mlx5_vdpa_counter {
@@ -88,7 +97,7 @@ struct macvlan_node {
 };
 
 void mlx5_vdpa_add_debugfs(struct mlx5_vdpa_net *ndev);
-void mlx5_vdpa_remove_debugfs(struct dentry *dbg);
+void mlx5_vdpa_remove_debugfs(struct mlx5_vdpa_net *ndev);
 void mlx5_vdpa_add_rx_flow_table(struct mlx5_vdpa_net *ndev);
 void mlx5_vdpa_remove_rx_flow_table(struct mlx5_vdpa_net *ndev);
 void mlx5_vdpa_add_tirn(struct mlx5_vdpa_net *ndev);
index 00d7d72713beb2d6942666df22a3d2cbd65da7f2..b3a3cb16579552ccec1cd4ec1875ad36376b6cd3 100644 (file)
@@ -499,12 +499,13 @@ static int __init vdpasim_blk_init(void)
                                         GFP_KERNEL);
                if (!shared_buffer) {
                        ret = -ENOMEM;
-                       goto parent_err;
+                       goto mgmt_dev_err;
                }
        }
 
        return 0;
-
+mgmt_dev_err:
+       vdpa_mgmtdev_unregister(&mgmt_dev);
 parent_err:
        device_unregister(&vdpasim_blk_mgmtdev);
        return ret;
index e4490639d3833e68a4d0b8c9deb50004dfa84290..9d2738e10c0b9d4d2b1018e4c948bf427d0315a9 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 407b3fd3273381ed5173f7e2ca2b83fe8800dc3b..6eceef7b028aae9b8b7a8cb49614e88525f4bade 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 b46174f5eb0955047081eb800c66ddfc188275e8..649b18ee394bb7932b8a24763a73a010c2d901ec 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 c71d573f1c9497c37e2da7693becd09f10bf5989..e0c181ad17e3166f77b9bd3ecf55d4a90b6e30f0 100644 (file)
@@ -1458,9 +1458,7 @@ ssize_t vhost_chr_write_iter(struct vhost_dev *dev,
                goto done;
        }
 
-       if ((msg.type == VHOST_IOTLB_UPDATE ||
-            msg.type == VHOST_IOTLB_INVALIDATE) &&
-            msg.size == 0) {
+       if (msg.type == VHOST_IOTLB_UPDATE && msg.size == 0) {
                ret = -EINVAL;
                goto done;
        }
index 955d938eb6633aa840f693f0aa23a1d118515fdc..7b8fd977f71ccf5ad32c026fda42ad44606cfef3 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 1b5a319971ed07f148e54d65de16f267a720252f..30577b1d3de590f123aa6af2c58bae1c6fea08de 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 eac0ba39581e3c5bfc7d6d345aee31a17a7e6730..c29754b65c0ec923387cfb8c1b7e0f47557d33cd 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 5c87817a4f4ce62afe173a2d0859b9c84a226858..3dcf83f5e7b4a1da7ad76c7b1d235ce720bc75ea 100644 (file)
@@ -3440,11 +3440,15 @@ static int atyfb_setup_generic(struct pci_dev *pdev, struct fb_info *info,
        }
 
        info->fix.mmio_start = raddr;
+#if defined(__i386__) || defined(__ia64__)
        /*
         * By using strong UC we force the MTRR to never have an
         * effect on the MMIO region on both non-PAT and PAT systems.
         */
        par->ati_regbase = ioremap_uc(info->fix.mmio_start, 0x1000);
+#else
+       par->ati_regbase = ioremap(info->fix.mmio_start, 0x1000);
+#endif
        if (par->ati_regbase == NULL)
                return -ENOMEM;
 
index baf7e852c75b60972ab24ddc10ac773b1a1dbf96..5ac1b063753110d51e5f6b8348e5edf23338e6db 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 6d4bfeecee35088f86d257d871c40ad934f79737..5b80bf3dae504850d9ebc12de3ac1df32341ccee 100644 (file)
@@ -382,7 +382,7 @@ void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
 {
        u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
        u32 height = area->height, width = area->width;
-       unsigned long const bits_per_line = p->fix.line_length*8u;
+       unsigned int const bits_per_line = p->fix.line_length * 8u;
        unsigned long __iomem *base = NULL;
        int bits = BITS_PER_LONG, bytes = bits >> 3;
        unsigned dst_idx = 0, src_idx = 0, rev_copy = 0;
index c1eda31909682aed092b02080134a08e32375913..7b8bd3a2bedc50c5ca23cb180f52dd99229d9cfc 100644 (file)
@@ -316,7 +316,7 @@ void sys_copyarea(struct fb_info *p, const struct fb_copyarea *area)
 {
        u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
        u32 height = area->height, width = area->width;
-       unsigned long const bits_per_line = p->fix.line_length*8u;
+       unsigned int const bits_per_line = p->fix.line_length * 8u;
        unsigned long *base = NULL;
        int bits = BITS_PER_LONG, bytes = bits >> 3;
        unsigned dst_idx = 0, src_idx = 0, rev_copy = 0;
index 167585a889d318667ebfdc4e5e77bd55c815589d..719b99a9bc7762c9f88c3532e97e7b3b79320d02 100644 (file)
@@ -1406,7 +1406,7 @@ struct mmphw_ctrl {
 
        /*pathes*/
        int path_num;
-       struct mmphw_path_plat path_plats[];
+       struct mmphw_path_plat path_plats[] __counted_by(path_num);
 };
 
 static inline int overlay_is_vid(struct mmp_overlay *overlay)
index f28cb90947a3412076a203368828044aa4241093..42c96f1cfc93c435ccf94154da2110bae0d4f082 100644 (file)
@@ -1645,13 +1645,13 @@ static int omapfb_do_probe(struct platform_device *pdev,
        }
        fbdev->int_irq = platform_get_irq(pdev, 0);
        if (fbdev->int_irq < 0) {
-               r = ENXIO;
+               r = -ENXIO;
                goto cleanup;
        }
 
        fbdev->ext_irq = platform_get_irq(pdev, 1);
        if (fbdev->ext_irq < 0) {
-               r = ENXIO;
+               r = -ENXIO;
                goto cleanup;
        }
 
index 3d76ce11148826a169bd0f0251424262024a2d66..cf0f706762b49b93a7a6f839bc86e12acaf4f106 100644 (file)
@@ -1214,7 +1214,7 @@ static struct platform_driver sa1100fb_driver = {
        },
 };
 
-int __init sa1100fb_init(void)
+static int __init sa1100fb_init(void)
 {
        if (fb_get_options("sa1100fb", NULL))
                return -ENODEV;
index a1a67830fbbcc22e7db922a7c77d73fb6a2ac66c..e1f421e91b4fb0f297e57cbc3f2bf9571d44a867 100644 (file)
@@ -1928,10 +1928,10 @@ static void uvesafb_exit(void)
                }
        }
 
-       cn_del_callback(&uvesafb_cn_id);
        driver_remove_file(&uvesafb_driver.driver, &driver_attr_v86d);
        platform_device_unregister(uvesafb_device);
        platform_driver_unregister(&uvesafb_driver);
+       cn_del_callback(&uvesafb_cn_id);
 }
 
 module_exit(uvesafb_exit);
index 5b15936a521491b411a5a0dc2750444cae8877d4..2d5d252ef419727f9685bacc483e4923544b181e 100644 (file)
@@ -395,7 +395,11 @@ static inline s64 towards_target(struct virtio_balloon *vb)
        virtio_cread_le(vb->vdev, struct virtio_balloon_config, num_pages,
                        &num_pages);
 
-       target = num_pages;
+       /*
+        * Aligned up to guest page size to avoid inflating and deflating
+        * balloon endlessly.
+        */
+       target = ALIGN(num_pages, VIRTIO_BALLOON_PAGES_PER_PAGE);
        return target - vb->num_pages;
 }
 
index 97760f611295941a36331573e53159ec5223eacc..59892a31cf761cced6ac50134bc250146c89c4aa 100644 (file)
@@ -631,14 +631,17 @@ static int virtio_mmio_probe(struct platform_device *pdev)
        spin_lock_init(&vm_dev->lock);
 
        vm_dev->base = devm_platform_ioremap_resource(pdev, 0);
-       if (IS_ERR(vm_dev->base))
-               return PTR_ERR(vm_dev->base);
+       if (IS_ERR(vm_dev->base)) {
+               rc = PTR_ERR(vm_dev->base);
+               goto free_vm_dev;
+       }
 
        /* Check magic value */
        magic = readl(vm_dev->base + VIRTIO_MMIO_MAGIC_VALUE);
        if (magic != ('v' | 'i' << 8 | 'r' << 16 | 't' << 24)) {
                dev_warn(&pdev->dev, "Wrong magic value 0x%08lx!\n", magic);
-               return -ENODEV;
+               rc = -ENODEV;
+               goto free_vm_dev;
        }
 
        /* Check device version */
@@ -646,7 +649,8 @@ static int virtio_mmio_probe(struct platform_device *pdev)
        if (vm_dev->version < 1 || vm_dev->version > 2) {
                dev_err(&pdev->dev, "Version %ld not supported!\n",
                                vm_dev->version);
-               return -ENXIO;
+               rc = -ENXIO;
+               goto free_vm_dev;
        }
 
        vm_dev->vdev.id.device = readl(vm_dev->base + VIRTIO_MMIO_DEVICE_ID);
@@ -655,7 +659,8 @@ static int virtio_mmio_probe(struct platform_device *pdev)
                 * virtio-mmio device with an ID 0 is a (dummy) placeholder
                 * with no function. End probing now with no error reported.
                 */
-               return -ENODEV;
+               rc = -ENODEV;
+               goto free_vm_dev;
        }
        vm_dev->vdev.id.vendor = readl(vm_dev->base + VIRTIO_MMIO_VENDOR_ID);
 
@@ -685,6 +690,10 @@ static int virtio_mmio_probe(struct platform_device *pdev)
                put_device(&vm_dev->vdev.dev);
 
        return rc;
+
+free_vm_dev:
+       kfree(vm_dev);
+       return rc;
 }
 
 static int virtio_mmio_remove(struct platform_device *pdev)
index aad7d9296e772063f8a15757cdf33c0ba1b2fc7d..9cb601e16688dccc8373fef26a604e1ea5766765 100644 (file)
@@ -291,7 +291,7 @@ int vp_modern_probe(struct virtio_pci_modern_device *mdev)
        err = -EINVAL;
        mdev->common = vp_modern_map_capability(mdev, common,
                                      sizeof(struct virtio_pci_common_cfg), 4,
-                                     0, sizeof(struct virtio_pci_common_cfg),
+                                     0, sizeof(struct virtio_pci_modern_common_cfg),
                                      NULL, NULL);
        if (!mdev->common)
                goto err_map_common;
index 3bdd5b59661de53300744be47abc5cb6cb6722ee..1b2136fe0fa51901123f928ed99a56facb19a9ca 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;
@@ -146,23 +148,13 @@ 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 fcc8191315723c6701ec5e7c5b97a73374b899a8..544d3f9010b92aca1e65a5c192b3ff79e6c19816 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 a4c2a6bac72ce9976b6b0ea20b1d9213cc4c2af8..f8589caef9c10ec829bc6470cab5ce159915114c 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 43b2a2851ba30b724d459c08d754bad225ac23cb..206812ce544aebbf131c5647808774ceb5afb015 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 b7d54efb47288e21496de7e74b794aecce6ae856..a4a809efc92fc6c7b5263a285b19b82907085b0a 100644 (file)
@@ -3196,12 +3196,14 @@ static int handle_direct_tree_backref(struct btrfs_backref_cache *cache,
  * We still need to do a tree search to find out the parents. This is for
  * TREE_BLOCK_REF backref (keyed or inlined).
  *
+ * @trans:     Transaction handle.
  * @ref_key:   The same as @ref_key in  handle_direct_tree_backref()
  * @tree_key:  The first key of this tree block.
  * @path:      A clean (released) path, to avoid allocating path every time
  *             the function get called.
  */
-static int handle_indirect_tree_backref(struct btrfs_backref_cache *cache,
+static int handle_indirect_tree_backref(struct btrfs_trans_handle *trans,
+                                       struct btrfs_backref_cache *cache,
                                        struct btrfs_path *path,
                                        struct btrfs_key *ref_key,
                                        struct btrfs_key *tree_key,
@@ -3315,7 +3317,7 @@ static int handle_indirect_tree_backref(struct btrfs_backref_cache *cache,
                         * If we know the block isn't shared we can avoid
                         * checking its backrefs.
                         */
-                       if (btrfs_block_can_be_shared(root, eb))
+                       if (btrfs_block_can_be_shared(trans, root, eb))
                                upper->checked = 0;
                        else
                                upper->checked = 1;
@@ -3363,11 +3365,13 @@ out:
  *      links aren't yet bi-directional. Needs to finish such links.
  *      Use btrfs_backref_finish_upper_links() to finish such linkage.
  *
+ * @trans:     Transaction handle.
  * @path:      Released path for indirect tree backref lookup
  * @iter:      Released backref iter for extent tree search
  * @node_key:  The first key of the tree block
  */
-int btrfs_backref_add_tree_node(struct btrfs_backref_cache *cache,
+int btrfs_backref_add_tree_node(struct btrfs_trans_handle *trans,
+                               struct btrfs_backref_cache *cache,
                                struct btrfs_path *path,
                                struct btrfs_backref_iter *iter,
                                struct btrfs_key *node_key,
@@ -3467,8 +3471,8 @@ int btrfs_backref_add_tree_node(struct btrfs_backref_cache *cache,
                         * offset means the root objectid. We need to search
                         * the tree to get its parent bytenr.
                         */
-                       ret = handle_indirect_tree_backref(cache, path, &key, node_key,
-                                                          cur);
+                       ret = handle_indirect_tree_backref(trans, cache, path,
+                                                          &key, node_key, cur);
                        if (ret < 0)
                                goto out;
                }
index 1616e3e3f1e4193c7fc531737e65da47698fc049..71d535e03dca87adcabb62eeac06582f1e3e45af 100644 (file)
@@ -540,7 +540,8 @@ static inline void btrfs_backref_panic(struct btrfs_fs_info *fs_info,
                    bytenr);
 }
 
-int btrfs_backref_add_tree_node(struct btrfs_backref_cache *cache,
+int btrfs_backref_add_tree_node(struct btrfs_trans_handle *trans,
+                               struct btrfs_backref_cache *cache,
                                struct btrfs_path *path,
                                struct btrfs_backref_iter *iter,
                                struct btrfs_key *node_key,
index a4cb4b6429870169eadbef99d359cdab4d84db0c..617d4827eec265f2ada05a82a1a03f01f6cabeb2 100644 (file)
@@ -367,7 +367,8 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
 /*
  * check if the tree block can be shared by multiple trees
  */
-int btrfs_block_can_be_shared(struct btrfs_root *root,
+int btrfs_block_can_be_shared(struct btrfs_trans_handle *trans,
+                             struct btrfs_root *root,
                              struct extent_buffer *buf)
 {
        /*
@@ -376,11 +377,21 @@ int btrfs_block_can_be_shared(struct btrfs_root *root,
         * not allocated by tree relocation, we know the block is not shared.
         */
        if (test_bit(BTRFS_ROOT_SHAREABLE, &root->state) &&
-           buf != root->node && buf != root->commit_root &&
+           buf != root->node &&
            (btrfs_header_generation(buf) <=
             btrfs_root_last_snapshot(&root->root_item) ||
-            btrfs_header_flag(buf, BTRFS_HEADER_FLAG_RELOC)))
-               return 1;
+            btrfs_header_flag(buf, BTRFS_HEADER_FLAG_RELOC))) {
+               if (buf != root->commit_root)
+                       return 1;
+               /*
+                * An extent buffer that used to be the commit root may still be
+                * shared because the tree height may have increased and it
+                * became a child of a higher level root. This can happen when
+                * snapshotting a subvolume created in the current transaction.
+                */
+               if (btrfs_header_generation(buf) == trans->transid)
+                       return 1;
+       }
 
        return 0;
 }
@@ -415,7 +426,7 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
         * are only allowed for blocks use full backrefs.
         */
 
-       if (btrfs_block_can_be_shared(root, buf)) {
+       if (btrfs_block_can_be_shared(trans, root, buf)) {
                ret = btrfs_lookup_extent_info(trans, fs_info, buf->start,
                                               btrfs_header_level(buf), 1,
                                               &refs, &flags);
@@ -682,18 +693,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 +828,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 9419f4e37a58c3d20164d4f6bf9fb447792e45c2..ff40acd63a3743d6265c7282cd9adb751348bb77 100644 (file)
@@ -540,7 +540,8 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
                      struct btrfs_root *root,
                      struct extent_buffer *buf,
                      struct extent_buffer **cow_ret, u64 new_root_objectid);
-int btrfs_block_can_be_shared(struct btrfs_root *root,
+int btrfs_block_can_be_shared(struct btrfs_trans_handle *trans,
+                             struct btrfs_root *root,
                              struct extent_buffer *buf);
 int btrfs_del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                  struct btrfs_path *path, int level, int slot);
index caf0bbd028d11070ea8d87524c9e8c670e7d905d..90aaedce1548a47a672ad1803fc4d7ac7b074d3e 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 dc1085b2a3976668e875d0dbf8b4d7aaf6b22dcd..1da213197f55f10ac674bbb953aac955d0eb5274 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 6a13cf00218bc3b8ab21d5d4b56c43dd0412ed49..9fe4ccca50a0604ad00cfa9ebb63f3f3db58f833 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 b8e14b0ba5f162fbb2bfec87e075d9051d5d2564..fd9bf2b709c0e461044b5829d9bcdd9a43bfefa6 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 f356f08b55cb8e4646e105791454afc98c2cb840..fc313fce5bbdc7d9e5e2a7994b7e3ba0ab12105a 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 ac3fca5a5e4162ddc2769f4e5932370d622ae0b4..caccd0376342b7b6c0ba4737f93728e80d9d3d98 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 ca46a529d56b1999cff4a785661db40dca049e47..361535c71c0f5a172328832e32b6d00f7b14f131 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 f09fbdc43f0f5b15c71d67564cfb264764ff1169..7814b9d654ce1234465bf8ad37a7890e06fd88aa 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 75ab766fe156550afef8135892dda7f3524aa948..8e7d03bc1b56512df6c338907fb2792da025bdf7 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 9951a0caf5bbf961cdb535dc643b3dca6d08b9e8..c6d4bb8cbe299578dca2259ce98e2ab2e4f6877d 100644 (file)
@@ -466,6 +466,7 @@ static bool handle_useless_nodes(struct reloc_control *rc,
  * cached.
  */
 static noinline_for_stack struct btrfs_backref_node *build_backref_tree(
+                       struct btrfs_trans_handle *trans,
                        struct reloc_control *rc, struct btrfs_key *node_key,
                        int level, u64 bytenr)
 {
@@ -499,8 +500,8 @@ static noinline_for_stack struct btrfs_backref_node *build_backref_tree(
 
        /* Breadth-first search to build backref cache */
        do {
-               ret = btrfs_backref_add_tree_node(cache, path, iter, node_key,
-                                                 cur);
+               ret = btrfs_backref_add_tree_node(trans, cache, path, iter,
+                                                 node_key, cur);
                if (ret < 0) {
                        err = ret;
                        goto out;
@@ -2803,7 +2804,7 @@ int relocate_tree_blocks(struct btrfs_trans_handle *trans,
 
        /* Do tree relocation */
        rbtree_postorder_for_each_entry_safe(block, next, blocks, rb_node) {
-               node = build_backref_tree(rc, &block->key,
+               node = build_backref_tree(trans, rc, &block->key,
                                          block->level, block->bytenr);
                if (IS_ERR(node)) {
                        err = PTR_ERR(node);
index 09bfe68d2ea3fcc8ca68da3deaf3b9a3ea87342d..1a093ec0f7e3626cd7468575a1697746f9034dd9 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 0bf42dccb0412d80db1250259ced8066deda7848..c780d37294636852144c8082899e1da4c1189b78 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 6b309f8a99a860b424865ee6656881037eb9329a..93869cda6af99c70adbf3c77c11d5f713edc8d32 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 d1e46b839519ca0cdd5560fc990c99ff59ffe973..cbb17b542131770e8893d47d057046241f465629 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 c5ff16f9e9fa53aaa8779059a903f9bd636ceb02..744f4f4d4c681139648cbb04394cf6d7bce572c9 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 9621455edebc9da384d249c8c34cfcaa245d9888..b9ef6f54635ca5c45c3266e02e1ea7f745775c24 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)) {
@@ -5110,7 +5109,7 @@ static void init_alloc_chunk_ctl_policy_regular(
        ASSERT(space_info);
 
        ctl->max_chunk_size = READ_ONCE(space_info->chunk_size);
-       ctl->max_stripe_size = ctl->max_chunk_size;
+       ctl->max_stripe_size = min_t(u64, ctl->max_chunk_size, SZ_1G);
 
        if (ctl->type & BTRFS_BLOCK_GROUP_SYSTEM)
                ctl->devs_max = min_t(int, ctl->devs_max, BTRFS_MAX_DEVS_SYS_CHUNK);
index 2379564e5aeadf5bebc786375d17b744cacd5f75..12e9a71c693d740a80ad5aa92b4653004a381711 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 e4d5cd56a80b9aa6c1b04089af0cd636b566d943..5b5112c784629cb6b97600a705e9cdcda6491199 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);
@@ -462,7 +460,7 @@ int ceph_fname_to_usr(const struct ceph_fname *fname, struct fscrypt_str *tname,
 out:
        fscrypt_fname_free_buffer(&_tname);
 out_inode:
-       if ((dir != fname->dir) && !IS_ERR(dir)) {
+       if (dir != fname->dir) {
                if ((dir->i_state & I_NEW))
                        discard_new_inode(dir);
                else
index b1da02f5dbe3b4f31a6e9b8b259ad974b1d9238f..b5f8038065d7c1f952ef1cbeef569ad88ac9e0f9 100644 (file)
@@ -2969,7 +2969,7 @@ static ssize_t __ceph_copy_file_range(struct file *src_file, loff_t src_off,
                ret = do_splice_direct(src_file, &src_off, dst_file,
                                       &dst_off, src_objlen, flags);
                /* Abort on short copies or on error */
-               if (ret < src_objlen) {
+               if (ret < (long)src_objlen) {
                        dout("Failed partial copy (%zd)\n", ret);
                        goto out;
                }
index 800ab79205137942c9b3c843218e5ea998b3802d..b79100f720b38f42a7af97591139e59967d60812 100644 (file)
@@ -769,9 +769,7 @@ int ceph_fill_file_size(struct inode *inode, int issued,
                        ci->i_truncate_seq = truncate_seq;
 
                        /* the MDS should have revoked these caps */
-                       WARN_ON_ONCE(issued & (CEPH_CAP_FILE_EXCL |
-                                              CEPH_CAP_FILE_RD |
-                                              CEPH_CAP_FILE_WR |
+                       WARN_ON_ONCE(issued & (CEPH_CAP_FILE_RD |
                                               CEPH_CAP_FILE_LAZYIO));
                        /*
                         * If we hold relevant caps, or in the case where we're
index 615db141b6c4b54362815910a1ab13c470dffe8c..293b93182955d017536e9628d9db1c2220b9b07f 100644 (file)
@@ -861,8 +861,8 @@ int ceph_wait_on_conflict_unlink(struct dentry *dentry)
                if (!d_same_name(udentry, pdentry, &dname))
                        goto next;
 
+               found = dget_dlock(udentry);
                spin_unlock(&udentry->d_lock);
-               found = dget(udentry);
                break;
 next:
                spin_unlock(&udentry->d_lock);
index 73091fbe3ea453d377f20bc4cfc0c2de5f76c1e5..dee10d22ada96e5f6031d752e00ef33dbe984018 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 44a24d573f1fd31455608a6757fd98195ce79a78..3700af9ee17332f4f6ea766ba3297cdd1e3746fc 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 38217422f938833f2eb9312f80da735190080dd6..dbebd8b3127e514e7dc165ced48da0b6ff3cd7da 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 969ce991b0b03f6b49f3b92cdcfc4ca515a8f315..c1af01b2c42d708ede9b2842b1cc0bfec5153838 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 a0ad7a0c46809ecdb01f6a8fb907aaa3a48aaf1e..98589aae52085c82d4e8951ca63be928cb33cec8 100644 (file)
@@ -192,17 +192,19 @@ int vfs_parse_fs_string(struct fs_context *fc, const char *key,
 EXPORT_SYMBOL(vfs_parse_fs_string);
 
 /**
- * generic_parse_monolithic - Parse key[=val][,key[=val]]* mount data
+ * vfs_parse_monolithic_sep - Parse key[=val][,key[=val]]* mount data
  * @fc: The superblock configuration to fill in.
  * @data: The data to parse
+ * @sep: callback for separating next option
  *
- * Parse a blob of data that's in key[=val][,key[=val]]* form.  This can be
- * called from the ->monolithic_mount_data() fs_context operation.
+ * Parse a blob of data that's in key[=val][,key[=val]]* form with a custom
+ * option separator callback.
  *
  * Returns 0 on success or the error returned by the ->parse_option() fs_context
  * operation on failure.
  */
-int generic_parse_monolithic(struct fs_context *fc, void *data)
+int vfs_parse_monolithic_sep(struct fs_context *fc, void *data,
+                            char *(*sep)(char **))
 {
        char *options = data, *key;
        int ret = 0;
@@ -214,7 +216,7 @@ int generic_parse_monolithic(struct fs_context *fc, void *data)
        if (ret)
                return ret;
 
-       while ((key = strsep(&options, ",")) != NULL) {
+       while ((key = sep(&options)) != NULL) {
                if (*key) {
                        size_t v_len = 0;
                        char *value = strchr(key, '=');
@@ -233,6 +235,28 @@ int generic_parse_monolithic(struct fs_context *fc, void *data)
 
        return ret;
 }
+EXPORT_SYMBOL(vfs_parse_monolithic_sep);
+
+static char *vfs_parse_comma_sep(char **s)
+{
+       return strsep(s, ",");
+}
+
+/**
+ * generic_parse_monolithic - Parse key[=val][,key[=val]]* mount data
+ * @fc: The superblock configuration to fill in.
+ * @data: The data to parse
+ *
+ * Parse a blob of data that's in key[=val][,key[=val]]* form.  This can be
+ * called from the ->monolithic_mount_data() fs_context operation.
+ *
+ * Returns 0 on success or the error returned by the ->parse_option() fs_context
+ * operation on failure.
+ */
+int generic_parse_monolithic(struct fs_context *fc, void *data)
+{
+       return vfs_parse_monolithic_sep(fc, data, vfs_parse_comma_sep);
+}
 EXPORT_SYMBOL(generic_parse_monolithic);
 
 /**
index 9cbf8d98489a4a67b05c8e2cfae16d34aeb594d9..4a280be229a6517b3a9bdd219051b0967af0249f 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 d26759a98b1074d417be5ecf2c1c52e934af73fd..f41ca89d216bc243a405b70482301649098fcba0 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 21ada332d55571021bda02fb55be74da43952388..1429945215a039dad28c05de4bc419ad0ebd6b79 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 35fd688168c553d1a270485fada1819db60c4918..84bc3c76e5ccb5d800172dfe76be3d3d80ecc2ff 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 ae8673ce08b16e4b4268fa3eaa76efee131155a8..2bc0aa23fde3b940427b9c32533fc54f6c075e4d 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;
 
@@ -879,8 +881,10 @@ static loff_t iomap_write_iter(struct iomap_iter *iter, struct iov_iter *i)
                size_t bytes;           /* Bytes to write to folio */
                size_t copied;          /* Bytes copied from user */
 
+               bytes = iov_iter_count(i);
+retry:
                offset = pos & (chunk - 1);
-               bytes = min(chunk - offset, iov_iter_count(i));
+               bytes = min(chunk - offset, bytes);
                status = balance_dirty_pages_ratelimited_flags(mapping,
                                                               bdp_flags);
                if (unlikely(status))
@@ -931,10 +935,12 @@ static loff_t iomap_write_iter(struct iomap_iter *iter, struct iov_iter *i)
                         * halfway through, might be a race with munmap,
                         * might be severe memory pressure.
                         */
-                       if (copied)
-                               bytes = copied;
                        if (chunk > PAGE_SIZE)
                                chunk /= 2;
+                       if (copied) {
+                               bytes = copied;
+                               goto retry;
+                       }
                } else {
                        pos += status;
                        written += status;
@@ -1047,7 +1053,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 +1267,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 +1277,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 a4eb1275788627161d1a1f0d5f5b6bc3557a5df1..37f2d34ee090bd1230426045d8565bf72a82579b 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 567ee547492bc24096cad45c9c64aef84491fe42..94565bd7e73f6f41c176513ff15a68961fa351d8 100644 (file)
@@ -188,7 +188,7 @@ getname_flags(const char __user *filename, int flags, int *empty)
                }
        }
 
-       result->refcnt = 1;
+       atomic_set(&result->refcnt, 1);
        /* The empty path is special. */
        if (unlikely(!len)) {
                if (empty)
@@ -249,7 +249,7 @@ getname_kernel(const char * filename)
        memcpy((char *)result->name, filename, len);
        result->uptr = NULL;
        result->aname = NULL;
-       result->refcnt = 1;
+       atomic_set(&result->refcnt, 1);
        audit_getname(result);
 
        return result;
@@ -261,9 +261,10 @@ void putname(struct filename *name)
        if (IS_ERR(name))
                return;
 
-       BUG_ON(name->refcnt <= 0);
+       if (WARN_ON_ONCE(!atomic_read(&name->refcnt)))
+               return;
 
-       if (--name->refcnt > 0)
+       if (!atomic_dec_and_test(&name->refcnt))
                return;
 
        if (name->name != name->iname) {
index 3404707ddbe7302201288e793287a1de5c5e24e7..2cd3ccf4c439960053e436d63792bc5bf7a914de 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 47d892a1d363d94d13b5d7af5a529ba44136d3f9..f6c74f4246917fafce2746198622edad39022179 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 7deb3cd76abe4b623c7d79554d7c9d7506491d1b..ef817a0475ffa6508a0d663b3fa4f7f29ebd58af 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:
@@ -2519,9 +2520,9 @@ ff_layout_mirror_prepare_stats(struct pnfs_layout_hdr *lo,
        return i;
 }
 
-static int
-ff_layout_prepare_layoutstats(struct nfs42_layoutstat_args *args)
+static int ff_layout_prepare_layoutstats(struct nfs42_layoutstat_args *args)
 {
+       struct pnfs_layout_hdr *lo;
        struct nfs4_flexfile_layout *ff_layout;
        const int dev_count = PNFS_LAYOUTSTATS_MAXDEV;
 
@@ -2532,11 +2533,14 @@ ff_layout_prepare_layoutstats(struct nfs42_layoutstat_args *args)
                return -ENOMEM;
 
        spin_lock(&args->inode->i_lock);
-       ff_layout = FF_LAYOUT_FROM_HDR(NFS_I(args->inode)->layout);
-       args->num_dev = ff_layout_mirror_prepare_stats(&ff_layout->generic_hdr,
-                                                      &args->devinfo[0],
-                                                      dev_count,
-                                                      NFS4_FF_OP_LAYOUTSTATS);
+       lo = NFS_I(args->inode)->layout;
+       if (lo && pnfs_layout_is_valid(lo)) {
+               ff_layout = FF_LAYOUT_FROM_HDR(lo);
+               args->num_dev = ff_layout_mirror_prepare_stats(
+                       &ff_layout->generic_hdr, &args->devinfo[0], dev_count,
+                       NFS4_FF_OP_LAYOUTSTATS);
+       } else
+               args->num_dev = 0;
        spin_unlock(&args->inode->i_lock);
        if (!args->num_dev) {
                kfree(args->devinfo);
index 063e00aff87edbf15db06ef5f2ce6ab65faa2059..28704f924612c4e5866470865c3ba7b03d1df929 100644 (file)
@@ -81,7 +81,8 @@ static int _nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep,
        if (status == 0) {
                if (nfs_should_remove_suid(inode)) {
                        spin_lock(&inode->i_lock);
-                       nfs_set_cache_invalid(inode, NFS_INO_INVALID_MODE);
+                       nfs_set_cache_invalid(inode,
+                               NFS_INO_REVAL_FORCED | NFS_INO_INVALID_MODE);
                        spin_unlock(&inode->i_lock);
                }
                status = nfs_post_op_update_inode_force_wcc(inode,
index 27fb25567ce755a54e16e487379a3cd7a4f62824..11e3a285594c231c6b887dc53edbe52ef8519b23 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 794343790ea8bbba5493f0374d5297c45f87dd4f..5ee283eb9660b8f27bf7360dee0182e425995dbe 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;
 }
@@ -8866,8 +8870,6 @@ static int _nfs4_proc_exchange_id(struct nfs_client *clp, const struct cred *cre
        /* Save the EXCHANGE_ID verifier session trunk tests */
        memcpy(clp->cl_confirm.data, argp->verifier.data,
               sizeof(clp->cl_confirm.data));
-       if (resp->flags & EXCHGID4_FLAG_USE_PNFS_DS)
-               set_bit(NFS_CS_DS, &clp->cl_flags);
 out:
        trace_nfs4_exchange_id(clp, status);
        rpc_put_task(task);
@@ -10618,7 +10620,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 e079987af4a3e41a5589e84f6f19853b5b5bc402..9a5d911a7edc77cae53cac45aa43f196b32caf20 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 306cba0b9e69af45b7fd5e57926dccb9c886ec77..84343aefbbd64cdf241fcf4e677ba50e991d9109 100644 (file)
@@ -2634,31 +2634,44 @@ pnfs_should_return_unused_layout(struct pnfs_layout_hdr *lo,
        return mode == 0;
 }
 
-static int
-pnfs_layout_return_unused_byserver(struct nfs_server *server, void *data)
+static int pnfs_layout_return_unused_byserver(struct nfs_server *server,
+                                             void *data)
 {
        const struct pnfs_layout_range *range = data;
+       const struct cred *cred;
        struct pnfs_layout_hdr *lo;
        struct inode *inode;
+       nfs4_stateid stateid;
+       enum pnfs_iomode iomode;
+
 restart:
        rcu_read_lock();
        list_for_each_entry_rcu(lo, &server->layouts, plh_layouts) {
-               if (!pnfs_layout_can_be_returned(lo) ||
+               inode = lo->plh_inode;
+               if (!inode || !pnfs_layout_can_be_returned(lo) ||
                    test_bit(NFS_LAYOUT_RETURN_REQUESTED, &lo->plh_flags))
                        continue;
-               inode = lo->plh_inode;
                spin_lock(&inode->i_lock);
-               if (!pnfs_should_return_unused_layout(lo, range)) {
+               if (!lo->plh_inode ||
+                   !pnfs_should_return_unused_layout(lo, range)) {
                        spin_unlock(&inode->i_lock);
                        continue;
                }
+               pnfs_get_layout_hdr(lo);
+               pnfs_set_plh_return_info(lo, range->iomode, 0);
+               if (pnfs_mark_matching_lsegs_return(lo, &lo->plh_return_segs,
+                                                   range, 0) != 0 ||
+                   !pnfs_prepare_layoutreturn(lo, &stateid, &cred, &iomode)) {
+                       spin_unlock(&inode->i_lock);
+                       rcu_read_unlock();
+                       pnfs_put_layout_hdr(lo);
+                       cond_resched();
+                       goto restart;
+               }
                spin_unlock(&inode->i_lock);
-               inode = pnfs_grab_inode_layout_hdr(lo);
-               if (!inode)
-                       continue;
                rcu_read_unlock();
-               pnfs_mark_layout_for_return(inode, range);
-               iput(inode);
+               pnfs_send_layoutreturn(lo, &stateid, &cred, iomode, false);
+               pnfs_put_layout_hdr(lo);
                cond_resched();
                goto restart;
        }
index f4cca8f00c0c20f6906e4e2e08ea19fc1a692e00..9d82d50ce0b12dc7063f021d4380582633ed419f 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;
 }
@@ -785,6 +788,8 @@ static void nfs_inode_add_request(struct nfs_page *req)
  */
 static void nfs_inode_remove_request(struct nfs_page *req)
 {
+       struct nfs_inode *nfsi = NFS_I(nfs_page_to_inode(req));
+
        if (nfs_page_group_sync_on_bit(req, PG_REMOVE)) {
                struct folio *folio = nfs_page_to_folio(req->wb_head);
                struct address_space *mapping = folio_file_mapping(folio);
@@ -799,8 +804,8 @@ static void nfs_inode_remove_request(struct nfs_page *req)
        }
 
        if (test_and_clear_bit(PG_INODE_REF, &req->wb_flags)) {
+               atomic_long_dec(&nfsi->nrequests);
                nfs_release_request(req);
-               atomic_long_dec(&NFS_I(nfs_page_to_inode(req))->nrequests);
        }
 }
 
@@ -955,18 +960,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 2e40c74d2f7278188e1ed0e124420db0428f132d..92c7dde148a4d81f3e29a4efbd480c9cffa03e3a 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 48260cf68fde8b73510ff7cc5a833cc8b5e66e84..02f5fcaad03f376a60f0771c680431d424717d01 100644 (file)
@@ -1788,6 +1788,12 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
        if (!flen || isdotent(fname, flen) || !tlen || isdotent(tname, tlen))
                goto out;
 
+       err = (rqstp->rq_vers == 2) ? nfserr_acces : nfserr_xdev;
+       if (ffhp->fh_export->ex_path.mnt != tfhp->fh_export->ex_path.mnt)
+               goto out;
+       if (ffhp->fh_export->ex_path.dentry != tfhp->fh_export->ex_path.dentry)
+               goto out;
+
 retry:
        host_err = fh_want_write(ffhp);
        if (host_err) {
@@ -1823,12 +1829,6 @@ retry:
        if (ndentry == trap)
                goto out_dput_new;
 
-       host_err = -EXDEV;
-       if (ffhp->fh_export->ex_path.mnt != tfhp->fh_export->ex_path.mnt)
-               goto out_dput_new;
-       if (ffhp->fh_export->ex_path.dentry != tfhp->fh_export->ex_path.dentry)
-               goto out_dput_new;
-
        if ((ndentry->d_sb->s_export_op->flags & EXPORT_OP_CLOSE_BEFORE_UNLINK) &&
            nfsd_has_cached_files(ndentry)) {
                close_cached = true;
index 48fe71d309cb4ac381ae247d16f2cbfbf1c28bea..8beb2730929d43578ad9b22a721201bb4540237d 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 f69c451018e33defb493eef93b538b6507138422..62fe0b679e586ccbe181000fe94ed5e2b142b203 100644 (file)
@@ -1585,16 +1585,25 @@ static int fanotify_test_fsid(struct dentry *dentry, __kernel_fsid_t *fsid)
 }
 
 /* Check if filesystem can encode a unique fid */
-static int fanotify_test_fid(struct dentry *dentry)
+static int fanotify_test_fid(struct dentry *dentry, unsigned int flags)
 {
+       unsigned int mark_type = flags & FANOTIFY_MARK_TYPE_BITS;
+       const struct export_operations *nop = dentry->d_sb->s_export_op;
+
+       /*
+        * We need to make sure that the filesystem supports encoding of
+        * file handles so user can use name_to_handle_at() to compare fids
+        * reported with events to the file handle of watched objects.
+        */
+       if (!nop)
+               return -EOPNOTSUPP;
+
        /*
-        * We need to make sure that the file system supports at least
-        * encoding a file handle so user can use name_to_handle_at() to
-        * compare fid returned with event to the file handle of watched
-        * objects. However, even the relaxed AT_HANDLE_FID flag requires
-        * at least empty export_operations for ecoding unique file ids.
+        * For sb/mount mark, we also need to make sure that the filesystem
+        * supports decoding file handles, so user has a way to map back the
+        * reported fids to filesystem objects.
         */
-       if (!dentry->d_sb->s_export_op)
+       if (mark_type != FAN_MARK_INODE && !nop->fh_to_dentry)
                return -EOPNOTSUPP;
 
        return 0;
@@ -1812,7 +1821,7 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
                if (ret)
                        goto path_put_and_out;
 
-               ret = fanotify_test_fid(path.dentry);
+               ret = fanotify_test_fid(path.dentry, flags);
                if (ret)
                        goto path_put_and_out;
 
index a9d82bbb4729ecf1b65984ed05a2d8c259d2028f..63f70259edc0d44d6a52c946c9a90663fe16722a 100644 (file)
@@ -1106,10 +1106,10 @@ repack:
                }
        }
 
-       /* 
+       /*
         * The code below may require additional cluster (to extend attribute list)
-        * and / or one MFT record 
-        * It is too complex to undo operations if -ENOSPC occurs deep inside 
+        * and / or one MFT record
+        * It is too complex to undo operations if -ENOSPC occurs deep inside
         * in 'ni_insert_nonresident'.
         * Return in advance -ENOSPC here if there are no free cluster and no free MFT.
         */
@@ -1736,10 +1736,8 @@ repack:
                        le_b = NULL;
                        attr_b = ni_find_attr(ni, NULL, &le_b, ATTR_DATA, NULL,
                                              0, NULL, &mi_b);
-                       if (!attr_b) {
-                               err = -ENOENT;
-                               goto out;
-                       }
+                       if (!attr_b)
+                               return -ENOENT;
 
                        attr = attr_b;
                        le = le_b;
index 42631b31adf17f39c635eacd3c0a8a033583d96b..7c01735d1219d858b46809147fa06dbcc6cafe4c 100644 (file)
@@ -52,7 +52,8 @@ int ntfs_load_attr_list(struct ntfs_inode *ni, struct ATTRIB *attr)
 
        if (!attr->non_res) {
                lsize = le32_to_cpu(attr->res.data_size);
-               le = kmalloc(al_aligned(lsize), GFP_NOFS | __GFP_NOWARN);
+               /* attr is resident: lsize < record_size (1K or 4K) */
+               le = kvmalloc(al_aligned(lsize), GFP_KERNEL);
                if (!le) {
                        err = -ENOMEM;
                        goto out;
@@ -80,7 +81,17 @@ int ntfs_load_attr_list(struct ntfs_inode *ni, struct ATTRIB *attr)
                if (err < 0)
                        goto out;
 
-               le = kmalloc(al_aligned(lsize), GFP_NOFS | __GFP_NOWARN);
+               /* attr is nonresident.
+                * The worst case:
+                * 1T (2^40) extremely fragmented file.
+                * cluster = 4K (2^12) => 2^28 fragments
+                * 2^9 fragments per one record => 2^19 records
+                * 2^5 bytes of ATTR_LIST_ENTRY per one record => 2^24 bytes.
+                *
+                * the result is 16M bytes per attribute list.
+                * Use kvmalloc to allocate in range [several Kbytes - dozen Mbytes]
+                */
+               le = kvmalloc(al_aligned(lsize), GFP_KERNEL);
                if (!le) {
                        err = -ENOMEM;
                        goto out;
index 107e808e06eae0068303c028d3c84c001f856142..63f14a0232f6a0e0672c5373748bf77b72931bf2 100644 (file)
@@ -125,6 +125,7 @@ void wnd_close(struct wnd_bitmap *wnd)
        struct rb_node *node, *next;
 
        kfree(wnd->free_bits);
+       wnd->free_bits = NULL;
        run_close(&wnd->run);
 
        node = rb_first(&wnd->start_tree);
@@ -659,7 +660,8 @@ int wnd_init(struct wnd_bitmap *wnd, struct super_block *sb, size_t nbits)
                wnd->bits_last = wbits;
 
        wnd->free_bits =
-               kcalloc(wnd->nwnd, sizeof(u16), GFP_NOFS | __GFP_NOWARN);
+               kvmalloc_array(wnd->nwnd, sizeof(u16), GFP_KERNEL | __GFP_ZERO);
+
        if (!wnd->free_bits)
                return -ENOMEM;
 
index 063a6654199bc078074e2b85f34ce1f31d93a197..ec0566b322d5d0b4b36533a3a218671bb0ff7b02 100644 (file)
@@ -309,7 +309,11 @@ static inline int ntfs_filldir(struct ntfs_sb_info *sbi, struct ntfs_inode *ni,
                return 0;
        }
 
-       dt_type = (fname->dup.fa & FILE_ATTRIBUTE_DIRECTORY) ? DT_DIR : DT_REG;
+       /* NTFS: symlinks are "dir + reparse" or "file + reparse" */
+       if (fname->dup.fa & FILE_ATTRIBUTE_REPARSE_POINT)
+               dt_type = DT_LNK;
+       else
+               dt_type = (fname->dup.fa & FILE_ATTRIBUTE_DIRECTORY) ? DT_DIR : DT_REG;
 
        return !dir_emit(ctx, (s8 *)name, name_len, ino, dt_type);
 }
index 962f12ce6c0a62c183236e3658b666f23c02ab58..1f7a194983c5db46e45c96d88966f6420581066c 100644 (file)
@@ -745,8 +745,8 @@ static ssize_t ntfs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
 }
 
 static ssize_t ntfs_file_splice_read(struct file *in, loff_t *ppos,
-                                    struct pipe_inode_info *pipe,
-                                    size_t len, unsigned int flags)
+                                    struct pipe_inode_info *pipe, size_t len,
+                                    unsigned int flags)
 {
        struct inode *inode = in->f_mapping->host;
        struct ntfs_inode *ni = ntfs_i(inode);
index 2b85cb10f0be405e89390815a8fd77b0f6031fce..dad976a6898596987d82d5ed07f40679b0a13f4a 100644 (file)
@@ -2148,7 +2148,7 @@ out1:
 
        for (i = 0; i < pages_per_frame; i++) {
                pg = pages[i];
-               if (i == idx)
+               if (i == idx || !pg)
                        continue;
                unlock_page(pg);
                put_page(pg);
@@ -3208,6 +3208,12 @@ static bool ni_update_parent(struct ntfs_inode *ni, struct NTFS_DUP_INFO *dup,
                if (!fname || !memcmp(&fname->dup, dup, sizeof(fname->dup)))
                        continue;
 
+               /* Check simple case when parent inode equals current inode. */
+               if (ino_get(&fname->home) == ni->vfs_inode.i_ino) {
+                       ntfs_set_state(sbi, NTFS_DIRTY_ERROR);
+                       continue;
+               }
+
                /* ntfs_iget5 may sleep. */
                dir = ntfs_iget5(sb, &fname->home, NULL);
                if (IS_ERR(dir)) {
index 12f28cdf5c838bfdc75b499e33551aa6ca89e237..98ccb66508583138ed7f5c273b2f4450be88159b 100644 (file)
@@ -2168,8 +2168,10 @@ file_is_valid:
 
                        if (!page) {
                                page = kmalloc(log->page_size, GFP_NOFS);
-                               if (!page)
-                                       return -ENOMEM;
+                               if (!page) {
+                                       err = -ENOMEM;
+                                       goto out;
+                               }
                        }
 
                        /*
index 33afee0f55593a92ff40315262ac4524a152eb40..fbfe21dbb42597cdb25a6d809f7b396e37508046 100644 (file)
@@ -983,18 +983,11 @@ out:
        if (err)
                return err;
 
-       mark_inode_dirty(&ni->vfs_inode);
+       mark_inode_dirty_sync(&ni->vfs_inode);
        /* verify(!ntfs_update_mftmirr()); */
 
-       /*
-        * If we used wait=1, sync_inode_metadata waits for the io for the
-        * inode to finish. It hangs when media is removed.
-        * So wait=0 is sent down to sync_inode_metadata
-        * and filemap_fdatawrite is used for the data blocks.
-        */
-       err = sync_inode_metadata(&ni->vfs_inode, 0);
-       if (!err)
-               err = filemap_fdatawrite(ni->vfs_inode.i_mapping);
+       /* write mft record on disk. */
+       err = _ni_write_inode(&ni->vfs_inode, 1);
 
        return err;
 }
@@ -2461,10 +2454,12 @@ void mark_as_free_ex(struct ntfs_sb_info *sbi, CLST lcn, CLST len, bool trim)
 {
        CLST end, i, zone_len, zlen;
        struct wnd_bitmap *wnd = &sbi->used.bitmap;
+       bool dirty = false;
 
        down_write_nested(&wnd->rw_lock, BITMAP_MUTEX_CLUSTERS);
        if (!wnd_is_used(wnd, lcn, len)) {
-               ntfs_set_state(sbi, NTFS_DIRTY_ERROR);
+               /* mark volume as dirty out of wnd->rw_lock */
+               dirty = true;
 
                end = lcn + len;
                len = 0;
@@ -2518,6 +2513,8 @@ void mark_as_free_ex(struct ntfs_sb_info *sbi, CLST lcn, CLST len, bool trim)
 
 out:
        up_write(&wnd->rw_lock);
+       if (dirty)
+               ntfs_set_state(sbi, NTFS_DIRTY_ERROR);
 }
 
 /*
index 124c6e822623feaff048f3b15354702944092de8..cf92b2433f7a750aeb86383eb7440c730ad7dc95 100644 (file)
@@ -729,6 +729,9 @@ static struct NTFS_DE *hdr_find_e(const struct ntfs_index *indx,
        u32 total = le32_to_cpu(hdr->total);
        u16 offs[128];
 
+       if (unlikely(!cmp))
+               return NULL;
+
 fill_table:
        if (end > total)
                return NULL;
index eb2ed0701495f103e62093283b769777752bf85e..d6d021e19aaa23ed8cd32e785798a61095411b45 100644 (file)
@@ -170,8 +170,8 @@ next_attr:
                nt2kernel(std5->cr_time, &ni->i_crtime);
 #endif
                nt2kernel(std5->a_time, &inode->i_atime);
-               ctime = inode_get_ctime(inode);
                nt2kernel(std5->c_time, &ctime);
+               inode_set_ctime_to_ts(inode, ctime);
                nt2kernel(std5->m_time, &inode->i_mtime);
 
                ni->std_fa = std5->fa;
@@ -1660,7 +1660,8 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap, struct inode *dir,
        d_instantiate(dentry, inode);
 
        /* Set original time. inode times (i_ctime) may be changed in ntfs_init_acl. */
-       inode->i_atime = inode->i_mtime = inode_set_ctime_to_ts(inode, ni->i_crtime);
+       inode->i_atime = inode->i_mtime =
+               inode_set_ctime_to_ts(inode, ni->i_crtime);
        dir->i_mtime = inode_set_ctime_to_ts(dir, ni->i_crtime);
 
        mark_inode_dirty(dir);
index ad430d50bd79836dca326afe3190cbcd47adfb2a..eedacf94edd80552791181407382d0e68dd8e191 100644 (file)
@@ -156,8 +156,8 @@ static int ntfs_link(struct dentry *ode, struct inode *dir, struct dentry *de)
        err = ntfs_link_inode(inode, de);
 
        if (!err) {
-               dir->i_mtime = inode_set_ctime_to_ts(inode,
-                                                    inode_set_ctime_current(dir));
+               dir->i_mtime = inode_set_ctime_to_ts(
+                       inode, inode_set_ctime_current(dir));
                mark_inode_dirty(inode);
                mark_inode_dirty(dir);
                d_instantiate(de, inode);
@@ -373,7 +373,7 @@ static int ntfs_atomic_open(struct inode *dir, struct dentry *dentry,
 
 #ifdef CONFIG_NTFS3_FS_POSIX_ACL
        if (IS_POSIXACL(dir)) {
-               /* 
+               /*
                 * Load in cache current acl to avoid ni_lock(dir):
                 * ntfs_create_inode -> ntfs_init_acl -> posix_acl_create ->
                 * ntfs_get_acl -> ntfs_get_acl_ex -> ni_lock
index 98b76d1b09e78774acbc614ed7f33c42b608912f..86aecbb01a92f282ab621a26df9897b70b65df28 100644 (file)
@@ -847,7 +847,7 @@ struct OBJECT_ID {
        // Birth Volume Id is the Object Id of the Volume on.
        // which the Object Id was allocated. It never changes.
        struct GUID BirthVolumeId; //0x10:
-       
+
        // Birth Object Id is the first Object Id that was
        // ever assigned to this MFT Record. I.e. If the Object Id
        // is changed for some reason, this field will reflect the
index 629403ede6e5f1713cb1f063f354afaa62682c3c..0e6a2777870c3e26d1ae2219b31f89c92b22f2ca 100644 (file)
@@ -42,9 +42,11 @@ enum utf16_endian;
 #define MINUS_ONE_T                    ((size_t)(-1))
 /* Biggest MFT / smallest cluster */
 #define MAXIMUM_BYTES_PER_MFT          4096
+#define MAXIMUM_SHIFT_BYTES_PER_MFT    12
 #define NTFS_BLOCKS_PER_MFT_RECORD     (MAXIMUM_BYTES_PER_MFT / 512)
 
 #define MAXIMUM_BYTES_PER_INDEX                4096
+#define MAXIMUM_SHIFT_BYTES_PER_INDEX  12
 #define NTFS_BLOCKS_PER_INODE          (MAXIMUM_BYTES_PER_INDEX / 512)
 
 /* NTFS specific error code when fixup failed. */
@@ -495,8 +497,6 @@ int ntfs_getattr(struct mnt_idmap *idmap, const struct path *path,
                 struct kstat *stat, u32 request_mask, u32 flags);
 int ntfs3_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
                  struct iattr *attr);
-void ntfs_sparse_cluster(struct inode *inode, struct page *page0, CLST vcn,
-                        CLST len);
 int ntfs_file_open(struct inode *inode, struct file *file);
 int ntfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                __u64 start, __u64 len);
index c12ebffc94da4c995955315687eb85a6288658f1..53629b1f65e995978cef9b312462447305cb578d 100644 (file)
@@ -189,12 +189,19 @@ out:
        return err;
 }
 
+/*
+ * mi_enum_attr - start/continue attributes enumeration in record.
+ *
+ * NOTE: mi->mrec - memory of size sbi->record_size
+ * here we sure that mi->mrec->total == sbi->record_size (see mi_read)
+ */
 struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)
 {
        const struct MFT_REC *rec = mi->mrec;
        u32 used = le32_to_cpu(rec->used);
-       u32 t32, off, asize;
+       u32 t32, off, asize, prev_type;
        u16 t16;
+       u64 data_size, alloc_size, tot_size;
 
        if (!attr) {
                u32 total = le32_to_cpu(rec->total);
@@ -213,6 +220,7 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)
                if (!is_rec_inuse(rec))
                        return NULL;
 
+               prev_type = 0;
                attr = Add2Ptr(rec, off);
        } else {
                /* Check if input attr inside record. */
@@ -226,11 +234,11 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)
                        return NULL;
                }
 
-               if (off + asize < off) {
-                       /* Overflow check. */
+               /* Overflow check. */
+               if (off + asize < off)
                        return NULL;
-               }
 
+               prev_type = le32_to_cpu(attr->type);
                attr = Add2Ptr(attr, asize);
                off += asize;
        }
@@ -250,7 +258,11 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)
 
        /* 0x100 is last known attribute for now. */
        t32 = le32_to_cpu(attr->type);
-       if ((t32 & 0xf) || (t32 > 0x100))
+       if (!t32 || (t32 & 0xf) || (t32 > 0x100))
+               return NULL;
+
+       /* attributes in record must be ordered by type */
+       if (t32 < prev_type)
                return NULL;
 
        /* Check overflow and boundary. */
@@ -259,16 +271,15 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)
 
        /* Check size of attribute. */
        if (!attr->non_res) {
+               /* Check resident fields. */
                if (asize < SIZEOF_RESIDENT)
                        return NULL;
 
                t16 = le16_to_cpu(attr->res.data_off);
-
                if (t16 > asize)
                        return NULL;
 
-               t32 = le32_to_cpu(attr->res.data_size);
-               if (t16 + t32 > asize)
+               if (t16 + le32_to_cpu(attr->res.data_size) > asize)
                        return NULL;
 
                t32 = sizeof(short) * attr->name_len;
@@ -278,21 +289,52 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)
                return attr;
        }
 
-       /* Check some nonresident fields. */
-       if (attr->name_len &&
-           le16_to_cpu(attr->name_off) + sizeof(short) * attr->name_len >
-                   le16_to_cpu(attr->nres.run_off)) {
+       /* Check nonresident fields. */
+       if (attr->non_res != 1)
+               return NULL;
+
+       t16 = le16_to_cpu(attr->nres.run_off);
+       if (t16 > asize)
+               return NULL;
+
+       t32 = sizeof(short) * attr->name_len;
+       if (t32 && le16_to_cpu(attr->name_off) + t32 > t16)
+               return NULL;
+
+       /* Check start/end vcn. */
+       if (le64_to_cpu(attr->nres.svcn) > le64_to_cpu(attr->nres.evcn) + 1)
                return NULL;
-       }
 
-       if (attr->nres.svcn || !is_attr_ext(attr)) {
+       data_size = le64_to_cpu(attr->nres.data_size);
+       if (le64_to_cpu(attr->nres.valid_size) > data_size)
+               return NULL;
+
+       alloc_size = le64_to_cpu(attr->nres.alloc_size);
+       if (data_size > alloc_size)
+               return NULL;
+
+       t32 = mi->sbi->cluster_mask;
+       if (alloc_size & t32)
+               return NULL;
+
+       if (!attr->nres.svcn && is_attr_ext(attr)) {
+               /* First segment of sparse/compressed attribute */
+               if (asize + 8 < SIZEOF_NONRESIDENT_EX)
+                       return NULL;
+
+               tot_size = le64_to_cpu(attr->nres.total_size);
+               if (tot_size & t32)
+                       return NULL;
+
+               if (tot_size > alloc_size)
+                       return NULL;
+       } else {
                if (asize + 8 < SIZEOF_NONRESIDENT)
                        return NULL;
 
                if (attr->nres.c_unit)
                        return NULL;
-       } else if (asize + 8 < SIZEOF_NONRESIDENT_EX)
-               return NULL;
+       }
 
        return attr;
 }
index cfec5e0c7f66ae923ab13dc18e88d4cba86b7478..f763e3256ccc1b6bf8b49acd783030ec4f59eef6 100644 (file)
@@ -453,15 +453,23 @@ static struct proc_dir_entry *proc_info_root;
  * ntfs3.1
  * cluster size
  * number of clusters
+ * total number of mft records
+ * number of used mft records ~= number of files + folders
+ * real state of ntfs "dirty"/"clean"
+ * current state of ntfs "dirty"/"clean"
 */
 static int ntfs3_volinfo(struct seq_file *m, void *o)
 {
        struct super_block *sb = m->private;
        struct ntfs_sb_info *sbi = sb->s_fs_info;
 
-       seq_printf(m, "ntfs%d.%d\n%u\n%zu\n", sbi->volume.major_ver,
-                  sbi->volume.minor_ver, sbi->cluster_size,
-                  sbi->used.bitmap.nbits);
+       seq_printf(m, "ntfs%d.%d\n%u\n%zu\n\%zu\n%zu\n%s\n%s\n",
+                  sbi->volume.major_ver, sbi->volume.minor_ver,
+                  sbi->cluster_size, sbi->used.bitmap.nbits,
+                  sbi->mft.bitmap.nbits,
+                  sbi->mft.bitmap.nbits - wnd_zeroes(&sbi->mft.bitmap),
+                  sbi->volume.real_dirty ? "dirty" : "clean",
+                  (sbi->volume.flags & VOLUME_FLAG_DIRTY) ? "dirty" : "clean");
 
        return 0;
 }
@@ -488,9 +496,13 @@ static ssize_t ntfs3_label_write(struct file *file, const char __user *buffer,
 {
        int err;
        struct super_block *sb = pde_data(file_inode(file));
-       struct ntfs_sb_info *sbi = sb->s_fs_info;
        ssize_t ret = count;
-       u8 *label = kmalloc(count, GFP_NOFS);
+       u8 *label;
+
+       if (sb_rdonly(sb))
+               return -EROFS;
+
+       label = kmalloc(count, GFP_NOFS);
 
        if (!label)
                return -ENOMEM;
@@ -502,7 +514,7 @@ static ssize_t ntfs3_label_write(struct file *file, const char __user *buffer,
        while (ret > 0 && label[ret - 1] == '\n')
                ret -= 1;
 
-       err = ntfs_set_label(sbi, label, ret);
+       err = ntfs_set_label(sb->s_fs_info, label, ret);
 
        if (err < 0) {
                ntfs_err(sb, "failed (%d) to write label", err);
@@ -576,20 +588,30 @@ static noinline void ntfs3_put_sbi(struct ntfs_sb_info *sbi)
        wnd_close(&sbi->mft.bitmap);
        wnd_close(&sbi->used.bitmap);
 
-       if (sbi->mft.ni)
+       if (sbi->mft.ni) {
                iput(&sbi->mft.ni->vfs_inode);
+               sbi->mft.ni = NULL;
+       }
 
-       if (sbi->security.ni)
+       if (sbi->security.ni) {
                iput(&sbi->security.ni->vfs_inode);
+               sbi->security.ni = NULL;
+       }
 
-       if (sbi->reparse.ni)
+       if (sbi->reparse.ni) {
                iput(&sbi->reparse.ni->vfs_inode);
+               sbi->reparse.ni = NULL;
+       }
 
-       if (sbi->objid.ni)
+       if (sbi->objid.ni) {
                iput(&sbi->objid.ni->vfs_inode);
+               sbi->objid.ni = NULL;
+       }
 
-       if (sbi->volume.ni)
+       if (sbi->volume.ni) {
                iput(&sbi->volume.ni->vfs_inode);
+               sbi->volume.ni = NULL;
+       }
 
        ntfs_update_mftmirr(sbi, 0);
 
@@ -836,7 +858,7 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size,
        struct ntfs_sb_info *sbi = sb->s_fs_info;
        int err;
        u32 mb, gb, boot_sector_size, sct_per_clst, record_size;
-       u64 sectors, clusters, mlcn, mlcn2;
+       u64 sectors, clusters, mlcn, mlcn2, dev_size0;
        struct NTFS_BOOT *boot;
        struct buffer_head *bh;
        struct MFT_REC *rec;
@@ -845,6 +867,9 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size,
        u32 boot_off = 0;
        const char *hint = "Primary boot";
 
+       /* Save original dev_size. Used with alternative boot. */
+       dev_size0 = dev_size;
+
        sbi->volume.blocks = dev_size >> PAGE_SHIFT;
 
        bh = ntfs_bread(sb, 0);
@@ -853,6 +878,11 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size,
 
 check_boot:
        err = -EINVAL;
+
+       /* Corrupted image; do not read OOB */
+       if (bh->b_size - sizeof(*boot) < boot_off)
+               goto out;
+
        boot = (struct NTFS_BOOT *)Add2Ptr(bh->b_data, boot_off);
 
        if (memcmp(boot->system_id, "NTFS    ", sizeof("NTFS    ") - 1)) {
@@ -899,9 +929,17 @@ check_boot:
                goto out;
        }
 
-       sbi->record_size = record_size =
-               boot->record_size < 0 ? 1 << (-boot->record_size) :
-                                       (u32)boot->record_size << cluster_bits;
+       if (boot->record_size >= 0) {
+               record_size = (u32)boot->record_size << cluster_bits;
+       } else if (-boot->record_size <= MAXIMUM_SHIFT_BYTES_PER_MFT) {
+               record_size = 1u << (-boot->record_size);
+       } else {
+               ntfs_err(sb, "%s: invalid record size %d.", hint,
+                        boot->record_size);
+               goto out;
+       }
+
+       sbi->record_size = record_size;
        sbi->record_bits = blksize_bits(record_size);
        sbi->attr_size_tr = (5 * record_size >> 4); // ~320 bytes
 
@@ -918,9 +956,15 @@ check_boot:
                goto out;
        }
 
-       sbi->index_size = boot->index_size < 0 ?
-                                 1u << (-boot->index_size) :
-                                 (u32)boot->index_size << cluster_bits;
+       if (boot->index_size >= 0) {
+               sbi->index_size = (u32)boot->index_size << cluster_bits;
+       } else if (-boot->index_size <= MAXIMUM_SHIFT_BYTES_PER_INDEX) {
+               sbi->index_size = 1u << (-boot->index_size);
+       } else {
+               ntfs_err(sb, "%s: invalid index size %d.", hint,
+                        boot->index_size);
+               goto out;
+       }
 
        /* Check index record size. */
        if (sbi->index_size < SECTOR_SIZE || !is_power_of_2(sbi->index_size)) {
@@ -1055,17 +1099,17 @@ check_boot:
 
        if (bh->b_blocknr && !sb_rdonly(sb)) {
                /*
-            * Alternative boot is ok but primary is not ok.
-            * Do not update primary boot here 'cause it may be faked boot.
-            * Let ntfs to be mounted and update boot later.
-            */
+                * Alternative boot is ok but primary is not ok.
+                * Do not update primary boot here 'cause it may be faked boot.
+                * Let ntfs to be mounted and update boot later.
+                */
                *boot2 = kmemdup(boot, sizeof(*boot), GFP_NOFS | __GFP_NOWARN);
        }
 
 out:
-       if (err == -EINVAL && !bh->b_blocknr && dev_size > PAGE_SHIFT) {
+       if (err == -EINVAL && !bh->b_blocknr && dev_size0 > PAGE_SHIFT) {
                u32 block_size = min_t(u32, sector_size, PAGE_SIZE);
-               u64 lbo = dev_size - sizeof(*boot);
+               u64 lbo = dev_size0 - sizeof(*boot);
 
                /*
                 * Try alternative boot (last sector)
@@ -1079,6 +1123,7 @@ out:
 
                boot_off = lbo & (block_size - 1);
                hint = "Alternative boot";
+               dev_size = dev_size0; /* restore original size. */
                goto check_boot;
        }
        brelse(bh);
@@ -1367,7 +1412,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
        }
 
        bytes = inode->i_size;
-       sbi->def_table = t = kmalloc(bytes, GFP_NOFS | __GFP_NOWARN);
+       sbi->def_table = t = kvmalloc(bytes, GFP_KERNEL);
        if (!t) {
                err = -ENOMEM;
                goto put_inode_out;
@@ -1521,9 +1566,9 @@ load_root:
 
        if (boot2) {
                /*
-            * Alternative boot is ok but primary is not ok.
-            * Volume is recognized as NTFS. Update primary boot.
-            */
+                * Alternative boot is ok but primary is not ok.
+                * Volume is recognized as NTFS. Update primary boot.
+                */
                struct buffer_head *bh0 = sb_getblk(sb, 0);
                if (bh0) {
                        if (buffer_locked(bh0))
@@ -1562,7 +1607,9 @@ load_root:
 put_inode_out:
        iput(inode);
 out:
+       ntfs3_put_sbi(sbi);
        kfree(boot2);
+       ntfs3_put_sbi(sbi);
        return err;
 }
 
@@ -1756,7 +1803,6 @@ static int __init init_ntfs_fs(void)
        if (IS_ENABLED(CONFIG_NTFS3_LZX_XPRESS))
                pr_info("ntfs3: Read-only LZX/Xpress compression included\n");
 
-
 #ifdef CONFIG_PROC_FS
        /* Create "/proc/fs/ntfs3" */
        proc_info_root = proc_mkdir("fs/ntfs3", NULL);
@@ -1798,7 +1844,6 @@ static void __exit exit_ntfs_fs(void)
        if (proc_info_root)
                remove_proc_entry("fs/ntfs3", NULL);
 #endif
-
 }
 
 MODULE_LICENSE("GPL");
index 29fd391899e59dfde9b29e920f7303862b7167ff..4920548192a0cf3513060717194e0e57c94452f9 100644 (file)
@@ -211,7 +211,8 @@ static ssize_t ntfs_list_ea(struct ntfs_inode *ni, char *buffer,
        size = le32_to_cpu(info->size);
 
        /* Enumerate all xattrs. */
-       for (ret = 0, off = 0; off < size; off += ea_size) {
+       ret = 0;
+       for (off = 0; off + sizeof(struct EA_FULL) < size; off += ea_size) {
                ea = Add2Ptr(ea_all, off);
                ea_size = unpacked_ea_size(ea);
 
@@ -219,6 +220,10 @@ static ssize_t ntfs_list_ea(struct ntfs_inode *ni, char *buffer,
                        break;
 
                if (buffer) {
+                       /* Check if we can use field ea->name */
+                       if (off + ea_size > size)
+                               break;
+
                        if (ret + ea->name_len + 1 > bytes_per_buffer) {
                                err = -ERANGE;
                                goto out;
index d1761ec5866aa6342db3d6091bd3cc06998d5ca6..ada3fcc9c6d5015ac65929ecf6738720b51615d6 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 c8c8588bd98caf4a29cd31d9e0e873de70fcec28..26b782c53910b538cb26d770fdb6b9416d0f19dd 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 4193633c4c7a771a880acb08d28b561080d2d8b1..8be4dc050d1ed2e5508f62e84be2d5a835990d36 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 e9539f98e86a4b29d0c54dc1859ea13d37cd46f2..d82d2a043da2c7b7ea055a5c7dbbe0b3c2544dbc 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 b9355bb6d75a33128c8ad84903dd0358b4edcd96..f6ff23fd101c8f3cda5f485c657a51b24fd565d1 100644 (file)
@@ -157,6 +157,34 @@ const struct fs_parameter_spec ovl_parameter_spec[] = {
        {}
 };
 
+static char *ovl_next_opt(char **s)
+{
+       char *sbegin = *s;
+       char *p;
+
+       if (sbegin == NULL)
+               return NULL;
+
+       for (p = sbegin; *p; p++) {
+               if (*p == '\\') {
+                       p++;
+                       if (!*p)
+                               break;
+               } else if (*p == ',') {
+                       *p = '\0';
+                       *s = p + 1;
+                       return sbegin;
+               }
+       }
+       *s = NULL;
+       return sbegin;
+}
+
+static int ovl_parse_monolithic(struct fs_context *fc, void *data)
+{
+       return vfs_parse_monolithic_sep(fc, data, ovl_next_opt);
+}
+
 static ssize_t ovl_parse_param_split_lowerdirs(char *str)
 {
        ssize_t nr_layers = 1, nr_colons = 0;
@@ -164,7 +192,8 @@ static ssize_t ovl_parse_param_split_lowerdirs(char *str)
 
        for (s = d = str;; s++, d++) {
                if (*s == '\\') {
-                       s++;
+                       /* keep esc chars in split lowerdir */
+                       *d++ = *s++;
                } else if (*s == ':') {
                        bool next_colon = (*(s + 1) == ':');
 
@@ -239,7 +268,7 @@ static void ovl_unescape(char *s)
        }
 }
 
-static int ovl_mount_dir(const char *name, struct path *path)
+static int ovl_mount_dir(const char *name, struct path *path, bool upper)
 {
        int err = -ENOMEM;
        char *tmp = kstrdup(name, GFP_KERNEL);
@@ -248,7 +277,7 @@ static int ovl_mount_dir(const char *name, struct path *path)
                ovl_unescape(tmp);
                err = ovl_mount_dir_noesc(tmp, path);
 
-               if (!err && path->dentry->d_flags & DCACHE_OP_REAL) {
+               if (!err && upper && path->dentry->d_flags & DCACHE_OP_REAL) {
                        pr_err("filesystem on '%s' not supported as upperdir\n",
                               tmp);
                        path_put_init(path);
@@ -269,7 +298,7 @@ static int ovl_parse_param_upperdir(const char *name, struct fs_context *fc,
        struct path path;
        char *dup;
 
-       err = ovl_mount_dir(name, &path);
+       err = ovl_mount_dir(name, &path, true);
        if (err)
                return err;
 
@@ -321,12 +350,6 @@ static void ovl_parse_param_drop_lowerdir(struct ovl_fs_context *ctx)
  *     Set "/lower1", "/lower2", and "/lower3" as lower layers and
  *     "/data1" and "/data2" as data lower layers. Any existing lower
  *     layers are replaced.
- * (2) lowerdir=:/lower4
- *     Append "/lower4" to current stack of lower layers. This requires
- *     that there already is at least one lower layer configured.
- * (3) lowerdir=::/lower5
- *     Append data "/lower5" as data lower layer. This requires that
- *     there's at least one regular lower layer present.
  */
 static int ovl_parse_param_lowerdir(const char *name, struct fs_context *fc)
 {
@@ -348,49 +371,9 @@ static int ovl_parse_param_lowerdir(const char *name, struct fs_context *fc)
                return 0;
        }
 
-       if (strncmp(name, "::", 2) == 0) {
-               /*
-                * This is a data layer.
-                * There must be at least one regular lower layer
-                * specified.
-                */
-               if (ctx->nr == 0) {
-                       pr_err("data lower layers without regular lower layers not allowed");
-                       return -EINVAL;
-               }
-
-               /* Skip the leading "::". */
-               name += 2;
-               data_layer = true;
-               /*
-                * A data layer is automatically an append as there
-                * must've been at least one regular lower layer.
-                */
-               append = true;
-       } else if (*name == ':') {
-               /*
-                * This is a regular lower layer.
-                * If users want to append a layer enforce that they
-                * have already specified a first layer before. It's
-                * better to be strict.
-                */
-               if (ctx->nr == 0) {
-                       pr_err("cannot append layer if no previous layer has been specified");
-                       return -EINVAL;
-               }
-
-               /*
-                * Once a sequence of data layers has started regular
-                * lower layers are forbidden.
-                */
-               if (ctx->nr_data > 0) {
-                       pr_err("regular lower layers cannot follow data lower layers");
-                       return -EINVAL;
-               }
-
-               /* Skip the leading ":". */
-               name++;
-               append = true;
+       if (*name == ':') {
+               pr_err("cannot append lower layer");
+               return -EINVAL;
        }
 
        dup = kstrdup(name, GFP_KERNEL);
@@ -472,7 +455,7 @@ static int ovl_parse_param_lowerdir(const char *name, struct fs_context *fc)
                l = &ctx->lower[nr];
                memset(l, 0, sizeof(*l));
 
-               err = ovl_mount_dir_noesc(dup_iter, &l->path);
+               err = ovl_mount_dir(dup_iter, &l->path, false);
                if (err)
                        goto out_put;
 
@@ -682,6 +665,7 @@ static int ovl_reconfigure(struct fs_context *fc)
 }
 
 static const struct fs_context_operations ovl_context_ops = {
+       .parse_monolithic = ovl_parse_monolithic,
        .parse_param = ovl_parse_param,
        .get_tree    = ovl_get_tree,
        .reconfigure = ovl_reconfigure,
@@ -752,12 +736,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 +749,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 +934,23 @@ 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];
-
-       /* ofs->layers[0] is the upper layer */
-       seq_printf(m, ",lowerdir=%s", ofs->layers[1].name);
-       /* dump regular lower layers */
-       for (nr = 2; nr < nr_merged_lower; nr++)
-               seq_printf(m, ":%s", ofs->layers[nr].name);
-       /* dump data lower layers */
-       for (nr = 0; nr < ofs->numdatalayer; nr++)
-               seq_printf(m, "::%s", data_layers[nr].name);
+
+       /*
+        * lowerdirs[] starts from offset 1, then
+        * >= 0 regular lower layers prefixed with : and
+        * >= 0 data-only lower layers prefixed with ::
+        *
+        * we need to escase comma and space like seq_show_option() does and
+        * we also need to escape the colon separator from lowerdir paths.
+        */
+       seq_puts(m, ",lowerdir=");
+       for (nr = 1; nr < ofs->numlayer; nr++) {
+               if (nr > 1)
+                       seq_putc(m, ':');
+               if (nr >= nr_merged_lower)
+                       seq_putc(m, ':');
+               seq_escape(m, ofs->config.lowerdirs[nr], ":, \t\n\\");
+       }
        if (ofs->config.upperdir) {
                seq_show_option(m, "upperdir", ofs->config.upperdir);
                seq_show_option(m, "workdir", ofs->config.workdir);
index def266b5e2a33b0aa630662286827227f952e513..3fa2416264a4e67b9bccd84700224ca6f484102f 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 6c1a9b1db9076c8c1402b7368a25ca7d9a894c70..139190165a1c2231ebb90fb364ee8bdb299b2b16 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 9dda7e54b2d0d98766b940701dd47a5034f2f463..9a8f32f21ff569d0dc40e1d7c31b63b9aea293bc 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 a8ac0dd8041ebca2178ab245c6337a3b9db2cbe6..7cebd397cc26e1056d3533643c98f87a2ae5fd79 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 9e72bfe8bbad9b7776d81f1949980013caea1fec..31e897ad5e6a79c3102d79dc1a4845725076319f 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);
                        /*
@@ -605,6 +601,15 @@ restart:
                         * 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 b81749492ef98e61bd22218c585864d9a9986953..7d12b8c5b2fa8c73929f7c9bd79d5085e7b1835f 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 b17f067e4ada0503e61550a16e6536c96055ed96..fe1bf5b6e0cb3dfe869f8942ca7b29f4865baab3 100644 (file)
@@ -15,6 +15,7 @@
 static struct cached_fid *init_cached_dir(const char *path);
 static void free_cached_dir(struct cached_fid *cfid);
 static void smb2_close_cached_fid(struct kref *ref);
+static void cfids_laundromat_worker(struct work_struct *work);
 
 static struct cached_fid *find_or_create_cached_dir(struct cached_fids *cfids,
                                                    const char *path,
@@ -169,15 +170,18 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
                return -ENOENT;
        }
        /*
-        * At this point we either have a lease already and we can just
-        * return it. If not we are guaranteed to be the only thread accessing
-        * this cfid.
+        * Return cached fid if it has a lease.  Otherwise, it is either a new
+        * entry or laundromat worker removed it from @cfids->entries.  Caller
+        * will put last reference if the latter.
         */
+       spin_lock(&cfids->cfid_list_lock);
        if (cfid->has_lease) {
+               spin_unlock(&cfids->cfid_list_lock);
                *ret_cfid = cfid;
                kfree(utf16_path);
                return 0;
        }
+       spin_unlock(&cfids->cfid_list_lock);
 
        /*
         * Skip any prefix paths in @path as lookup_positive_unlocked() ends up
@@ -294,9 +298,11 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
                        goto oshr_free;
                }
        }
+       spin_lock(&cfids->cfid_list_lock);
        cfid->dentry = dentry;
        cfid->time = jiffies;
        cfid->has_lease = true;
+       spin_unlock(&cfids->cfid_list_lock);
 
 oshr_free:
        kfree(utf16_path);
@@ -305,24 +311,28 @@ oshr_free:
        free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
        free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
        spin_lock(&cfids->cfid_list_lock);
-       if (rc && !cfid->has_lease) {
-               if (cfid->on_list) {
-                       list_del(&cfid->entry);
-                       cfid->on_list = false;
-                       cfids->num_entries--;
+       if (!cfid->has_lease) {
+               if (rc) {
+                       if (cfid->on_list) {
+                               list_del(&cfid->entry);
+                               cfid->on_list = false;
+                               cfids->num_entries--;
+                       }
+                       rc = -ENOENT;
+               } else {
+                       /*
+                        * We are guaranteed to have two references at this
+                        * point. One for the caller and one for a potential
+                        * lease. Release the Lease-ref so that the directory
+                        * will be closed when the caller closes the cached
+                        * handle.
+                        */
+                       spin_unlock(&cfids->cfid_list_lock);
+                       kref_put(&cfid->refcount, smb2_close_cached_fid);
+                       goto out;
                }
-               rc = -ENOENT;
        }
        spin_unlock(&cfids->cfid_list_lock);
-       if (!rc && !cfid->has_lease) {
-               /*
-                * We are guaranteed to have two references at this point.
-                * One for the caller and one for a potential lease.
-                * Release the Lease-ref so that the directory will be closed
-                * when the caller closes the cached handle.
-                */
-               kref_put(&cfid->refcount, smb2_close_cached_fid);
-       }
        if (rc) {
                if (cfid->is_open)
                        SMB2_close(0, cfid->tcon, cfid->fid.persistent_fid,
@@ -330,7 +340,7 @@ oshr_free:
                free_cached_dir(cfid);
                cfid = NULL;
        }
-
+out:
        if (rc == 0) {
                *ret_cfid = cfid;
                atomic_inc(&tcon->num_remote_opens);
@@ -452,6 +462,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);
@@ -569,53 +582,51 @@ static void free_cached_dir(struct cached_fid *cfid)
        kfree(cfid);
 }
 
-static int
-cifs_cfids_laundromat_thread(void *p)
+static void cfids_laundromat_worker(struct work_struct *work)
 {
-       struct cached_fids *cfids = p;
+       struct cached_fids *cfids;
        struct cached_fid *cfid, *q;
-       struct list_head entry;
+       LIST_HEAD(entry);
 
-       while (!kthread_should_stop()) {
-               ssleep(1);
-               INIT_LIST_HEAD(&entry);
-               if (kthread_should_stop())
-                       return 0;
-               spin_lock(&cfids->cfid_list_lock);
-               list_for_each_entry_safe(cfid, q, &cfids->entries, entry) {
-                       if (time_after(jiffies, cfid->time + HZ * dir_cache_timeout)) {
-                               list_del(&cfid->entry);
-                               list_add(&cfid->entry, &entry);
-                               cfids->num_entries--;
-                       }
-               }
-               spin_unlock(&cfids->cfid_list_lock);
+       cfids = container_of(work, struct cached_fids, laundromat_work.work);
 
-               list_for_each_entry_safe(cfid, q, &entry, entry) {
+       spin_lock(&cfids->cfid_list_lock);
+       list_for_each_entry_safe(cfid, q, &cfids->entries, entry) {
+               if (cfid->time &&
+                   time_after(jiffies, cfid->time + HZ * dir_cache_timeout)) {
                        cfid->on_list = false;
-                       list_del(&cfid->entry);
+                       list_move(&cfid->entry, &entry);
+                       cfids->num_entries--;
+                       /* To prevent race with smb2_cached_lease_break() */
+                       kref_get(&cfid->refcount);
+               }
+       }
+       spin_unlock(&cfids->cfid_list_lock);
+
+       list_for_each_entry_safe(cfid, q, &entry, entry) {
+               list_del(&cfid->entry);
+               /*
+                * Cancel and wait for the work to finish in case we are racing
+                * with it.
+                */
+               cancel_work_sync(&cfid->lease_break);
+               if (cfid->has_lease) {
                        /*
-                        * Cancel, and wait for the work to finish in
-                        * case we are racing with it.
+                        * Our lease has not yet been cancelled from the server
+                        * so we need to drop the reference.
                         */
-                       cancel_work_sync(&cfid->lease_break);
-                       if (cfid->has_lease) {
-                               /*
-                                * We lease has not yet been cancelled from
-                                * the server so we need to drop the reference.
-                                */
-                               spin_lock(&cfids->cfid_list_lock);
-                               cfid->has_lease = false;
-                               spin_unlock(&cfids->cfid_list_lock);
-                               kref_put(&cfid->refcount, smb2_close_cached_fid);
-                       }
+                       spin_lock(&cfids->cfid_list_lock);
+                       cfid->has_lease = false;
+                       spin_unlock(&cfids->cfid_list_lock);
+                       kref_put(&cfid->refcount, smb2_close_cached_fid);
                }
+               /* Drop the extra reference opened above */
+               kref_put(&cfid->refcount, smb2_close_cached_fid);
        }
-
-       return 0;
+       queue_delayed_work(cifsiod_wq, &cfids->laundromat_work,
+                          dir_cache_timeout * HZ);
 }
 
-
 struct cached_fids *init_cached_dirs(void)
 {
        struct cached_fids *cfids;
@@ -626,19 +637,10 @@ struct cached_fids *init_cached_dirs(void)
        spin_lock_init(&cfids->cfid_list_lock);
        INIT_LIST_HEAD(&cfids->entries);
 
-       /*
-        * since we're in a cifs function already, we know that
-        * this will succeed. No need for try_module_get().
-        */
-       __module_get(THIS_MODULE);
-       cfids->laundromat = kthread_run(cifs_cfids_laundromat_thread,
-                                 cfids, "cifsd-cfid-laundromat");
-       if (IS_ERR(cfids->laundromat)) {
-               cifs_dbg(VFS, "Failed to start cfids laundromat thread.\n");
-               kfree(cfids);
-               module_put(THIS_MODULE);
-               return NULL;
-       }
+       INIT_DELAYED_WORK(&cfids->laundromat_work, cfids_laundromat_worker);
+       queue_delayed_work(cifsiod_wq, &cfids->laundromat_work,
+                          dir_cache_timeout * HZ);
+
        return cfids;
 }
 
@@ -651,11 +653,10 @@ void free_cached_dirs(struct cached_fids *cfids)
        struct cached_fid *cfid, *q;
        LIST_HEAD(entry);
 
-       if (cfids->laundromat) {
-               kthread_stop(cfids->laundromat);
-               cfids->laundromat = NULL;
-               module_put(THIS_MODULE);
-       }
+       if (cfids == NULL)
+               return;
+
+       cancel_delayed_work_sync(&cfids->laundromat_work);
 
        spin_lock(&cfids->cfid_list_lock);
        list_for_each_entry_safe(cfid, q, &cfids->entries, entry) {
index a82ff2cea789c68b1ecdaf70dc489b593ed7227a..81ba0fd5cc16d6bd9bb782dc4a13f32a9b1322f5 100644 (file)
@@ -57,7 +57,7 @@ struct cached_fids {
        spinlock_t cfid_list_lock;
        int num_entries;
        struct list_head entries;
-       struct task_struct *laundromat;
+       struct delayed_work laundromat_work;
 };
 
 extern struct cached_fids *init_cached_dirs(void);
index 032d8716f6719cb0084d90aa9145b29c4a55cb03..02082621d8e07a8682095516d94f440728a74f76 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 7d8035846680ab224ee02300d4c0ed804a197d8c..0c37eefa18a57c0ed7be7921033ca86eda86c144 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 687754791bf0af496029bf7ba19d3cf7c46cdae7..7b923e36501b0bb09f7a1339004ab23f335510e0 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 e45ce31bbda7174c8754a89aed4dfe76d413b8b5..a3493da12ad1e6cbac7249f3e8464cf7eeff542e 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 366b755ca9130df5177bd92ea7d1f940c18cbf1f..35b176457bbed02d0df438e127dc2c0482e5143c 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 b41e2e872b22462f2d0ee6ee14ecab0a3959654a..0b89f7008ac0f429cc1a6b004c70117e19658837 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 194799ddd38288847dec2b2a1b65f604ec4be322..1a90dd78b238f0de191421bd0d1838164bff9778 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 44d4943e9c566fadec7f82faaace3c4f7ab3ac58..c75a80bb6d9eefa8a76e8c03baea7af8b7740c25 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 2a2aec8c61129b907acc7b1418e8207548e3716b..94df9eec3d8d1c240d6b4573c7fe1884ef99fdd4 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 a7e4755bed0fc240267f68f48a652ee7e9428083..de199ec9f7263daf369639d2bda1df453f225e59 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 d52057a511ee3062365c3b0632e33d908d44a643..14710afdc2a36cf3715e940a77d79b5f02f7c999 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 0d990c2f33cda76f6aeba475b5b8b9d02d6582d6..4b38c3a285f6028ea3bcdf9f7ecea957a1398e82 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 ab2583f030cebcc0cdc0069ed5aa6fe6f1ab5223..3c005246a32e8d2c38bde51b3ea8994e319c9c6b 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 408cddf2f094a87a0b5ffce7855b08acd886a68d..d2c81a8a11dda10ef710bc97e1c059073fddb700 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 562d647ad9fad46e49e6746f396bce223a73c742..6377a70b811c8993575d96889a8c2ef5f2fada2c 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 8a5dcab05614f196652999d33ed233ef3069ee8b..15f68ee0508946843983b7d773dc6837f12b3bf0 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 f99d475b28db45f96ae559c7368220a5dcd1a69e..63cb08fffde84c4a5f03b936577fe02288885b6e 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 5ab2f52f9b35573a8afc8c6ddf6c4dd2c10ad572..3079e607c5fe6db71e3cc70a76bcb26d90f813c3 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 e881df1d10cbd58ba1be08556a15c13c3d1a06db..23bd3d1209dfa53feb4f094989b2f9c5f3a67603 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 544022dd6d2007132a1bc3a310d4ee57f671a047..93262ca3f58a7706770f06e0387e01215a2336b9 100644 (file)
@@ -231,11 +231,12 @@ void set_smb2_rsp_status(struct ksmbd_work *work, __le32 err)
 {
        struct smb2_hdr *rsp_hdr;
 
-       if (work->next_smb2_rcv_hdr_off)
-               rsp_hdr = ksmbd_resp_buf_next(work);
-       else
-               rsp_hdr = smb2_get_msg(work->response_buf);
+       rsp_hdr = smb2_get_msg(work->response_buf);
        rsp_hdr->Status = err;
+
+       work->iov_idx = 0;
+       work->iov_cnt = 0;
+       work->next_smb2_rcv_hdr_off = 0;
        smb2_set_err_rsp(work);
 }
 
@@ -1993,6 +1994,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 +2126,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 +2191,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 +2223,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 +3405,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;
@@ -6115,12 +6152,12 @@ static noinline int smb2_read_pipe(struct ksmbd_work *work)
                memcpy(aux_payload_buf, rpc_resp->payload, rpc_resp->payload_sz);
 
                nbytes = rpc_resp->payload_sz;
-               kvfree(rpc_resp);
                err = ksmbd_iov_pin_rsp_read(work, (void *)rsp,
                                             offsetof(struct smb2_read_rsp, Buffer),
                                             aux_payload_buf, nbytes);
                if (err)
                        goto out;
+               kvfree(rpc_resp);
        } else {
                err = ksmbd_iov_pin_rsp(work, (void *)rsp,
                                        offsetof(struct smb2_read_rsp, Buffer));
@@ -7028,10 +7065,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 +7095,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 +7114,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 +8063,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 f41f8d6108ce92c07e870e9043f5bf9533117e4e..c91eac6514dd95e732e6cdc74ee9a5422dc06eec 100644 (file)
@@ -106,7 +106,7 @@ int ksmbd_query_inode_status(struct inode *inode)
        ci = __ksmbd_inode_lookup(inode);
        if (ci) {
                ret = KSMBD_INODE_STATUS_OK;
-               if (ci->m_flags & S_DEL_PENDING)
+               if (ci->m_flags & (S_DEL_PENDING | S_DEL_ON_CLS))
                        ret = KSMBD_INODE_STATUS_PENDING_DELETE;
                atomic_dec(&ci->m_count);
        }
@@ -116,7 +116,7 @@ int ksmbd_query_inode_status(struct inode *inode)
 
 bool ksmbd_inode_pending_delete(struct ksmbd_file *fp)
 {
-       return (fp->f_ci->m_flags & S_DEL_PENDING);
+       return (fp->f_ci->m_flags & (S_DEL_PENDING | S_DEL_ON_CLS));
 }
 
 void ksmbd_set_inode_pending_delete(struct ksmbd_file *fp)
@@ -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,17 @@ err_out:
        return ERR_PTR(ret);
 }
 
+void ksmbd_update_fstate(struct ksmbd_file_table *ft, struct ksmbd_file *fp,
+                        unsigned int state)
+{
+       if (!fp)
+               return;
+
+       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 fcb13413fa8d9366c12e5a0d506412d3e8159060..03d0bf941216f8f5157e1d9f1dca76897a3c51c3 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 6e60389d6a15ae56a21889b95ab656e48d5e9533..d43a5cc1bfa46b142197c991343a295d375af60f 100644 (file)
--- a/fs/stat.c
+++ b/fs/stat.c
 #include "internal.h"
 #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
@@ -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 9f64e73327968edc286eaaa847249a4115fa2d49..8c8d64e76103e130aeab0a8f913822abf1b0b5af 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 c9d653168ad03bbe95e9bc738523ec0ae6e676ac..ed0bc8cbc703d9c345f121f1226e13f419b511d4 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 e9cc481b4ddff17961e3a4fbb7db761a945d5079..f9f4d694640d043209c7de4feb06d6ede96174fb 100644 (file)
@@ -1001,6 +1001,12 @@ xfs_ag_shrink_space(
                error = -ENOSPC;
                goto resv_init_out;
        }
+
+       /* Update perag geometry */
+       pag->block_count -= delta;
+       __xfs_agino_range(pag->pag_mount, pag->block_count, &pag->agino_min,
+                               &pag->agino_max);
+
        xfs_ialloc_log_agi(*tpp, agibp, XFS_AGI_LENGTH);
        xfs_alloc_log_agf(*tpp, agfbp, XFS_AGF_LENGTH);
        return 0;
index 2420865f300719d8974c316934c4d4013c9f42d9..a5100a11faf9cd26943a21410f6f7c0d9fb34e96 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 5e174685a77c5ee4f52984e71530a585bf011aff..6264daaab37b06151bd12abc2ef9f41f61fcc675 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 ad22656376d3f88521f98c2c5d9f573e7cd2aeca..6b2296ff248a4385c737c943064c9234dfef402f 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 7d3aa14d81b55e9f0b867fb569da2ea11af61375..4849efcaa33aea500372195b1027976e6d2b0e58 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 aeb92624176b9d1636ce10f14790efc480544478..cd91db4a554896fdcdd61f4824ae4047cab93017 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 d98e8e77c684fa2bfca3232a60c115f905d8a6da..090c3ead43fdf1d244a053fb46a2831a8c39b9b6 100644 (file)
@@ -10,7 +10,6 @@
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
-#include "xfs_format.h"
 #include "scrub/xfile.h"
 #include "scrub/xfarray.h"
 #include "scrub/scrub.h"
index 5db87b34fb6e2067442e50d7e586605978e27b0a..89c7a9f4f93054d20b3504a8192fe16deee0dbda 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 2788a6f2edcdb82b1765af1a7a939ac2420e8c71..36fe2abb16e6e35563a0f7d5ca8ed895c4ff2130 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 7551c3ec4ea5d68eaba0d233ac7c4446d02614b8..e736a0844c89d655e717fec39f96b939e764dc73 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 afc4c78b9eed648ccfcb0611a3657eaca083f886..d5787991bb5b46477419074e1015ba1135945c7b 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 de92d9cc958ff353b2e5304025c98a0e614e4127..2b1a85223a56c6d37e9711c1025ce63bdb6b048d 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 1064c2342876807837bf400a87ac9d296bfec9fa..7cd09c3a82cb5013ced681bc389266d21da90a60 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 7c2fdc71e42d448ee87938270232bfbdc1377734..9ecfdcdc752f799a8dfe7a4bdede0ad39b127f4e 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,33 @@ 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);
+       /* always process discard lists in fifo order */
+       list_add_tail(&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 c37bf87e6781b6aa09b794627a4d5b9cf30ed760..0639aab336f3f71c129713f3710e05115b7d38c3 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,10 +28,31 @@ 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 f1a5ecf099aabf6779a69a85a64b34207c2c8781..3fa8789820ad9d4e5014aa4e00b1e4c3dc3ee874 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 10403ba9b58f7d31d42ee2f0a80993f692557beb..736e5545f584025ec204dfc6059e83fc06e99bdb 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 e541f5c0bc251c4a1e2d74b3094e32f30b6ccd94..3c210ac8371368bc00a77fb9df52315b710d17ce 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);
@@ -2093,47 +2112,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 2fa6f2e09d078a2a884bf1bc88bec960eeea92aa..905944dafbe539245bc30fe2df2d8681af0c5a04 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 360fe83a334fc5dcf061d22628bee58d0baa3619..4d55f58d99b7ac0333b725fa7baf6f1f62b7fc98 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 7547caf2f2abd525010aa046d8b1e93e29d599dd..0c5bdb91152e1cf920cfb5cb76268d0b025640fc 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 2ededd3f6b8ce861489a54038fa4d700637c845c..2b3b05c28e9e48bd6ea70819c33d4c59c3490b06 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;
@@ -584,6 +584,11 @@ xfs_vn_getattr(
                }
        }
 
+       if ((request_mask & STATX_CHANGE_COOKIE) && IS_I_VERSION(inode)) {
+               stat->change_cookie = inode_query_iversion(inode);
+               stat->result_mask |= STATX_CHANGE_COOKIE;
+       }
+
        /*
         * Note: If you add another clause to set an attribute flag, please
         * update attributes_mask below.
@@ -917,7 +922,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 c2093cb56092bedb2058e3fdd9df13cbd099068b..f5377ba5967a7a30398b893dec0424c1caa96a2e 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 79004d193e54dc2b06c796cef994d0bb1ba786eb..51c100c861770f619776a8e3efb921d0b2e55bd8 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)) {
@@ -780,12 +771,6 @@ xfs_log_mount_finish(
                return 0;
        }
 
-       /*
-        * 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.
@@ -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 eccbfb99e89486cca1f1f185d2875d9421d44764..67a99d94701e5b08da7849ddc29a361a71e12f12 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
@@ -1790,38 +1735,6 @@ out_shutdown:
        return 0;
 }
 
-/*
- * 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.
  */
index 1bd2963e8fbd10c0adcc02887382030e79ff37ae..fa3ad1d7b31c85b1196fc1b93ee416f21ab5e98b 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 82c81d20459d147ce6f18574037b2850863d0176..13b94d2e605bd9ddb852f76eeeea0bd956a595e0 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 a25eece3be2b9b53c1370c112957011046310d7a..d19cca099bc3a701786c3e5e9871f086ac3f290c 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 4a9bbd3fe12011a7f0a2e9f80765ea4010c6e509..a7daa522e00fe758039b0811bfc9568b28dd1466 100644 (file)
@@ -126,8 +126,8 @@ xfs_dax_notify_ddev_failure(
                struct xfs_rmap_irec    ri_low = { };
                struct xfs_rmap_irec    ri_high;
                struct xfs_agf          *agf;
-               xfs_agblock_t           agend;
                struct xfs_perag        *pag;
+               xfs_agblock_t           range_agend;
 
                pag = xfs_perag_get(mp, agno);
                error = xfs_alloc_read_agf(pag, tp, 0, &agf_bp);
@@ -148,10 +148,10 @@ xfs_dax_notify_ddev_failure(
                        ri_high.rm_startblock = XFS_FSB_TO_AGBNO(mp, end_fsbno);
 
                agf = agf_bp->b_addr;
-               agend = min(be32_to_cpu(agf->agf_length),
+               range_agend = min(be32_to_cpu(agf->agf_length) - 1,
                                ri_high.rm_startblock);
                notify.startblock = ri_low.rm_startblock;
-               notify.blockcount = agend - ri_low.rm_startblock;
+               notify.blockcount = range_agend + 1 - ri_low.rm_startblock;
 
                error = xfs_rmap_query_range(cur, &ri_low, &ri_high,
                                xfs_dax_failure_fn, &notify);
index 6abcc34fafd8c2e807784908be3004c7e58ffda4..086e78a6143aa151c706eeaaf394fb7844875059 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 edd8587658d5577a6c7a8d37a292808ebac94b55..2d4444d61e98766e0b49f1187634b470f66334c9 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 520c7ebdfed8d1ab2b1b91a5e45dba19b2ac4907..0e0e747028da2e8638114b3268ee87490eed5f97 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 1f77014c6e1abd136753807d37ac5cdf12099b76..819a3568b28f46fa9036d888ca0b8284d5f8fed0 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 902c7f67a117f4831016d093773d73e5297e9a98..3926cf7f2a6ed189ccbf2d76f7b8e02db9e02294 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 43e5c219aaed568ffb5a711b4583b2cdf1723d9c..a3975f325f4ea83dde12540f7d854ab384d4fd4c 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 94181fe9780a5e899fe977226f5938a9ef8de470..3f34ebb275253e281fbecaad602a0531b1e6e55d 100644 (file)
@@ -465,9 +465,4 @@ extern int acpi_processor_ffh_lpi_probe(unsigned int cpu);
 extern int acpi_processor_ffh_lpi_enter(struct acpi_lpi_state *lpi);
 #endif
 
-#ifdef CONFIG_ACPI_HOTPLUG_CPU
-extern int arch_register_cpu(int cpu);
-extern void arch_unregister_cpu(int cpu);
-#endif
-
 #endif
index 4da02798a00bb6cbc8d5491ce89e72eb22616788..6dcf4d576970c4b43ce8be9e0373bc39d10e3518 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 cecd2b7bd033e92335e1904d449beedd3e9bb3c0..430f0ae0dde2d0046dd37067ed4403c213a2029a 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 9c59409104f69830fe229ef8c32df24cb9c03e07..67d8dd2f1bdec12a0d4a919641d9397aebcf85d3 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 f9544d9b670d33aee0114b85d5946684128d8175..ac65f0626cfc9153d2711ed5959b2e8c84229e08 100644 (file)
@@ -68,8 +68,7 @@ enum drm_sched_priority {
        DRM_SCHED_PRIORITY_HIGH,
        DRM_SCHED_PRIORITY_KERNEL,
 
-       DRM_SCHED_PRIORITY_COUNT,
-       DRM_SCHED_PRIORITY_UNSET = -2
+       DRM_SCHED_PRIORITY_COUNT
 };
 
 /* Used to chose between FIFO and RR jobs scheduling */
index bb3cb005873ec9828b1ece587755cb8a9fc9b5ed..e748bc957d83262233b3c8a655ed68b0ad8f34dd 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 a73246c3c35e083541b2e33638c575b6910497ba..afd94c9b8b8afd100c54fb07b5f1e8dcce08e92c 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 2dd175f5debd080f4cc20f7090b2ad57ce03df33..29cc10220952dbe05497875b64cd19f00a81362b 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 18f5744dfb5d89f09ff3191bdfc517a0839580d6..b83ef19da13de210e3ae8ce42f8dc022b51d8ef1 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 024e8b28c34b813296d6fd015bc0047702258193..49f8b691496c4563b9cf4a9dc51b2b9c8133487d 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 a3462a9b8e18547d521d9dc318074f6a69afe5ed..a9cb10b0e2e9bf45c33f4ad39e7a95d8d9b6b1b5 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 5f2301ee88bcccf85a057273b45267690f4031f1..f3b3593254b975004409b9dec8a8c88eec8bb0b0 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 f1b3151ac30bf0e13b1762f3730695e726237c82..265da00a1a8b1b34c2405a6ae1e31d18cadb389f 100644 (file)
@@ -238,7 +238,7 @@ struct css_set {
         * Lists running through all tasks using this cgroup group.
         * mg_tasks lists tasks which belong to this cset but are in the
         * process of being migrated out or in.  Protected by
-        * css_set_rwsem, but, during migration, once tasks are moved to
+        * css_set_lock, but, during migration, once tasks are moved to
         * mg_tasks, it can be read safely while holding cgroup_mutex.
         */
        struct list_head tasks;
index 0abd60a7987b6803db3e02c5571cf4a2f6c94b88..eb768a866fe31ea47449da87bcc5c8992a062d4f 100644 (file)
@@ -80,6 +80,8 @@ extern __printf(4, 5)
 struct device *cpu_device_create(struct device *parent, void *drvdata,
                                 const struct attribute_group **groups,
                                 const char *fmt, ...);
+extern int arch_register_cpu(int cpu);
+extern void arch_unregister_cpu(int cpu);
 #ifdef CONFIG_HOTPLUG_CPU
 extern void unregister_cpu(struct cpu *cpu);
 extern ssize_t arch_cpu_probe(const char *, size_t);
index 06dda85f042445bb0d4b017b7e2aecd5b0587651..068f7738be22ab17b9958d01d46f92bec0d903f7 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 0d678e9a7b2482fe05fb884f0694347dead82897..ebe78bd3d121dd82e795824b6a9e00b770049e77 100644 (file)
@@ -568,6 +568,25 @@ static inline void dma_fence_set_error(struct dma_fence *fence,
        fence->error = error;
 }
 
+/**
+ * dma_fence_timestamp - helper to get the completion timestamp of a fence
+ * @fence: fence to get the timestamp from.
+ *
+ * After a fence is signaled the timestamp is updated with the signaling time,
+ * but setting the timestamp can race with tasks waiting for the signaling. This
+ * helper busy waits for the correct timestamp to appear.
+ */
+static inline ktime_t dma_fence_timestamp(struct dma_fence *fence)
+{
+       if (WARN_ON(!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)))
+               return ktime_get();
+
+       while (!test_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags))
+               cpu_relax();
+
+       return fence->timestamp;
+}
+
 signed long dma_fence_wait_timeout(struct dma_fence *,
                                   bool intr, signed long timeout);
 signed long dma_fence_wait_any_timeout(struct dma_fence **fences,
index 4aeb3fa1192771cdd8e1e1ebdf18f9b08c983166..4a40823c3c6784f19bc98911cd1557736eafba7a 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));
@@ -2444,7 +2403,7 @@ struct audit_names;
 struct filename {
        const char              *name;  /* pointer to actual string */
        const __user char       *uptr;  /* original userland pointer */
-       int                     refcnt;
+       atomic_t                refcnt;
        struct audit_names      *aname;
        const char              iname[];
 };
@@ -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 96332db693d5e023e3cbf4974f75f4bfa5da6daa..c13e99cbbf8162bb395a48f3709cbd69ac009e7d 100644 (file)
@@ -136,6 +136,8 @@ extern struct fs_context *vfs_dup_fs_context(struct fs_context *fc);
 extern int vfs_parse_fs_param(struct fs_context *fc, struct fs_parameter *param);
 extern int vfs_parse_fs_string(struct fs_context *fc, const char *key,
                               const char *value, size_t v_size);
+int vfs_parse_monolithic_sep(struct fs_context *fc, void *data,
+                            char *(*sep)(char **));
 extern int generic_parse_monolithic(struct fs_context *fc, void *data);
 extern int vfs_get_tree(struct fs_context *fc);
 extern void put_fs_context(struct fs_context *fc);
index 5b2626063f4fddd521c831eb17c1aae8a0e9d41e..47d25a5e1933d05a1921613ae63e213d990c0249 100644 (file)
@@ -60,6 +60,7 @@ struct resv_map {
        long adds_in_progress;
        struct list_head region_cache;
        long region_cache_count;
+       struct rw_semaphore rw_sema;
 #ifdef CONFIG_CGROUP_HUGETLB
        /*
         * On private mappings, the counter to uncharge reservations is stored
@@ -138,7 +139,7 @@ struct page *hugetlb_follow_page_mask(struct vm_area_struct *vma,
 void unmap_hugepage_range(struct vm_area_struct *,
                          unsigned long, unsigned long, struct page *,
                          zap_flags_t);
-void __unmap_hugepage_range_final(struct mmu_gather *tlb,
+void __unmap_hugepage_range(struct mmu_gather *tlb,
                          struct vm_area_struct *vma,
                          unsigned long start, unsigned long end,
                          struct page *ref_page, zap_flags_t zap_flags);
@@ -245,6 +246,25 @@ int huge_pmd_unshare(struct mm_struct *mm, struct vm_area_struct *vma,
 void adjust_range_if_pmd_sharing_possible(struct vm_area_struct *vma,
                                unsigned long *start, unsigned long *end);
 
+extern void __hugetlb_zap_begin(struct vm_area_struct *vma,
+                               unsigned long *begin, unsigned long *end);
+extern void __hugetlb_zap_end(struct vm_area_struct *vma,
+                             struct zap_details *details);
+
+static inline void hugetlb_zap_begin(struct vm_area_struct *vma,
+                                    unsigned long *start, unsigned long *end)
+{
+       if (is_vm_hugetlb_page(vma))
+               __hugetlb_zap_begin(vma, start, end);
+}
+
+static inline void hugetlb_zap_end(struct vm_area_struct *vma,
+                                  struct zap_details *details)
+{
+       if (is_vm_hugetlb_page(vma))
+               __hugetlb_zap_end(vma, details);
+}
+
 void hugetlb_vma_lock_read(struct vm_area_struct *vma);
 void hugetlb_vma_unlock_read(struct vm_area_struct *vma);
 void hugetlb_vma_lock_write(struct vm_area_struct *vma);
@@ -296,6 +316,18 @@ static inline void adjust_range_if_pmd_sharing_possible(
 {
 }
 
+static inline void hugetlb_zap_begin(
+                               struct vm_area_struct *vma,
+                               unsigned long *start, unsigned long *end)
+{
+}
+
+static inline void hugetlb_zap_end(
+                               struct vm_area_struct *vma,
+                               struct zap_details *details)
+{
+}
+
 static inline struct page *hugetlb_follow_page_mask(
     struct vm_area_struct *vma, unsigned long address, unsigned int flags,
     unsigned int *page_mask)
@@ -441,7 +473,7 @@ static inline long hugetlb_change_protection(
        return 0;
 }
 
-static inline void __unmap_hugepage_range_final(struct mmu_gather *tlb,
+static inline void __unmap_hugepage_range(struct mmu_gather *tlb,
                        struct vm_area_struct *vma, unsigned long start,
                        unsigned long end, struct page *ref_page,
                        zap_flags_t zap_flags)
@@ -984,7 +1016,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 +1207,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)
 {
 }
 
@@ -1231,6 +1265,11 @@ static inline bool __vma_shareable_lock(struct vm_area_struct *vma)
        return (vma->vm_flags & VM_MAYSHARE) && vma->vm_private_data;
 }
 
+static inline bool __vma_private_lock(struct vm_area_struct *vma)
+{
+       return (!(vma->vm_flags & VM_MAYSHARE)) && vma->vm_private_data;
+}
+
 /*
  * Safe version of huge_pte_offset() to check the locks.  See comments
  * above huge_pte_offset().
index bd2f6e19c357a8185eddecff59d393e8554f1eba..b24fb80782c5a10d3af761403324c36bf5d3d452 100644 (file)
@@ -4355,6 +4355,35 @@ static inline bool ieee80211_is_public_action(struct ieee80211_hdr *hdr,
        return mgmt->u.action.category == WLAN_CATEGORY_PUBLIC;
 }
 
+/**
+ * ieee80211_is_protected_dual_of_public_action - check if skb contains a
+ * protected dual of public action management frame
+ * @skb: the skb containing the frame, length will be checked
+ *
+ * Return: true if the skb contains a protected dual of public action
+ * management frame, false otherwise.
+ */
+static inline bool
+ieee80211_is_protected_dual_of_public_action(struct sk_buff *skb)
+{
+       u8 action;
+
+       if (!ieee80211_is_public_action((void *)skb->data, skb->len) ||
+           skb->len < IEEE80211_MIN_ACTION_SIZE + 1)
+               return false;
+
+       action = *(u8 *)(skb->data + IEEE80211_MIN_ACTION_SIZE);
+
+       return action != WLAN_PUB_ACTION_20_40_BSS_COEX &&
+               action != WLAN_PUB_ACTION_DSE_REG_LOC_ANN &&
+               action != WLAN_PUB_ACTION_MSMT_PILOT &&
+               action != WLAN_PUB_ACTION_TDLS_DISCOVER_RES &&
+               action != WLAN_PUB_ACTION_LOC_TRACK_NOTI &&
+               action != WLAN_PUB_ACTION_FTM_REQUEST &&
+               action != WLAN_PUB_ACTION_FTM_RESPONSE &&
+               action != WLAN_PUB_ACTION_FILS_DISCOVERY;
+}
+
 /**
  * _ieee80211_is_group_privacy_action - check if frame is a group addressed
  * privacy action frame
index 1b9b15a492fae417f87b946fe343f7ee29ec890b..cdc684e04a2fb6fcabda07a3427270af79b7eca8 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 a92bce40b04b3a0352534f76334faec42d85fbb1..4a1dc88ddbff9a6bfec51b1b62f3cd2cc3758463 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 3df5499f79369df25448c3069f00888d0cbb31f2..71fa9a40fb5a95ac3124c1af50cbdd0d7013c81a 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)
@@ -466,10 +466,10 @@ static inline void kasan_free_module_shadow(const struct vm_struct *vm) {}
 
 #endif /* (CONFIG_KASAN_GENERIC || CONFIG_KASAN_SW_TAGS) && !CONFIG_KASAN_VMALLOC */
 
-#ifdef CONFIG_KASAN_INLINE
+#if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS)
 void kasan_non_canonical_hook(unsigned long addr);
-#else /* CONFIG_KASAN_INLINE */
+#else /* CONFIG_KASAN_GENERIC || CONFIG_KASAN_SW_TAGS */
 static inline void kasan_non_canonical_hook(unsigned long addr) { }
-#endif /* CONFIG_KASAN_INLINE */
+#endif /* CONFIG_KASAN_GENERIC || CONFIG_KASAN_SW_TAGS */
 
 #endif /* LINUX_KASAN_H */
index bf4913f4d7ac1710c258b61e0e2f9ef201a24c04..2a7d2af0ed80a860717a27303e7da6b8ade51e3d 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 e41c70ac7744e4310b2e69259c700b8c1be22493..d01e850b570fd41a42f1d778c2242bb3dc58db6a 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 1e5893138afe02435256b7f1dd945b2b5cd0debd..0b971b24a804b2722fa8f48e105efce3c52134e2 100644 (file)
@@ -63,7 +63,6 @@ static inline struct mcb_bus *to_mcb_bus(struct device *dev)
 struct mcb_device {
        struct device dev;
        struct mcb_bus *bus;
-       bool is_added;
        struct mcb_driver *driver;
        u16 id;
        int inst;
index ab94ad4597d07373b813f110092ebaa3cf5527c5..e4e24da16d2c398493e197cfb97f25be9940e3d0 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 0b6b59f7cfbdcd46826b33a2c23f518ab1755f52..56047a4e54c9c21350ca2e0d74705e369acc0189 100644 (file)
@@ -21,6 +21,9 @@ struct jedec_ecc_info {
 /* JEDEC features */
 #define JEDEC_FEATURE_16_BIT_BUS       (1 << 0)
 
+/* JEDEC Optional Commands */
+#define JEDEC_OPT_CMD_READ_CACHE       BIT(1)
+
 struct nand_jedec_params {
        /* rev info and features block */
        /* 'J' 'E' 'S' 'D'  */
index a7376f9beddfd6de749f25583196548fda718f35..55ab2e4d62f9476c427bdf68412c0a3102d4bbe2 100644 (file)
@@ -55,6 +55,7 @@
 #define ONFI_SUBFEATURE_PARAM_LEN      4
 
 /* ONFI optional commands SET/GET FEATURES supported? */
+#define ONFI_OPT_CMD_READ_CACHE                BIT(1)
 #define ONFI_OPT_CMD_SET_GET_FEATURES  BIT(2)
 
 struct nand_onfi_params {
index 90a141ba2a5acc18eb347baeb31dd8dc52d24f19..c29ace15a053a69a13e2d97ef9f30debe3d3f830 100644 (file)
@@ -225,6 +225,7 @@ struct gpio_desc;
  * struct nand_parameters - NAND generic parameters from the parameter page
  * @model: Model name
  * @supports_set_get_features: The NAND chip supports setting/getting features
+ * @supports_read_cache: The NAND chip supports read cache operations
  * @set_feature_list: Bitmap of features that can be set
  * @get_feature_list: Bitmap of features that can be get
  * @onfi: ONFI specific parameters
@@ -233,6 +234,7 @@ struct nand_parameters {
        /* Generic parameters */
        const char *model;
        bool supports_set_get_features;
+       bool supports_read_cache;
        DECLARE_BITMAP(set_feature_list, ONFI_FEATURE_NUMBER);
        DECLARE_BITMAP(get_feature_list, ONFI_FEATURE_NUMBER);
 
index 625f491b95de87904892dc52e6e5bf5bba8a57fa..fb31312825ae530f95577f3866e8fbd235dadd2a 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 20eeba8b009df1100a3c6080f84c93277aaba4dc..cd628c4b011e54fa807674daa8a3361c97c20a5f 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 aa9f4c6ebe261d40fc3dc21389a97458e1722178..1c315f854ea8013bef87fb820dd0186aefb4a3cf 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 e85cd1c0eaf355ebb85c0b7c48b803283d91544e..7b5406e3288d98cdf42d1d5f10afef0928b73a4f 100644 (file)
@@ -704,6 +704,7 @@ struct perf_event {
        /* The cumulative AND of all event_caps for events in this group. */
        int                             group_caps;
 
+       unsigned int                    group_generation;
        struct perf_event               *group_leader;
        /*
         * event->pmu will always point to pmu in which this event belongs.
index 1fba072b3dac3dd613270fc8ec86922e2a3f4627..af7639c3b0a3a4919c60b70d496519407734ad11 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 fd692b4a41d5fbe0dae06b46da3ebc47c4747b2e..07071e64abf3d66298680b829a2d3b251ebbde5d 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 11a4becff3a983247a8653f3f68fe000739f026f..4fa4ef0a173a360ae236bcd967666936933fec7c 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 28518945444968fed623838f4028dca96736a9f7..f8f3e958e9cf2fbf0777fdbf5e3fd993c889cee3 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 987a59d977c566ae5eb0f306e4ed79f4e5428204..e9bd2f65d7f4e40d10cfe11b4fe5d433be4273db 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 4174c4b82d13b90198d155acdf3a3a455b759c9c..97bfef071255f333051dd196578691d5708b3ee0 100644 (file)
@@ -1309,7 +1309,7 @@ struct sk_buff_fclones {
  *
  * Returns true if skb is a fast clone, and its clone is not freed.
  * Some drivers call skb_orphan() in their ndo_start_xmit(),
- * so we also check that this didnt happen.
+ * so we also check that didn't happen.
  */
 static inline bool skb_fclone_busy(const struct sock *sk,
                                   const struct sk_buff *skb)
@@ -2016,7 +2016,7 @@ static inline struct sk_buff *skb_share_check(struct sk_buff *skb, gfp_t pri)
  *     Copy shared buffers into a new sk_buff. We effectively do COW on
  *     packets to handle cases where we have a local reader and forward
  *     and a couple of other messy ones. The normal one is tcpdumping
- *     a packet thats being forwarded.
+ *     a packet that's being forwarded.
  */
 
 /**
index 5b4fb3c791bc267042a9af1b7384e606ae0b043f..2f8dc47f1eb07504903318682a58ec8735ac4c5d 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 b4536626f8ff35c018a8f8dada7010c7f11f0c26..ecde0312dd5203a125e21846235ab5b1acae6cb7 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 7b4dd69555e497497460dcf5d72737fe5c09fd53..27cc1d4643219a44c01a2404124cd45ef46f7f3d 100644 (file)
@@ -3,8 +3,8 @@
 #define _LINUX_VIRTIO_NET_H
 
 #include <linux/if_vlan.h>
+#include <linux/udp.h>
 #include <uapi/linux/tcp.h>
-#include <uapi/linux/udp.h>
 #include <uapi/linux/virtio_net.h>
 
 static inline bool virtio_net_hdr_match_proto(__be16 protocol, __u8 gso_type)
@@ -151,9 +151,22 @@ retry:
                unsigned int nh_off = p_off;
                struct skb_shared_info *shinfo = skb_shinfo(skb);
 
-               /* UFO may not include transport header in gso_size. */
-               if (gso_type & SKB_GSO_UDP)
+               switch (gso_type & ~SKB_GSO_TCP_ECN) {
+               case SKB_GSO_UDP:
+                       /* UFO may not include transport header in gso_size. */
                        nh_off -= thlen;
+                       break;
+               case SKB_GSO_UDP_L4:
+                       if (!(hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM))
+                               return -EINVAL;
+                       if (skb->csum_offset != offsetof(struct udphdr, check))
+                               return -EINVAL;
+                       if (skb->len - p_off > gso_size * UDP_MAX_SEGMENTS)
+                               return -EINVAL;
+                       if (gso_type != SKB_GSO_UDP_L4)
+                               return -EINVAL;
+                       break;
+               }
 
                /* Kernel has a special handling for GSO_BY_FRAGS. */
                if (gso_size == GSO_BY_FRAGS)
index e6359f7346f1fb4a2703e3de6bae8db475972cdb..c33348ba1657e34e888119cc78ec1d245f4539f2 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 2d5fcda1bcd057d776457067941a09ba25ed8d34..082f89531b8896e8fdcc618d9b63e2ab5d062c41 100644 (file)
@@ -56,7 +56,7 @@ struct hci_mon_new_index {
        __u8            type;
        __u8            bus;
        bdaddr_t        bdaddr;
-       char            name[8];
+       char            name[8] __nonstring;
 } __packed;
 #define HCI_MON_NEW_INDEX_SIZE 16
 
index 3a4b684f89bf78d1d2464bfe293612533c000be1..7192346e4a22dfd1f9f2a6c6067e92f4167b55ad 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 f0c13864180e23e43fe065494fe4e42114c6ecd1..15de07d36540526fd4ede91f77af17eaf9ea1a45 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 75a6f4863c837a5ba825466e477432854af865e7..ebf9bc54036a5f2a24828ce0959b92c3be17a178 100644 (file)
@@ -258,6 +258,7 @@ struct macsec_context {
        struct macsec_secy *secy;
        struct macsec_rx_sc *rx_sc;
        struct {
+               bool update_pn;
                unsigned char assoc_num;
                u8 key[MACSEC_MAX_KEY_LEN];
                union {
index 9f70b43322383a1c3c980ec84b23e919903a7de1..4d43adf186064c4de216d6f83bdf4916a7b07877 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 6da68886fabbcb33a63ef256242d51a618571c95..07022bb0d44d4b5eef5812cc86e042833cf3a337 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 d466e1a3b0b1984c96439a31cbd0b5ff3a415740..fe1507c1db828b14e6d684f1f1bca514dbb4103d 100644 (file)
@@ -53,6 +53,7 @@ struct nf_flowtable_type {
        struct list_head                list;
        int                             family;
        int                             (*init)(struct nf_flowtable *ft);
+       bool                            (*gc)(const struct flow_offload *flow);
        int                             (*setup)(struct nf_flowtable *ft,
                                                 struct net_device *dev,
                                                 enum flow_block_command cmd);
index dd40c75011d25fdf8ce2360c9b291ebc4ee6104b..7c816359d5a98884cf303b87af1bb2adbb1b48e2 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 bd7c3be4af5d7bee4c63a57a2b0bf283b81bc4bf..423b52eca908d90009889b64764fbd4008a29529 100644 (file)
@@ -50,6 +50,7 @@ struct netns_xfrm {
        struct list_head        policy_all;
        struct hlist_head       *policy_byidx;
        unsigned int            policy_idx_hmask;
+       unsigned int            idx_generator;
        struct hlist_head       policy_inexact[XFRM_POLICY_MAX];
        struct xfrm_policy_hash policy_bydst[XFRM_POLICY_MAX];
        unsigned int            policy_count[XFRM_POLICY_MAX * 2];
index 94231533a3696849ec52210269086155dc68dc25..8e7751464ff59596e89f5c0d803c699ced9afa24 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 b770261fbdaf59d4d1c0b30adb2592c56442e9e3..92f7ea62a9159c8d9c37d86422d883d8680fdb6f 100644 (file)
@@ -336,7 +336,7 @@ struct sk_filter;
   *    @sk_cgrp_data: cgroup data for this cgroup
   *    @sk_memcg: this socket's memory cgroup association
   *    @sk_write_pending: a write to stream socket waits to start
-  *    @sk_wait_pending: number of threads blocked on this socket
+  *    @sk_disconnects: number of disconnect operations performed on this sock
   *    @sk_state_change: callback to indicate change in the state of the sock
   *    @sk_data_ready: callback to indicate there is data to be processed
   *    @sk_write_space: callback to indicate there is bf sending space available
@@ -429,7 +429,7 @@ struct sock {
        unsigned int            sk_napi_id;
 #endif
        int                     sk_rcvbuf;
-       int                     sk_wait_pending;
+       int                     sk_disconnects;
 
        struct sk_filter __rcu  *sk_filter;
        union {
@@ -1189,8 +1189,7 @@ static inline void sock_rps_reset_rxhash(struct sock *sk)
 }
 
 #define sk_wait_event(__sk, __timeo, __condition, __wait)              \
-       ({      int __rc;                                               \
-               __sk->sk_wait_pending++;                                \
+       ({      int __rc, __dis = __sk->sk_disconnects;                 \
                release_sock(__sk);                                     \
                __rc = __condition;                                     \
                if (!__rc) {                                            \
@@ -1200,8 +1199,7 @@ static inline void sock_rps_reset_rxhash(struct sock *sk)
                }                                                       \
                sched_annotate_sleep();                                 \
                lock_sock(__sk);                                        \
-               __sk->sk_wait_pending--;                                \
-               __rc = __condition;                                     \
+               __rc = __dis == __sk->sk_disconnects ? __condition : -EPIPE; \
                __rc;                                                   \
        })
 
index 91688d0dadcd6f72144aac747178de8d85f15bf7..4b03ca7cb8a5eb479290db2834e7cc806050cb0a 100644 (file)
@@ -141,6 +141,9 @@ void tcp_time_wait(struct sock *sk, int state, int timeo);
 #define TCP_RTO_MAX    ((unsigned)(120*HZ))
 #define TCP_RTO_MIN    ((unsigned)(HZ/5))
 #define TCP_TIMEOUT_MIN        (2U) /* Min timeout for TCP timers in jiffies */
+
+#define TCP_TIMEOUT_MIN_US (2*USEC_PER_MSEC) /* Min TCP timeout in microsecs */
+
 #define TCP_TIMEOUT_INIT ((unsigned)(1*HZ))    /* RFC6298 2.1 initial RTO value        */
 #define TCP_TIMEOUT_FALLBACK ((unsigned)(3*HZ))        /* RFC 1122 initial RTO value, now
                                                 * used as a fallback RTO for the
@@ -348,12 +351,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 ec093594ba53df4e8328a821c5e92f6f88c5a9c0..4498f845b1122185017a83a5c75fd07ad4ef5566 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 b9230b6add041dbba870995974bffd4dc31f728b..65e49fae8da7a0ca8e354c3a7dfc6a2aaf1c0439 100644 (file)
@@ -161,6 +161,26 @@ struct scsi_device {
                                 * pass settings from slave_alloc to scsi
                                 * core. */
        unsigned int eh_timeout; /* Error handling timeout */
+
+       /*
+        * If true, let the high-level device driver (sd) manage the device
+        * power state for system suspend/resume (suspend to RAM and
+        * hibernation) operations.
+        */
+       bool manage_system_start_stop;
+
+       /*
+        * If true, let the high-level device driver (sd) manage the device
+        * power state for runtime device suspand and resume operations.
+        */
+       bool manage_runtime_start_stop;
+
+       /*
+        * If true, let the high-level device driver (sd) manage the device
+        * power state for system shutdown (power off) operations.
+        */
+       bool manage_shutdown;
+
        unsigned removable:1;
        unsigned changed:1;     /* Data invalid due to media change */
        unsigned busy:1;        /* Used to prevent races */
@@ -193,7 +213,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 49f768d0ff370b3f7aa67666b1f75444e55f1ee3..4c2dc8150c6d71c4c83c1cb3894ffdaf69ff75e7 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 d2faec9a323ea3e87c99fc04dcdfd93c59c5d8fc..433543eb82b916dc3620b701813533338590def2 100644 (file)
@@ -469,6 +469,7 @@ void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card);
 
 int snd_soc_dapm_update_dai(struct snd_pcm_substream *substream,
                            struct snd_pcm_hw_params *params, struct snd_soc_dai *dai);
+int snd_soc_dapm_widget_name_cmp(struct snd_soc_dapm_widget *widget, const char *s);
 
 /* dapm path setup */
 int snd_soc_dapm_new_widgets(struct snd_soc_card *card);
index fa2337a3cf4c775b566e1d133844b5dcefb1516a..37f9d3fe302a60460852f19a5b5e303fb5108c47 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 5eaa1fa9917153f6038d82ce5474d1f9acc6a0fa..833143d0992e063bc80e06ac3b0e94fdd263460b 100644 (file)
@@ -39,7 +39,6 @@ TRACE_EVENT(neigh_create,
        ),
 
        TP_fast_assign(
-               struct in6_addr *pin6;
                __be32 *p32;
 
                __entry->family = tbl->family;
@@ -47,7 +46,6 @@ TRACE_EVENT(neigh_create,
                __entry->entries = atomic_read(&tbl->gc_entries);
                __entry->created = n != NULL;
                __entry->gc_exempt = exempt_from_gc;
-               pin6 = (struct in6_addr *)__entry->primary_key6;
                p32 = (__be32 *)__entry->primary_key4;
 
                if (tbl->family == AF_INET)
@@ -57,6 +55,8 @@ TRACE_EVENT(neigh_create,
 
 #if IS_ENABLED(CONFIG_IPV6)
                if (tbl->family == AF_INET6) {
+                       struct in6_addr *pin6;
+
                        pin6 = (struct in6_addr *)__entry->primary_key6;
                        *pin6 = *(struct in6_addr *)pkey;
                }
index 44a3f565264d931b1b9257ad4090e5182f322bb6..0577f0cdd23162d6abd7a88b005d9479a7c0f5b0 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 8d7402c13e564220d91f36ea3ac7dcd4d3f5b0c9..0bade1592f34f21690eab41de48595d7aaa24fe4 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 max pushes through getparam
+ *
+ * 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 8790b3962e4b85f22593f8f9c9f8d94eaf6981f3..0448700890f77d9a4fffa6fed5c17aa02b9f718b 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 2f61298a7b7796fc2b8cca615ffed03d08e9f03b..3dcdb9e33cba22b3e96a5079f74426958e98ad72 100644 (file)
@@ -33,6 +33,6 @@ enum gtp_attrs {
        GTPA_PAD,
        __GTPA_MAX,
 };
-#define GTPA_MAX (__GTPA_MAX + 1)
+#define GTPA_MAX (__GTPA_MAX - 1)
 
 #endif /* _UAPI_LINUX_GTP_H_ */
index 4d0ad22f83b56be6566765766a43195d59e966aa..9efc42382fdb98f9e9b5470ae2a66ccf4d0ba4e1 100644 (file)
@@ -18,11 +18,7 @@ struct sockaddr_ll {
        unsigned short  sll_hatype;
        unsigned char   sll_pkttype;
        unsigned char   sll_halen;
-       union {
-               unsigned char   sll_addr[8];
-               /* Actual length is in sll_halen. */
-               __DECLARE_FLEX_ARRAY(unsigned char, sll_addr_flex);
-       };
+       unsigned char   sll_addr[8];
 };
 
 /* Packet types */
index 13065dd96132da65beb99f9455659c9b75ed109d..863f84619a15ad183660b929ff30828e024935ee 100644 (file)
@@ -264,6 +264,7 @@ struct kvm_xen_exit {
 #define KVM_EXIT_RISCV_SBI        35
 #define KVM_EXIT_RISCV_CSR        36
 #define KVM_EXIT_NOTIFY           37
+#define KVM_EXIT_LOONGARCH_IOCSR  38
 
 /* For KVM_EXIT_INTERNAL_ERROR */
 /* Emulate instruction failed. */
@@ -336,6 +337,13 @@ struct kvm_run {
                        __u32 len;
                        __u8  is_write;
                } mmio;
+               /* KVM_EXIT_LOONGARCH_IOCSR */
+               struct {
+                       __u64 phys_addr;
+                       __u8  data[8];
+                       __u32 len;
+                       __u8  is_write;
+               } iocsr_io;
                /* KVM_EXIT_HYPERCALL */
                struct {
                        __u64 nr;
@@ -1362,6 +1370,7 @@ struct kvm_dirty_tlb {
 #define KVM_REG_ARM64          0x6000000000000000ULL
 #define KVM_REG_MIPS           0x7000000000000000ULL
 #define KVM_REG_RISCV          0x8000000000000000ULL
+#define KVM_REG_LOONGARCH      0x9000000000000000ULL
 
 #define KVM_REG_SIZE_SHIFT     52
 #define KVM_REG_SIZE_MASK      0x00f0000000000000ULL
index 7c3fc39808811022b849d9f715b7b6c62a10ef18..5c6c4269f7efe4d649366907191adfbcffef41e4 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 77252cb46361f6526a6516cf1c04527dfa639319..a722dcbf5073dab3400918fd8052a146855eb6d7 100644 (file)
@@ -231,7 +231,7 @@ struct mmp_path {
 
        /* layers */
        int overlay_num;
-       struct mmp_overlay overlays[];
+       struct mmp_overlay overlays[] __counted_by(overlay_num);
 };
 
 extern struct mmp_path *mmp_get_path(const char *name);
index 8d2a3bfc8dac2c7a04f234750fdf0f035f1c78f6..47d96e75e8ef9215415e95910a459c7a7c4cc14c 100644 (file)
@@ -109,8 +109,6 @@ struct uvesafb_ktask {
        u32 ack;
 };
 
-static int uvesafb_exec(struct uvesafb_ktask *tsk);
-
 #define UVESAFB_EXACT_RES      1
 #define UVESAFB_EXACT_DEPTH    2
 
index 43ef24dd030e10237a97373e635632ae5a8e4a9c..9995695204f5d25730ddbc6c9663117eac557072 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 95d5e28de324af3c46f1fd876e7e3e26c8120c70..23932b0673dc7459037c16e97642598a16f08877 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 c536788754164293058b2b852493293369828124..f04a43044d917ceef45fc5a2acfb1910978dd0f3 100644 (file)
@@ -53,7 +53,6 @@ static __cold int io_uring_show_cred(struct seq_file *m, unsigned int id,
 __cold void io_uring_show_fdinfo(struct seq_file *m, struct file *f)
 {
        struct io_ring_ctx *ctx = f->private_data;
-       struct io_sq_data *sq = NULL;
        struct io_overflow_cqe *ocqe;
        struct io_rings *r = ctx->rings;
        unsigned int sq_mask = ctx->sq_entries - 1, cq_mask = ctx->cq_entries - 1;
@@ -64,6 +63,7 @@ __cold void io_uring_show_fdinfo(struct seq_file *m, struct file *f)
        unsigned int cq_shift = 0;
        unsigned int sq_shift = 0;
        unsigned int sq_entries, cq_entries;
+       int sq_pid = -1, sq_cpu = -1;
        bool has_lock;
        unsigned int i;
 
@@ -143,13 +143,19 @@ __cold void io_uring_show_fdinfo(struct seq_file *m, struct file *f)
        has_lock = mutex_trylock(&ctx->uring_lock);
 
        if (has_lock && (ctx->flags & IORING_SETUP_SQPOLL)) {
-               sq = ctx->sq_data;
-               if (!sq->thread)
-                       sq = NULL;
+               struct io_sq_data *sq = ctx->sq_data;
+
+               if (mutex_trylock(&sq->lock)) {
+                       if (sq->thread) {
+                               sq_pid = task_pid_nr(sq->thread);
+                               sq_cpu = task_cpu(sq->thread);
+                       }
+                       mutex_unlock(&sq->lock);
+               }
        }
 
-       seq_printf(m, "SqThread:\t%d\n", sq ? task_pid_nr(sq->thread) : -1);
-       seq_printf(m, "SqThreadCpu:\t%d\n", sq ? task_cpu(sq->thread) : -1);
+       seq_printf(m, "SqThread:\t%d\n", sq_pid);
+       seq_printf(m, "SqThreadCpu:\t%d\n", sq_cpu);
        seq_printf(m, "UserFiles:\t%u\n", ctx->nr_user_files);
        for (i = 0; has_lock && i < ctx->nr_user_files; i++) {
                struct file *f = io_file_from_index(&ctx->file_table, i);
index f6a69a549fd4503fc15a51bf417733fad44c1ebc..08e3b175469c685d64186595da74c778210df88a 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 1ecc8c7487682cec5ee938d9a949ba92305f9205..522196dfb0ff5a2c8054842569d5b1a8d1d43d2d 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 783ed0fff71b58a9e72a05965024ffbe4cb900bc..8d1bc6cdfe712e75638ddf99c2f9ebac2d32d1f5 100644 (file)
@@ -2674,7 +2674,11 @@ static void io_pages_free(struct page ***pages, int npages)
 
        if (!pages)
                return;
+
        page_array = *pages;
+       if (!page_array)
+               return;
+
        for (i = 0; i < npages; i++)
                unpin_user_page(page_array[i]);
        kvfree(page_array);
@@ -2686,7 +2690,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 +2720,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]);
@@ -2744,7 +2762,9 @@ static void io_rings_free(struct io_ring_ctx *ctx)
                ctx->sq_sqes = NULL;
        } else {
                io_pages_free(&ctx->ring_pages, ctx->n_ring_pages);
+               ctx->n_ring_pages = 0;
                io_pages_free(&ctx->sqe_pages, ctx->n_sqe_pages);
+               ctx->n_sqe_pages = 0;
        }
 }
 
index 547c30582fb8872b692b41dfc4986ffa257f808a..0bc145614a6e66ae2d2ec0933fa7165e11f74229 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 556f4df25b0fa0119ea9a135311256b2fda2573a..9123138aa9f48b1acc216f08b70870e095523632 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 c8c822fa79805a958d2e602864a1a2ffc2d13bee..8f68d5ad4564fe7b971f9f0c977276179a713faa 100644 (file)
@@ -339,7 +339,7 @@ static int kiocb_done(struct io_kiocb *req, ssize_t ret,
        struct io_rw *rw = io_kiocb_to_cmd(req, struct io_rw);
        unsigned final_ret = io_fixup_rw_res(req, ret);
 
-       if (req->flags & REQ_F_CUR_POS)
+       if (ret >= 0 && req->flags & REQ_F_CUR_POS)
                req->file->f_pos = rw->kiocb.ki_pos;
        if (ret >= 0 && (rw->kiocb.ki_complete == io_complete_rw)) {
                if (!__io_complete_rw_common(req, ret)) {
@@ -913,15 +913,6 @@ int io_write(struct io_kiocb *req, unsigned int issue_flags)
                kiocb_start_write(kiocb);
        kiocb->ki_flags |= IOCB_WRITE;
 
-       /*
-        * For non-polled IO, set IOCB_DIO_CALLER_COMP, stating that our handler
-        * groks deferring the completion to task context. This isn't
-        * necessary and useful for polled IO as that can always complete
-        * directly.
-        */
-       if (!(kiocb->ki_flags & IOCB_HIPRI))
-               kiocb->ki_flags |= IOCB_DIO_CALLER_COMP;
-
        if (likely(req->file->f_op->write_iter))
                ret2 = call_write_iter(req->file, kiocb, &s->iter);
        else if (req->file->f_op->write)
index 21d2fa815e782afddb5b2c56110fadf7e83376bc..6f0d6fb6523fa76fea59ebe32dd68def39d449c0 100644 (file)
@@ -2212,7 +2212,7 @@ __audit_reusename(const __user char *uptr)
                if (!n->name)
                        continue;
                if (n->name->uptr == uptr) {
-                       n->name->refcnt++;
+                       atomic_inc(&n->name->refcnt);
                        return n->name;
                }
        }
@@ -2241,7 +2241,7 @@ void __audit_getname(struct filename *name)
        n->name = name;
        n->name_len = AUDIT_NAME_FULL;
        name->aname = n;
-       name->refcnt++;
+       atomic_inc(&name->refcnt);
 }
 
 static inline int audit_copy_fcaps(struct audit_names *name,
@@ -2373,7 +2373,7 @@ out_alloc:
                return;
        if (name) {
                n->name = name;
-               name->refcnt++;
+               atomic_inc(&name->refcnt);
        }
 
 out:
@@ -2500,7 +2500,7 @@ void __audit_inode_child(struct inode *parent,
                if (found_parent) {
                        found_child->name = found_parent->name;
                        found_child->name_len = AUDIT_NAME_FULL;
-                       found_child->name->refcnt++;
+                       atomic_inc(&found_child->name->refcnt);
                }
        }
 
index 1095bbe2985930f486010f955d96ee7b57d0a8a1..8090d7fb11ef686019b4734bbc7151057ee78efa 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 5b2741aa0d9bb8e01d630ca548eb39ce10553e6a..03b3d4492980d04f33f63235c6fef18ee2667702 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 9c49ae53deaf81f9e22fefc376657492abd2ebb9..d93ddac283d40144e2cb5ad990ca911a37041346 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 32d2c4829eb8d16ce82d03e06773f67e7684b5d8..1394168062e856b084585ae6663bc989c1c9a400 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);
@@ -398,14 +401,16 @@ int bpf_mprog_query(const union bpf_attr *attr, union bpf_attr __user *uattr,
        struct bpf_mprog_cp *cp;
        struct bpf_prog *prog;
        const u32 flags = 0;
+       u32 id, count = 0;
+       u64 revision = 1;
        int i, ret = 0;
-       u32 id, count;
-       u64 revision;
 
        if (attr->query.query_flags || attr->query.attach_flags)
                return -EINVAL;
-       revision = bpf_mprog_revision(entry);
-       count = bpf_mprog_total(entry);
+       if (entry) {
+               revision = bpf_mprog_revision(entry);
+               count = bpf_mprog_total(entry);
+       }
        if (copy_to_user(&uattr->query.attach_flags, &flags, sizeof(flags)))
                return -EFAULT;
        if (copy_to_user(&uattr->query.revision, &revision, sizeof(revision)))
index 3e4f2ec1af0687dc92d74a376072ab3a77d7b5e3..87d6693d8233f1aa3a1283e73600c9cd6fdf3cdf 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 8d2ddcb7566b7fe262e7571700f1b1ac48dcc782..d869f51ea93a0e918d365729ee5bcd8687a5ce4f 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 eb01c31ed591dde57dc8463a7d701dc46132c8f7..d77b2f8b93641b4445645ec2d9397849fe6a5af3 100644 (file)
@@ -3796,7 +3796,6 @@ static int bpf_prog_attach(const union bpf_attr *attr)
 {
        enum bpf_prog_type ptype;
        struct bpf_prog *prog;
-       u32 mask;
        int ret;
 
        if (CHECK_ATTR(BPF_PROG_ATTACH))
@@ -3805,10 +3804,16 @@ static int bpf_prog_attach(const union bpf_attr *attr)
        ptype = attach_type_to_prog_type(attr->attach_type);
        if (ptype == BPF_PROG_TYPE_UNSPEC)
                return -EINVAL;
-       mask = bpf_mprog_supported(ptype) ?
-              BPF_F_ATTACH_MASK_MPROG : BPF_F_ATTACH_MASK_BASE;
-       if (attr->attach_flags & ~mask)
-               return -EINVAL;
+       if (bpf_mprog_supported(ptype)) {
+               if (attr->attach_flags & ~BPF_F_ATTACH_MASK_MPROG)
+                       return -EINVAL;
+       } else {
+               if (attr->attach_flags & ~BPF_F_ATTACH_MASK_BASE)
+                       return -EINVAL;
+               if (attr->relative_fd ||
+                   attr->expected_revision)
+                       return -EINVAL;
+       }
 
        prog = bpf_prog_get_type(attr->attach_bpf_fd, ptype);
        if (IS_ERR(prog))
@@ -3878,6 +3883,10 @@ static int bpf_prog_detach(const union bpf_attr *attr)
                        if (IS_ERR(prog))
                                return PTR_ERR(prog);
                }
+       } else if (attr->attach_flags ||
+                  attr->relative_fd ||
+                  attr->expected_revision) {
+               return -EINVAL;
        }
 
        switch (ptype) {
@@ -3913,7 +3922,7 @@ static int bpf_prog_detach(const union bpf_attr *attr)
        return ret;
 }
 
-#define BPF_PROG_QUERY_LAST_FIELD query.link_attach_flags
+#define BPF_PROG_QUERY_LAST_FIELD query.revision
 
 static int bpf_prog_query(const union bpf_attr *attr,
                          union bpf_attr __user *uattr)
index 13f0b5dc8262a0086487c95041d8c90ee0cffff8..1338a13a8b64b0dcc0afd37c077a81318c990ddd 100644 (file)
@@ -123,7 +123,6 @@ int tcx_prog_query(const union bpf_attr *attr, union bpf_attr __user *uattr)
 {
        bool ingress = attr->query.attach_type == BPF_TCX_INGRESS;
        struct net *net = current->nsproxy->net_ns;
-       struct bpf_mprog_entry *entry;
        struct net_device *dev;
        int ret;
 
@@ -133,12 +132,7 @@ int tcx_prog_query(const union bpf_attr *attr, union bpf_attr __user *uattr)
                ret = -ENODEV;
                goto out;
        }
-       entry = tcx_entry_fetch(dev, ingress);
-       if (!entry) {
-               ret = -ENOENT;
-               goto out;
-       }
-       ret = bpf_mprog_query(attr, uattr, entry);
+       ret = bpf_mprog_query(attr, uattr, tcx_entry_fetch(dev, ingress));
 out:
        rtnl_unlock();
        return ret;
index bb78212fa5b27305e6672931ae815def8e931fe9..873ade146f3deb17098fab68c21c3e4bca19aa5d 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;
                        }
@@ -14481,7 +14479,7 @@ static int check_return_code(struct bpf_verifier_env *env)
        struct tnum enforce_attach_type_range = tnum_unknown;
        const struct bpf_prog *prog = env->prog;
        struct bpf_reg_state *reg;
-       struct tnum range = tnum_range(0, 1);
+       struct tnum range = tnum_range(0, 1), const_0 = tnum_const(0);
        enum bpf_prog_type prog_type = resolve_prog_type(env->prog);
        int err;
        struct bpf_func_state *frame = env->cur_state->frame[0];
@@ -14529,8 +14527,8 @@ static int check_return_code(struct bpf_verifier_env *env)
                        return -EINVAL;
                }
 
-               if (!tnum_in(tnum_const(0), reg->var_off)) {
-                       verbose_invalid_scalar(env, reg, &range, "async callback", "R0");
+               if (!tnum_in(const_0, reg->var_off)) {
+                       verbose_invalid_scalar(env, reg, &const_0, "async callback", "R0");
                        return -EINVAL;
                }
                return 0;
index c487ffef6652d75735bad19f5bb4eb4a38401b5c..76db6c67e39a9207dfecbc1a5fd375401e6a6142 100644 (file)
@@ -360,10 +360,9 @@ static int pidlist_array_load(struct cgroup *cgrp, enum cgroup_filetype type,
        }
        css_task_iter_end(&it);
        length = n;
-       /* now sort & (if procs) strip out duplicates */
+       /* now sort & strip out duplicates (tgids or recycled thread PIDs) */
        sort(array, length, sizeof(pid_t), cmppid, NULL);
-       if (type == CGROUP_FILE_PROCS)
-               length = pidlist_uniq(array, length);
+       length = pidlist_uniq(array, length);
 
        l = cgroup_pidlist_find_create(cgrp, type);
        if (!l) {
index 03a7932cde0a518939f8325fb450c91391b08891..2f675ef045d40db9704ad940663847db42bdf196 100644 (file)
@@ -739,6 +739,17 @@ subsys_initcall(crash_notes_memory_init);
 #undef pr_fmt
 #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
@@ -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 394494a6b1f35cc7038a2c3ffa00d3984eedd334..dff067bd56b1e2e5a8a6c7565f77fa8984e8a6d5 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)
@@ -679,6 +678,11 @@ static struct io_tlb_pool *swiotlb_alloc_pool(struct device *dev,
        size_t pool_size;
        size_t tlb_size;
 
+       if (nslabs > SLABS_PER_PAGE << MAX_ORDER) {
+               nslabs = SLABS_PER_PAGE << MAX_ORDER;
+               nareas = limit_nareas(nareas, nslabs);
+       }
+
        pool_size = sizeof(*pool) + array_size(sizeof(*pool->areas), nareas);
        pool = kzalloc(pool_size, gfp);
        if (!pool)
@@ -729,9 +733,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 +1153,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 4c72a41f11afbfd8cd893f076176e17602cb78ab..a2f2a9525d72ea86c5510ace8ba651c504e5d794 100644 (file)
@@ -1954,6 +1954,7 @@ static void perf_group_attach(struct perf_event *event)
 
        list_add_tail(&event->sibling_list, &group_leader->sibling_list);
        group_leader->nr_siblings++;
+       group_leader->group_generation++;
 
        perf_event__header_size(group_leader);
 
@@ -2144,6 +2145,7 @@ static void perf_group_detach(struct perf_event *event)
        if (leader != event) {
                list_del_init(&event->sibling_list);
                event->group_leader->nr_siblings--;
+               event->group_leader->group_generation++;
                goto out;
        }
 
@@ -5440,7 +5442,7 @@ static int __perf_read_group_add(struct perf_event *leader,
                                        u64 read_format, u64 *values)
 {
        struct perf_event_context *ctx = leader->ctx;
-       struct perf_event *sub;
+       struct perf_event *sub, *parent;
        unsigned long flags;
        int n = 1; /* skip @nr */
        int ret;
@@ -5450,6 +5452,33 @@ static int __perf_read_group_add(struct perf_event *leader,
                return ret;
 
        raw_spin_lock_irqsave(&ctx->lock, flags);
+       /*
+        * Verify the grouping between the parent and child (inherited)
+        * events is still in tact.
+        *
+        * Specifically:
+        *  - leader->ctx->lock pins leader->sibling_list
+        *  - parent->child_mutex pins parent->child_list
+        *  - parent->ctx->mutex pins parent->sibling_list
+        *
+        * Because parent->ctx != leader->ctx (and child_list nests inside
+        * ctx->mutex), group destruction is not atomic between children, also
+        * see perf_event_release_kernel(). Additionally, parent can grow the
+        * group.
+        *
+        * Therefore it is possible to have parent and child groups in a
+        * different configuration and summing over such a beast makes no sense
+        * what so ever.
+        *
+        * Reject this.
+        */
+       parent = leader->parent;
+       if (parent &&
+           (parent->group_generation != leader->group_generation ||
+            parent->nr_siblings != leader->nr_siblings)) {
+               ret = -ECHILD;
+               goto unlock;
+       }
 
        /*
         * Since we co-schedule groups, {enabled,running} times of siblings
@@ -5483,8 +5512,9 @@ static int __perf_read_group_add(struct perf_event *leader,
                        values[n++] = atomic64_read(&sub->lost_samples);
        }
 
+unlock:
        raw_spin_unlock_irqrestore(&ctx->lock, flags);
-       return 0;
+       return ret;
 }
 
 static int perf_read_group(struct perf_event *event,
@@ -5503,10 +5533,6 @@ static int perf_read_group(struct perf_event *event,
 
        values[0] = 1 + leader->nr_siblings;
 
-       /*
-        * By locking the child_mutex of the leader we effectively
-        * lock the child list of all siblings.. XXX explain how.
-        */
        mutex_lock(&leader->child_mutex);
 
        ret = __perf_read_group_add(leader, read_format, values);
@@ -13346,6 +13372,8 @@ static int inherit_group(struct perf_event *parent_event,
                    !perf_get_aux_event(child_ctr, leader))
                        return -EINVAL;
        }
+       if (leader)
+               leader->group_generation = parent_event->group_generation;
        return 0;
 }
 
index fee14a4486a310ee650e1249b3a85d0719f9a7a7..6500ef956f2f885793833e160891b4f441acd104 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 87e9f7e2bdc05787ab346d2b7a91124692ab5ca2..0f12e0a97e432e312f971bb9dae07639ffe1428b 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 7e0b4dd02398db9a6d12c47d5a8abc383bbcee69..0b3af1529778c0ffe58675af216faeba434aba5e 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 2299a5cfbfb9ed250695edb75d977edbe61eaf43..802551e0009bf1ef66191441a802633bb57543bc 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 4492608b7d7f1c715f46ae462fd760e074066ced..458d359f5991ca7977fb655da4cbb1f71b53bebc 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 a286e726eb4b857d12f2a03b2cadfa07d0df9e52..42c40cfdf83630be349949e5498bd16522405461 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 cb225921bbca47419eeac08a96c98ac74a57ced2..df348aa55d3c7e049fba67b76e1ada8035e797f9 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;
 }
@@ -864,14 +872,16 @@ struct sched_entity *__pick_first_entity(struct cfs_rq *cfs_rq)
  *
  * Which allows an EDF like search on (sub)trees.
  */
-static struct sched_entity *pick_eevdf(struct cfs_rq *cfs_rq)
+static struct sched_entity *__pick_eevdf(struct cfs_rq *cfs_rq)
 {
        struct rb_node *node = cfs_rq->tasks_timeline.rb_root.rb_node;
        struct sched_entity *curr = cfs_rq->curr;
        struct sched_entity *best = NULL;
+       struct sched_entity *best_left = NULL;
 
        if (curr && (!curr->on_rq || !entity_eligible(cfs_rq, curr)))
                curr = NULL;
+       best = curr;
 
        /*
         * Once selected, run a task until it either becomes non-eligible or
@@ -892,33 +902,75 @@ static struct sched_entity *pick_eevdf(struct cfs_rq *cfs_rq)
                }
 
                /*
-                * If this entity has an earlier deadline than the previous
-                * best, take this one. If it also has the earliest deadline
-                * of its subtree, we're done.
+                * Now we heap search eligible trees for the best (min_)deadline
                 */
-               if (!best || deadline_gt(deadline, best, se)) {
+               if (!best || deadline_gt(deadline, best, se))
                        best = se;
-                       if (best->deadline == best->min_deadline)
-                               break;
-               }
 
                /*
-                * If the earlest deadline in this subtree is in the fully
-                * eligible left half of our space, go there.
+                * Every se in a left branch is eligible, keep track of the
+                * branch with the best min_deadline
                 */
+               if (node->rb_left) {
+                       struct sched_entity *left = __node_2_se(node->rb_left);
+
+                       if (!best_left || deadline_gt(min_deadline, best_left, left))
+                               best_left = left;
+
+                       /*
+                        * min_deadline is in the left branch. rb_left and all
+                        * descendants are eligible, so immediately switch to the second
+                        * loop.
+                        */
+                       if (left->min_deadline == se->min_deadline)
+                               break;
+               }
+
+               /* min_deadline is at this node, no need to look right */
+               if (se->deadline == se->min_deadline)
+                       break;
+
+               /* else min_deadline is in the right branch. */
+               node = node->rb_right;
+       }
+
+       /*
+        * We ran into an eligible node which is itself the best.
+        * (Or nr_running == 0 and both are NULL)
+        */
+       if (!best_left || (s64)(best_left->min_deadline - best->deadline) > 0)
+               return best;
+
+       /*
+        * Now best_left and all of its children are eligible, and we are just
+        * looking for deadline == min_deadline
+        */
+       node = &best_left->run_node;
+       while (node) {
+               struct sched_entity *se = __node_2_se(node);
+
+               /* min_deadline is the current node */
+               if (se->deadline == se->min_deadline)
+                       return se;
+
+               /* min_deadline is in the left branch */
                if (node->rb_left &&
                    __node_2_se(node->rb_left)->min_deadline == se->min_deadline) {
                        node = node->rb_left;
                        continue;
                }
 
+               /* else min_deadline is in the right branch */
                node = node->rb_right;
        }
+       return NULL;
+}
 
-       if (!best || (curr && deadline_gt(deadline, best, curr)))
-               best = curr;
+static struct sched_entity *pick_eevdf(struct cfs_rq *cfs_rq)
+{
+       struct sched_entity *se = __pick_eevdf(cfs_rq);
 
-       if (unlikely(!best)) {
+       if (!se) {
                struct sched_entity *left = __pick_first_entity(cfs_rq);
                if (left) {
                        pr_err("EEVDF scheduling fail, picking leftmost\n");
@@ -926,7 +978,7 @@ static struct sched_entity *pick_eevdf(struct cfs_rq *cfs_rq)
                }
        }
 
-       return best;
+       return se;
 }
 
 #ifdef CONFIG_SCHED_DEBUG
@@ -3605,6 +3657,8 @@ static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se,
                 */
                deadline = div_s64(deadline * old_weight, weight);
                se->deadline = se->vruntime + deadline;
+               if (se != cfs_rq->curr)
+                       min_deadline_cb_propagate(&se->run_node, NULL);
        }
 
 #ifdef CONFIG_SMP
@@ -4919,10 +4973,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 342f58a329f528fcc6060208cfba9b7e908d3a98..5007b25c5bc653a9ca0696af1f7136150cd6131e 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 065e1ef8fc8d72e55c66000b7b25f9ba0189db45..95a7e1b7f1dab2d3e5eef4b16e2cefe7f25f2f22 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 a7264b2c17ad771d3bfc2a752da2339c157f4993..868008f56fec24fe7030d2fed9b063d1e1dd7926 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 3b21f406325829ceedfb3911ce76ed0f219005b8..881f90f0cbcfac92831e97bca869347d52b15e3e 100644 (file)
@@ -189,7 +189,7 @@ static int fprobe_init_rethook(struct fprobe *fp, int num)
 {
        int i, size;
 
-       if (num < 0)
+       if (num <= 0)
                return -EINVAL;
 
        if (!fp->exit_handler) {
@@ -202,8 +202,8 @@ static int fprobe_init_rethook(struct fprobe *fp, int num)
                size = fp->nr_maxactive;
        else
                size = num * num_possible_cpus() * 2;
-       if (size < 0)
-               return -E2BIG;
+       if (size <= 0)
+               return -EINVAL;
 
        fp->rethook = rethook_alloc((void *)fp, fprobe_exit_handler);
        if (!fp->rethook)
index a1651edc48d5187ef4cf4d2beacd3fa8e68a22cc..515cafdb18d98a0f6846f078847bead4c8ecd87d 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 91951d038ba491fe51ba66f7ed792526be0ed9d7..f49d6ddb634255335ebdd4e0d938ac841e69bad1 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 6f046650e52719918fdbb083f6c24df29d947036..b87f41187c6a9252be444f00f42049cf3941455e 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 3d7a180a84272e891458c5274daa2897a91f867c..e834f149695b75b1f66fd6f2c498a8037a3c2719 100644 (file)
@@ -705,6 +705,41 @@ static struct notifier_block trace_kprobe_module_nb = {
        .priority = 1   /* Invoked after kprobe module callback */
 };
 
+static int count_symbols(void *data, unsigned long unused)
+{
+       unsigned int *count = data;
+
+       (*count)++;
+
+       return 0;
+}
+
+struct sym_count_ctx {
+       unsigned int count;
+       const char *name;
+};
+
+static int count_mod_symbols(void *data, const char *name, unsigned long unused)
+{
+       struct sym_count_ctx *ctx = data;
+
+       if (strcmp(name, ctx->name) == 0)
+               ctx->count++;
+
+       return 0;
+}
+
+static unsigned int number_of_same_symbols(char *func_name)
+{
+       struct sym_count_ctx ctx = { .count = 0, .name = func_name };
+
+       kallsyms_on_each_match_symbol(count_symbols, func_name, &ctx.count);
+
+       module_kallsyms_on_each_symbol(NULL, count_mod_symbols, &ctx);
+
+       return ctx.count;
+}
+
 static int __trace_kprobe_create(int argc, const char *argv[])
 {
        /*
@@ -836,6 +871,31 @@ static int __trace_kprobe_create(int argc, const char *argv[])
                }
        }
 
+       if (symbol && !strchr(symbol, ':')) {
+               unsigned int count;
+
+               count = number_of_same_symbols(symbol);
+               if (count > 1) {
+                       /*
+                        * Users should use ADDR to remove the ambiguity of
+                        * using KSYM only.
+                        */
+                       trace_probe_log_err(0, NON_UNIQ_SYMBOL);
+                       ret = -EADDRNOTAVAIL;
+
+                       goto error;
+               } else if (count == 0) {
+                       /*
+                        * We can return ENOENT earlier than when register the
+                        * kprobe.
+                        */
+                       trace_probe_log_err(0, BAD_PROBE_ADDR);
+                       ret = -ENOENT;
+
+                       goto error;
+               }
+       }
+
        trace_probe_log_set_index(0);
        if (event) {
                ret = traceprobe_parse_event_name(&event, &group, gbuf,
@@ -963,7 +1023,7 @@ EXPORT_SYMBOL_GPL(kprobe_event_cmd_init);
  * @name: The name of the kprobe event
  * @loc: The location of the kprobe event
  * @kretprobe: Is this a return probe?
- * @args: Variable number of arg (pairs), one pair for each field
+ * @...: Variable number of arg (pairs), one pair for each field
  *
  * NOTE: Users normally won't want to call this function directly, but
  * rather use the kprobe_event_gen_cmd_start() wrapper, which automatically
@@ -1036,7 +1096,7 @@ EXPORT_SYMBOL_GPL(__kprobe_event_gen_cmd_start);
 /**
  * __kprobe_event_add_fields - Add probe fields to a kprobe command from arg list
  * @cmd: A pointer to the dynevent_cmd struct representing the new event
- * @args: Variable number of arg (pairs), one pair for each field
+ * @...: Variable number of arg (pairs), one pair for each field
  *
  * NOTE: Users normally won't want to call this function directly, but
  * rather use the kprobe_event_add_fields() wrapper, which
@@ -1695,6 +1755,7 @@ static int unregister_kprobe_event(struct trace_kprobe *tk)
 }
 
 #ifdef CONFIG_PERF_EVENTS
+
 /* create a trace_kprobe, but don't add it to global lists */
 struct trace_event_call *
 create_local_trace_kprobe(char *func, void *addr, unsigned long offs,
@@ -1705,6 +1766,24 @@ create_local_trace_kprobe(char *func, void *addr, unsigned long offs,
        int ret;
        char *event;
 
+       if (func) {
+               unsigned int count;
+
+               count = number_of_same_symbols(func);
+               if (count > 1)
+                       /*
+                        * Users should use addr to remove the ambiguity of
+                        * using func only.
+                        */
+                       return ERR_PTR(-EADDRNOTAVAIL);
+               else if (count == 0)
+                       /*
+                        * We can return ENOENT earlier than when register the
+                        * kprobe.
+                        */
+                       return ERR_PTR(-ENOENT);
+       }
+
        /*
         * local trace_kprobes are not added to dyn_event, so they are never
         * searched in find_trace_kprobe(). Therefore, there is no concern of
index 02b432ae7513137922d90a73621dad3071ec0fb5..850d9ecb6765a8bd372b214ee6f302e3374ffa93 100644 (file)
@@ -450,6 +450,7 @@ extern int traceprobe_define_arg_fields(struct trace_event_call *event_call,
        C(BAD_MAXACT,           "Invalid maxactive number"),            \
        C(MAXACT_TOO_BIG,       "Maxactive is too big"),                \
        C(BAD_PROBE_ADDR,       "Invalid probed address or symbol"),    \
+       C(NON_UNIQ_SYMBOL,      "The symbol is not unique"),            \
        C(BAD_RETPROBE,         "Retprobe address must be an function entry"), \
        C(NO_TRACEPOINT,        "Tracepoint is not found"),             \
        C(BAD_ADDR_SUFFIX,      "Invalid probed address suffix"), \
index c85825e17df8530d8ec1b76f2a262e8ecd51a099..a3522b70218d3a8e77c2db02c0ad3bc4ea366ca0 100644 (file)
@@ -2166,7 +2166,7 @@ static struct worker *create_worker(struct worker_pool *pool)
 {
        struct worker *worker;
        int id;
-       char id_buf[16];
+       char id_buf[23];
 
        /* ID is needed to determine kthread name */
        id = ida_alloc(&pool->worker_ida, GFP_KERNEL);
@@ -4600,12 +4600,22 @@ static int alloc_and_link_pwqs(struct workqueue_struct *wq)
        }
        cpus_read_unlock();
 
+       /* for unbound pwq, flush the pwq_release_worker ensures that the
+        * pwq_release_workfn() completes before calling kfree(wq).
+        */
+       if (ret)
+               kthread_flush_worker(pwq_release_worker);
+
        return ret;
 
 enomem:
        if (wq->cpu_pwq) {
-               for_each_possible_cpu(cpu)
-                       kfree(*per_cpu_ptr(wq->cpu_pwq, cpu));
+               for_each_possible_cpu(cpu) {
+                       struct pool_workqueue *pwq = *per_cpu_ptr(wq->cpu_pwq, cpu);
+
+                       if (pwq)
+                               kmem_cache_free(pwq_cache, pwq);
+               }
                free_percpu(wq->cpu_pwq);
                wq->cpu_pwq = NULL;
        }
@@ -5782,9 +5792,13 @@ static int workqueue_apply_unbound_cpumask(const cpumask_var_t unbound_cpumask)
        list_for_each_entry(wq, &workqueues, list) {
                if (!(wq->flags & WQ_UNBOUND))
                        continue;
+
                /* creating multiple pwqs breaks ordering guarantee */
-               if (wq->flags & __WQ_ORDERED)
-                       continue;
+               if (!list_empty(&wq->pwqs)) {
+                       if (wq->flags & __WQ_ORDERED_EXPLICIT)
+                               continue;
+                       wq->flags &= ~__WQ_ORDERED;
+               }
 
                ctx = apply_wqattrs_prepare(wq, wq->unbound_attrs, unbound_cpumask);
                if (IS_ERR(ctx)) {
@@ -6535,9 +6549,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 +6616,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 1a19a0a93dc1cb8931c2f9f5d512650a5a1a0fe6..e28db8e3b58c8154ef571b5359cab90b32f6acba 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 ee1ff0c59fd7534325759c2c07525ba16f0beb8a..bb24d84a4922f0d5b14f40a202a76708cb247402 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
@@ -5574,7 +5627,7 @@ int mas_expected_entries(struct ma_state *mas, unsigned long nr_entries)
        /* Internal nodes */
        nr_nodes += DIV_ROUND_UP(nr_nodes, nonleaf_cap);
        /* Add working room for split (2 nodes) + new parents */
-       mas_node_count(mas, nr_nodes + 3);
+       mas_node_count_gfp(mas, nr_nodes + 3, GFP_KERNEL);
 
        /* Detect if allocations run out */
        mas->mas_flags |= MA_STATE_PREALLOC;
@@ -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 c65566b4dc662afff966b773b78631de185c8851..68b45c82c37a6981bb72cc79ab4c4fcac8e2e489 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 0674aebd44230d94a12f6b8545bb6e67ae69c938..464eeb90d5ad02392dd6fed2ac8a3b8ac5a75b91 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <linux/maple_tree.h>
 #include <linux/module.h>
+#include <linux/rwsem.h>
 
 #define MTREE_ALLOC_MAX 0x2000000000000Ul
 #define CONFIG_MAPLE_SEARCH
@@ -1841,17 +1842,21 @@ static noinline void __init check_forking(struct maple_tree *mt)
        void *val;
        MA_STATE(mas, mt, 0, 0);
        MA_STATE(newmas, mt, 0, 0);
+       struct rw_semaphore newmt_lock;
+
+       init_rwsem(&newmt_lock);
 
        for (i = 0; i <= nr_entries; i++)
                mtree_store_range(mt, i*10, i*10 + 5,
                                  xa_mk_value(i), GFP_KERNEL);
 
        mt_set_non_kernel(99999);
-       mt_init_flags(&newmt, MT_FLAGS_ALLOC_RANGE);
+       mt_init_flags(&newmt, MT_FLAGS_ALLOC_RANGE | MT_FLAGS_LOCK_EXTERN);
+       mt_set_external_lock(&newmt, &newmt_lock);
        newmas.tree = &newmt;
        mas_reset(&newmas);
        mas_reset(&mas);
-       mas_lock(&newmas);
+       down_write(&newmt_lock);
        mas.index = 0;
        mas.last = 0;
        if (mas_expected_entries(&newmas, nr_entries)) {
@@ -1866,10 +1871,10 @@ static noinline void __init check_forking(struct maple_tree *mt)
        }
        rcu_read_unlock();
        mas_destroy(&newmas);
-       mas_unlock(&newmas);
        mt_validate(&newmt);
        mt_set_non_kernel(0);
-       mtree_destroy(&newmt);
+       __mt_destroy(&newmt);
+       up_write(&newmt_lock);
 }
 
 static noinline void __init check_iteration(struct maple_tree *mt)
@@ -1980,6 +1985,10 @@ static noinline void __init bench_forking(struct maple_tree *mt)
        void *val;
        MA_STATE(mas, mt, 0, 0);
        MA_STATE(newmas, mt, 0, 0);
+       struct rw_semaphore newmt_lock;
+
+       init_rwsem(&newmt_lock);
+       mt_set_external_lock(&newmt, &newmt_lock);
 
        for (i = 0; i <= nr_entries; i++)
                mtree_store_range(mt, i*10, i*10 + 5,
@@ -1994,7 +2003,7 @@ static noinline void __init bench_forking(struct maple_tree *mt)
                mas.index = 0;
                mas.last = 0;
                rcu_read_lock();
-               mas_lock(&newmas);
+               down_write(&newmt_lock);
                if (mas_expected_entries(&newmas, nr_entries)) {
                        printk("OOM!");
                        BUG_ON(1);
@@ -2005,11 +2014,11 @@ static noinline void __init bench_forking(struct maple_tree *mt)
                        mas_store(&newmas, val);
                }
                mas_destroy(&newmas);
-               mas_unlock(&newmas);
                rcu_read_unlock();
                mt_validate(&newmt);
                mt_set_non_kernel(0);
-               mtree_destroy(&newmt);
+               __mt_destroy(&newmt);
+               up_write(&newmt_lock);
        }
 }
 #endif
@@ -2166,7 +2175,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;
@@ -2616,6 +2625,10 @@ static noinline void __init check_dup_gaps(struct maple_tree *mt,
        void *tmp;
        MA_STATE(mas, mt, 0, 0);
        MA_STATE(newmas, &newmt, 0, 0);
+       struct rw_semaphore newmt_lock;
+
+       init_rwsem(&newmt_lock);
+       mt_set_external_lock(&newmt, &newmt_lock);
 
        if (!zero_start)
                i = 1;
@@ -2625,9 +2638,9 @@ static noinline void __init check_dup_gaps(struct maple_tree *mt,
                mtree_store_range(mt, i*10, (i+1)*10 - gap,
                                  xa_mk_value(i), GFP_KERNEL);
 
-       mt_init_flags(&newmt, MT_FLAGS_ALLOC_RANGE);
+       mt_init_flags(&newmt, MT_FLAGS_ALLOC_RANGE | MT_FLAGS_LOCK_EXTERN);
        mt_set_non_kernel(99999);
-       mas_lock(&newmas);
+       down_write(&newmt_lock);
        ret = mas_expected_entries(&newmas, nr_entries);
        mt_set_non_kernel(0);
        MT_BUG_ON(mt, ret != 0);
@@ -2640,9 +2653,9 @@ static noinline void __init check_dup_gaps(struct maple_tree *mt,
        }
        rcu_read_unlock();
        mas_destroy(&newmas);
-       mas_unlock(&newmas);
 
-       mtree_destroy(&newmt);
+       __mt_destroy(&newmt);
+       up_write(&newmt_lock);
 }
 
 /* Duplicate many sizes of trees.  Mainly to test expected entry values */
@@ -2917,6 +2930,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 +2959,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 +2970,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 +2982,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 +3007,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 +3054,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 +3084,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,27 +3283,48 @@ 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 */
        mas_set(&mas, 0);
        entry = mas_next(&mas, ULONG_MAX);
@@ -3307,11 +3343,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 +3396,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 +3450,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 +3849,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 b86ba7b0a9214c8b1b036ce2d4f793aa451765bb..f60e56150feb691e9b740c31f9fc539cb2a0cba1 100644 (file)
@@ -1208,6 +1208,8 @@ static int damon_sysfs_set_targets(struct damon_ctx *ctx,
        return 0;
 }
 
+static bool damon_sysfs_schemes_regions_updating;
+
 static void damon_sysfs_before_terminate(struct damon_ctx *ctx)
 {
        struct damon_target *t, *next;
@@ -1219,8 +1221,10 @@ static void damon_sysfs_before_terminate(struct damon_ctx *ctx)
        cmd = damon_sysfs_cmd_request.cmd;
        if (kdamond && ctx == kdamond->damon_ctx &&
                        (cmd == DAMON_SYSFS_CMD_UPDATE_SCHEMES_TRIED_REGIONS ||
-                        cmd == DAMON_SYSFS_CMD_UPDATE_SCHEMES_TRIED_BYTES)) {
+                        cmd == DAMON_SYSFS_CMD_UPDATE_SCHEMES_TRIED_BYTES) &&
+                       damon_sysfs_schemes_regions_updating) {
                damon_sysfs_schemes_update_regions_stop(ctx);
+               damon_sysfs_schemes_regions_updating = false;
                mutex_unlock(&damon_sysfs_lock);
        }
 
@@ -1340,7 +1344,6 @@ static int damon_sysfs_commit_input(struct damon_sysfs_kdamond *kdamond)
 static int damon_sysfs_cmd_request_callback(struct damon_ctx *c)
 {
        struct damon_sysfs_kdamond *kdamond;
-       static bool damon_sysfs_schemes_regions_updating;
        bool total_bytes_only = false;
        int err = 0;
 
index c4b455b5ee30b867765da4bcff1d3c24e1398c8f..dcf1ca6b31cc4f8ef86ffe7ab6ea77f81a221bde 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 4c81a9dbd0444801a6578dd4e9fb2a47622da1af..cf8a9fc5c9d1a61770572a15c8e55738601b6e7a 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 582f5317ff717d8d9fa017d0395a3bda3628a1f6..f0a15ce1bd1ba1cca4856e05e70d9e44128709b4 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 ba6d39b71cb14326393f53d7c6068e2648932ffb..1301ba7b2c9a90f5d16bf97a7190b6a202d2db8b 100644 (file)
@@ -97,6 +97,7 @@ static void hugetlb_vma_lock_alloc(struct vm_area_struct *vma);
 static void __hugetlb_vma_unlock_write_free(struct vm_area_struct *vma);
 static void hugetlb_unshare_pmds(struct vm_area_struct *vma,
                unsigned long start, unsigned long end);
+static struct resv_map *vma_resv_map(struct vm_area_struct *vma);
 
 static inline bool subpool_is_free(struct hugepage_subpool *spool)
 {
@@ -267,6 +268,10 @@ void hugetlb_vma_lock_read(struct vm_area_struct *vma)
                struct hugetlb_vma_lock *vma_lock = vma->vm_private_data;
 
                down_read(&vma_lock->rw_sema);
+       } else if (__vma_private_lock(vma)) {
+               struct resv_map *resv_map = vma_resv_map(vma);
+
+               down_read(&resv_map->rw_sema);
        }
 }
 
@@ -276,6 +281,10 @@ void hugetlb_vma_unlock_read(struct vm_area_struct *vma)
                struct hugetlb_vma_lock *vma_lock = vma->vm_private_data;
 
                up_read(&vma_lock->rw_sema);
+       } else if (__vma_private_lock(vma)) {
+               struct resv_map *resv_map = vma_resv_map(vma);
+
+               up_read(&resv_map->rw_sema);
        }
 }
 
@@ -285,6 +294,10 @@ void hugetlb_vma_lock_write(struct vm_area_struct *vma)
                struct hugetlb_vma_lock *vma_lock = vma->vm_private_data;
 
                down_write(&vma_lock->rw_sema);
+       } else if (__vma_private_lock(vma)) {
+               struct resv_map *resv_map = vma_resv_map(vma);
+
+               down_write(&resv_map->rw_sema);
        }
 }
 
@@ -294,17 +307,27 @@ void hugetlb_vma_unlock_write(struct vm_area_struct *vma)
                struct hugetlb_vma_lock *vma_lock = vma->vm_private_data;
 
                up_write(&vma_lock->rw_sema);
+       } else if (__vma_private_lock(vma)) {
+               struct resv_map *resv_map = vma_resv_map(vma);
+
+               up_write(&resv_map->rw_sema);
        }
 }
 
 int hugetlb_vma_trylock_write(struct vm_area_struct *vma)
 {
-       struct hugetlb_vma_lock *vma_lock = vma->vm_private_data;
 
-       if (!__vma_shareable_lock(vma))
-               return 1;
+       if (__vma_shareable_lock(vma)) {
+               struct hugetlb_vma_lock *vma_lock = vma->vm_private_data;
 
-       return down_write_trylock(&vma_lock->rw_sema);
+               return down_write_trylock(&vma_lock->rw_sema);
+       } else if (__vma_private_lock(vma)) {
+               struct resv_map *resv_map = vma_resv_map(vma);
+
+               return down_write_trylock(&resv_map->rw_sema);
+       }
+
+       return 1;
 }
 
 void hugetlb_vma_assert_locked(struct vm_area_struct *vma)
@@ -313,6 +336,10 @@ void hugetlb_vma_assert_locked(struct vm_area_struct *vma)
                struct hugetlb_vma_lock *vma_lock = vma->vm_private_data;
 
                lockdep_assert_held(&vma_lock->rw_sema);
+       } else if (__vma_private_lock(vma)) {
+               struct resv_map *resv_map = vma_resv_map(vma);
+
+               lockdep_assert_held(&resv_map->rw_sema);
        }
 }
 
@@ -345,6 +372,11 @@ static void __hugetlb_vma_unlock_write_free(struct vm_area_struct *vma)
                struct hugetlb_vma_lock *vma_lock = vma->vm_private_data;
 
                __hugetlb_vma_unlock_write_put(vma_lock);
+       } else if (__vma_private_lock(vma)) {
+               struct resv_map *resv_map = vma_resv_map(vma);
+
+               /* no free for anon vmas, but still need to unlock */
+               up_write(&resv_map->rw_sema);
        }
 }
 
@@ -1068,6 +1100,7 @@ struct resv_map *resv_map_alloc(void)
        kref_init(&resv_map->refs);
        spin_lock_init(&resv_map->lock);
        INIT_LIST_HEAD(&resv_map->regions);
+       init_rwsem(&resv_map->rw_sema);
 
        resv_map->adds_in_progress = 0;
        /*
@@ -1138,8 +1171,7 @@ static void set_vma_resv_map(struct vm_area_struct *vma, struct resv_map *map)
        VM_BUG_ON_VMA(!is_vm_hugetlb_page(vma), vma);
        VM_BUG_ON_VMA(vma->vm_flags & VM_MAYSHARE, vma);
 
-       set_vma_private_data(vma, (get_vma_private_data(vma) &
-                               HPAGE_RESV_MASK) | (unsigned long)map);
+       set_vma_private_data(vma, (unsigned long)map);
 }
 
 static void set_vma_resv_flags(struct vm_area_struct *vma, unsigned long flags)
@@ -4980,7 +5012,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 +5020,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 +5097,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 +5112,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 +5177,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 +5198,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 +5216,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 +5235,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 +5292,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)
@@ -5273,9 +5306,9 @@ int move_hugetlb_page_tables(struct vm_area_struct *vma,
        return len + old_addr - old_end;
 }
 
-static void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct *vma,
-                                  unsigned long start, unsigned long end,
-                                  struct page *ref_page, zap_flags_t zap_flags)
+void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct *vma,
+                           unsigned long start, unsigned long end,
+                           struct page *ref_page, zap_flags_t zap_flags)
 {
        struct mm_struct *mm = vma->vm_mm;
        unsigned long address;
@@ -5337,7 +5370,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 +5405,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);
 
@@ -5402,16 +5437,25 @@ static void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct
                tlb_flush_mmu_tlbonly(tlb);
 }
 
-void __unmap_hugepage_range_final(struct mmu_gather *tlb,
-                         struct vm_area_struct *vma, unsigned long start,
-                         unsigned long end, struct page *ref_page,
-                         zap_flags_t zap_flags)
+void __hugetlb_zap_begin(struct vm_area_struct *vma,
+                        unsigned long *start, unsigned long *end)
 {
+       if (!vma->vm_file)      /* hugetlbfs_file_mmap error */
+               return;
+
+       adjust_range_if_pmd_sharing_possible(vma, start, end);
        hugetlb_vma_lock_write(vma);
-       i_mmap_lock_write(vma->vm_file->f_mapping);
+       if (vma->vm_file)
+               i_mmap_lock_write(vma->vm_file->f_mapping);
+}
 
-       /* mmu notification performed in caller */
-       __unmap_hugepage_range(tlb, vma, start, end, ref_page, zap_flags);
+void __hugetlb_zap_end(struct vm_area_struct *vma,
+                      struct zap_details *details)
+{
+       zap_flags_t zap_flags = details ? details->zap_flags : 0;
+
+       if (!vma->vm_file)      /* hugetlbfs_file_mmap error */
+               return;
 
        if (zap_flags & ZAP_FLAG_UNMAP) {       /* final unmap */
                /*
@@ -5424,11 +5468,12 @@ void __unmap_hugepage_range_final(struct mmu_gather *tlb,
                 * someone else.
                 */
                __hugetlb_vma_unlock_write_free(vma);
-               i_mmap_unlock_write(vma->vm_file->f_mapping);
        } else {
-               i_mmap_unlock_write(vma->vm_file->f_mapping);
                hugetlb_vma_unlock_write(vma);
        }
+
+       if (vma->vm_file)
+               i_mmap_unlock_write(vma->vm_file->f_mapping);
 }
 
 void unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start,
@@ -5676,7 +5721,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 +6017,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 +6306,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 +6458,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 +6644,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 +6669,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);
        }
@@ -6806,8 +6853,10 @@ out_err:
                 */
                if (chg >= 0 && add < 0)
                        region_abort(resv_map, from, to, regions_needed);
-       if (vma && is_vma_resv_set(vma, HPAGE_RESV_OWNER))
+       if (vma && is_vma_resv_set(vma, HPAGE_RESV_OWNER)) {
                kref_put(&resv_map->refs, resv_map_release);
+               set_vma_resv_map(vma, NULL);
+       }
        return false;
 }
 
index f70e3d7a602e1e816abe7357793fcb16fdfa3f91..d37831b8511c611a43dbe6f0a1bea1ccf6e7c0e4 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 ca4b6ff080a64c3f6c03635205ae0244d7512591..6e3cb118d20ed53eb3ad39b07a579be13fa7cd3b 100644 (file)
@@ -621,7 +621,7 @@ void kasan_report_async(void)
 }
 #endif /* CONFIG_KASAN_HW_TAGS */
 
-#ifdef CONFIG_KASAN_INLINE
+#if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS)
 /*
  * With CONFIG_KASAN_INLINE, accesses to bogus pointers (outside the high
  * canonical half of the address space) cause out-of-bounds shadow memory reads
index a4d3282493b60461a7cb8e275db27a8638c0c4a4..5b009b233ab8921110148de54b6b96e69d5ab638 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;
@@ -5077,6 +5084,12 @@ static struct cftype mem_cgroup_legacy_files[] = {
                .seq_show = memcg_numa_stat_show,
        },
 #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),
index 6c264d2f969c0200685307ca2d8ac0e0f5ba4f05..517221f013035345f611a2a595dd31f0fbbe53b1 100644 (file)
@@ -1683,7 +1683,7 @@ static void unmap_single_vma(struct mmu_gather *tlb,
                        if (vma->vm_file) {
                                zap_flags_t zap_flags = details ?
                                    details->zap_flags : 0;
-                               __unmap_hugepage_range_final(tlb, vma, start, end,
+                               __unmap_hugepage_range(tlb, vma, start, end,
                                                             NULL, zap_flags);
                        }
                } else
@@ -1728,8 +1728,12 @@ void unmap_vmas(struct mmu_gather *tlb, struct ma_state *mas,
                                start_addr, end_addr);
        mmu_notifier_invalidate_range_start(&range);
        do {
-               unmap_single_vma(tlb, vma, start_addr, end_addr, &details,
+               unsigned long start = start_addr;
+               unsigned long end = end_addr;
+               hugetlb_zap_begin(vma, &start, &end);
+               unmap_single_vma(tlb, vma, start, end, &details,
                                 mm_wr_locked);
+               hugetlb_zap_end(vma, &details);
        } while ((vma = mas_find(mas, tree_end - 1)) != NULL);
        mmu_notifier_invalidate_range_end(&range);
 }
@@ -1753,9 +1757,7 @@ void zap_page_range_single(struct vm_area_struct *vma, unsigned long address,
        lru_add_drain();
        mmu_notifier_range_init(&range, MMU_NOTIFY_CLEAR, 0, vma->vm_mm,
                                address, end);
-       if (is_vm_hugetlb_page(vma))
-               adjust_range_if_pmd_sharing_possible(vma, &range.start,
-                                                    &range.end);
+       hugetlb_zap_begin(vma, &range.start, &range.end);
        tlb_gather_mmu(&tlb, vma->vm_mm);
        update_hiwater_rss(vma->vm_mm);
        mmu_notifier_invalidate_range_start(&range);
@@ -1766,6 +1768,7 @@ void zap_page_range_single(struct vm_area_struct *vma, unsigned long address,
        unmap_single_vma(&tlb, vma, address, end, details, false);
        mmu_notifier_invalidate_range_end(&range);
        tlb_finish_mmu(&tlb);
+       hugetlb_zap_end(vma, details);
 }
 
 /**
index 42b5567e37738d20ae67fa3b826677d97afe4609..29ebf1e7898cf0ea4a0ab5ee3ea92eecd269208a 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:
@@ -1544,8 +1543,10 @@ SYSCALL_DEFINE4(set_mempolicy_home_node, unsigned long, start, unsigned long, le
                 * the home node for vmas we already updated before.
                 */
                old = vma_policy(vma);
-               if (!old)
+               if (!old) {
+                       prev = vma;
                        continue;
+               }
                if (old->mode != MPOL_BIND && old->mode != MPOL_PREFERRED_MANY) {
                        err = -EOPNOTSUPP;
                        break;
index b7fa020003f34e4f539491d3755735607469b1c1..06086dc9da288f96debedb4582d9467a02563322 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
                {
@@ -2159,6 +2162,7 @@ static int do_pages_move(struct mm_struct *mm, nodemask_t task_nodes,
                         const int __user *nodes,
                         int __user *status, int flags)
 {
+       compat_uptr_t __user *compat_pages = (void __user *)pages;
        int current_node = NUMA_NO_NODE;
        LIST_HEAD(pagelist);
        int start, i;
@@ -2171,8 +2175,17 @@ static int do_pages_move(struct mm_struct *mm, nodemask_t task_nodes,
                int node;
 
                err = -EFAULT;
-               if (get_user(p, pages + i))
-                       goto out_flush;
+               if (in_compat_syscall()) {
+                       compat_uptr_t cp;
+
+                       if (get_user(cp, compat_pages + i))
+                               goto out_flush;
+
+                       p = compat_ptr(cp);
+               } else {
+                       if (get_user(p, pages + i))
+                               goto out_flush;
+               }
                if (get_user(node, nodes + i))
                        goto out_flush;
 
index b56a7f0c9f856509a7a17eac92c71f2ce30b659c..9e018d8dd7d6930519760e8d96d02386294e4a68 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -583,11 +583,12 @@ again:
  * dup_anon_vma() - Helper function to duplicate anon_vma
  * @dst: The destination VMA
  * @src: The source VMA
+ * @dup: Pointer to the destination VMA when successful.
  *
  * Returns: 0 on success.
  */
 static inline int dup_anon_vma(struct vm_area_struct *dst,
-                              struct vm_area_struct *src)
+               struct vm_area_struct *src, struct vm_area_struct **dup)
 {
        /*
         * Easily overlooked: when mprotect shifts the boundary, make sure the
@@ -595,9 +596,15 @@ static inline int dup_anon_vma(struct vm_area_struct *dst,
         * anon pages imported.
         */
        if (src->anon_vma && !dst->anon_vma) {
+               int ret;
+
                vma_assert_write_locked(dst);
                dst->anon_vma = src->anon_vma;
-               return anon_vma_clone(dst, src);
+               ret = anon_vma_clone(dst, src);
+               if (ret)
+                       return ret;
+
+               *dup = dst;
        }
 
        return 0;
@@ -624,6 +631,7 @@ int vma_expand(struct vma_iterator *vmi, struct vm_area_struct *vma,
               unsigned long start, unsigned long end, pgoff_t pgoff,
               struct vm_area_struct *next)
 {
+       struct vm_area_struct *anon_dup = NULL;
        bool remove_next = false;
        struct vma_prepare vp;
 
@@ -633,7 +641,7 @@ int vma_expand(struct vma_iterator *vmi, struct vm_area_struct *vma,
 
                remove_next = true;
                vma_start_write(next);
-               ret = dup_anon_vma(vma, next);
+               ret = dup_anon_vma(vma, next, &anon_dup);
                if (ret)
                        return ret;
        }
@@ -661,6 +669,8 @@ int vma_expand(struct vma_iterator *vmi, struct vm_area_struct *vma,
        return 0;
 
 nomem:
+       if (anon_dup)
+               unlink_anon_vmas(anon_dup);
        return -ENOMEM;
 }
 
@@ -860,6 +870,7 @@ struct vm_area_struct *vma_merge(struct vma_iterator *vmi, struct mm_struct *mm,
 {
        struct vm_area_struct *curr, *next, *res;
        struct vm_area_struct *vma, *adjust, *remove, *remove2;
+       struct vm_area_struct *anon_dup = NULL;
        struct vma_prepare vp;
        pgoff_t vma_pgoff;
        int err = 0;
@@ -927,18 +938,18 @@ struct vm_area_struct *vma_merge(struct vma_iterator *vmi, struct mm_struct *mm,
                vma_start_write(next);
                remove = next;                          /* case 1 */
                vma_end = next->vm_end;
-               err = dup_anon_vma(prev, next);
+               err = dup_anon_vma(prev, next, &anon_dup);
                if (curr) {                             /* case 6 */
                        vma_start_write(curr);
                        remove = curr;
                        remove2 = next;
                        if (!next->anon_vma)
-                               err = dup_anon_vma(prev, curr);
+                               err = dup_anon_vma(prev, curr, &anon_dup);
                }
        } else if (merge_prev) {                        /* case 2 */
                if (curr) {
                        vma_start_write(curr);
-                       err = dup_anon_vma(prev, curr);
+                       err = dup_anon_vma(prev, curr, &anon_dup);
                        if (end == curr->vm_end) {      /* case 7 */
                                remove = curr;
                        } else {                        /* case 5 */
@@ -954,7 +965,7 @@ struct vm_area_struct *vma_merge(struct vma_iterator *vmi, struct mm_struct *mm,
                        vma_end = addr;
                        adjust = next;
                        adj_start = -(prev->vm_end - addr);
-                       err = dup_anon_vma(next, prev);
+                       err = dup_anon_vma(next, prev, &anon_dup);
                } else {
                        /*
                         * Note that cases 3 and 8 are the ONLY ones where prev
@@ -968,14 +979,14 @@ struct vm_area_struct *vma_merge(struct vma_iterator *vmi, struct mm_struct *mm,
                                vma_pgoff = curr->vm_pgoff;
                                vma_start_write(curr);
                                remove = curr;
-                               err = dup_anon_vma(next, curr);
+                               err = dup_anon_vma(next, curr, &anon_dup);
                        }
                }
        }
 
        /* Error in anon_vma clone. */
        if (err)
-               return NULL;
+               goto anon_vma_fail;
 
        if (vma_start < vma->vm_start || vma_end > vma->vm_end)
                vma_expanded = true;
@@ -988,7 +999,7 @@ struct vm_area_struct *vma_merge(struct vma_iterator *vmi, struct mm_struct *mm,
        }
 
        if (vma_iter_prealloc(vmi, vma))
-               return NULL;
+               goto prealloc_fail;
 
        init_multi_vma_prep(&vp, vma, adjust, remove, remove2);
        VM_WARN_ON(vp.anon_vma && adjust && adjust->anon_vma &&
@@ -1016,6 +1027,15 @@ struct vm_area_struct *vma_merge(struct vma_iterator *vmi, struct mm_struct *mm,
        vma_complete(&vp, vmi, mm);
        khugepaged_enter_vma(res, vm_flags);
        return res;
+
+prealloc_fail:
+       if (anon_dup)
+               unlink_anon_vmas(anon_dup);
+
+anon_vma_fail:
+       vma_iter_set(vmi, addr);
+       vma_iter_load(vmi);
+       return NULL;
 }
 
 /*
@@ -3143,13 +3163,13 @@ int vm_brk_flags(unsigned long addr, unsigned long request, unsigned long flags)
        if (!len)
                return 0;
 
-       if (mmap_write_lock_killable(mm))
-               return -EINTR;
-
        /* Until we need other flags, refuse anything except VM_EXEC. */
        if ((flags & (~VM_EXEC)) != 0)
                return -EINVAL;
 
+       if (mmap_write_lock_killable(mm))
+               return -EINTR;
+
        ret = check_brk_limits(addr, len);
        if (ret)
                goto limits_failed;
index 0c5be12f9336367fa4e25f202038ec22d1d79c82..85741403948f55261f953deeb7e30de716533caf 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);
@@ -6475,6 +6475,7 @@ static void break_down_buddy_pages(struct zone *zone, struct page *page,
                        next_page = page;
                        current_buddy = page + size;
                }
+               page = next_page;
 
                if (set_page_guard(zone, current_buddy, high, migratetype))
                        continue;
@@ -6482,7 +6483,6 @@ static void break_down_buddy_pages(struct zone *zone, struct page *page,
                if (current_buddy != target) {
                        add_to_free_list(current_buddy, zone, high, migratetype);
                        set_buddy_order(current_buddy, high);
-                       page = next_page;
                }
        }
 }
index ec7f8e6c9e483a6ff768272d4e89221044974bee..9f795b93cf40f5fa57c3dc38f7f18c4d4020d17d 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 02e62fccc80d4973b6626988eed07ff2482980d1..69595d3418829f08d05829f3ad5166b7421a30fc 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 cd71f9581e672258872eeb369f69ce0c58f4c3da..9bbffe82d65af1ad12087ba0587b57346e9bd42b 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);
 
@@ -895,10 +895,13 @@ void __init setup_kmalloc_cache_index_table(void)
 
 static unsigned int __kmalloc_minalign(void)
 {
+       unsigned int minalign = dma_get_cache_alignment();
+
        if (IS_ENABLED(CONFIG_DMA_BOUNCE_UNALIGNED_KMALLOC) &&
            is_swiotlb_allocated())
-               return ARCH_KMALLOC_MINALIGN;
-       return dma_get_cache_alignment();
+               minalign = ARCH_KMALLOC_MINALIGN;
+
+       return max(minalign, arch_slab_minalign());
 }
 
 void __init
index ef8599d394fd0657b644bdeafaca9b8a781c6d6c..a3fedb3ee0dbd48a3bae9c712bb2602a94dd3fbf 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 412b1409a0d78afbeba2aabc640084e83b39602b..37d2b1cb2ecb4675ace6f1e7558af1e1c0640c68 100644 (file)
@@ -1218,6 +1218,19 @@ bool zswap_store(struct folio *folio)
        if (!zswap_enabled || !tree)
                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
@@ -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);
        }
@@ -1363,8 +1383,8 @@ reject:
 
 shrink:
        pool = zswap_pool_last_get();
-       if (pool)
-               queue_work(shrink_wq, &pool->shrink_work);
+       if (pool && !queue_work(shrink_wq, &pool->shrink_work))
+               zswap_pool_put(pool);
        goto reject;
 }
 
index d3a9843a043d7a0a731c3d8d89396b2bf5513fa0..fdb666607f10ac748a59daf46189cd1cba158c43 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 9d5057cef30a303abf099f1f7eff05afe56abaf3..73470cc3518a71e5a88759a833c6107902669ceb 100644 (file)
@@ -1627,6 +1627,15 @@ struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
                return ERR_PTR(-EOPNOTSUPP);
        }
 
+       /* Reject outgoing connection to device with same BD ADDR against
+        * CVE-2020-26555
+        */
+       if (!bacmp(&hdev->bdaddr, dst)) {
+               bt_dev_dbg(hdev, "Reject connection with same BD_ADDR %pMR\n",
+                          dst);
+               return ERR_PTR(-ECONNREFUSED);
+       }
+
        acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
        if (!acl) {
                acl = hci_conn_add(hdev, ACL_LINK, dst, HCI_ROLE_MASTER);
@@ -2413,34 +2422,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 a5992f1b3c9b74438986f4f3a7289a1e9ddec873..195aea2198a963ebeecaec40f74e03be7e3a70b5 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 35f251041eeb9b58f2ffce8696a3c84a6f5e8355..1e1c9147356c3cf931a7f605fcb1f35e3c7694ae 100644 (file)
@@ -26,6 +26,8 @@
 /* Bluetooth HCI event handling. */
 
 #include <asm/unaligned.h>
+#include <linux/crypto.h>
+#include <crypto/algapi.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
@@ -33,6 +35,7 @@
 
 #include "hci_request.h"
 #include "hci_debugfs.h"
+#include "hci_codec.h"
 #include "a2mp.h"
 #include "amp.h"
 #include "smp.h"
@@ -3267,6 +3270,16 @@ static void hci_conn_request_evt(struct hci_dev *hdev, void *data,
 
        bt_dev_dbg(hdev, "bdaddr %pMR type 0x%x", &ev->bdaddr, ev->link_type);
 
+       /* Reject incoming connection from device with same BD ADDR against
+        * CVE-2020-26555
+        */
+       if (hdev && !bacmp(&hdev->bdaddr, &ev->bdaddr)) {
+               bt_dev_dbg(hdev, "Reject connection with same BD_ADDR %pMR\n",
+                          &ev->bdaddr);
+               hci_reject_conn(hdev, &ev->bdaddr);
+               return;
+       }
+
        mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type,
                                      &flags);
 
@@ -4741,6 +4754,15 @@ static void hci_link_key_notify_evt(struct hci_dev *hdev, void *data,
        if (!conn)
                goto unlock;
 
+       /* Ignore NULL link key against CVE-2020-26555 */
+       if (!crypto_memneq(ev->link_key, ZERO_KEY, HCI_LINK_KEY_SIZE)) {
+               bt_dev_dbg(hdev, "Ignore NULL link key (ZERO KEY) for %pMR",
+                          &ev->bdaddr);
+               hci_disconnect(conn, HCI_ERROR_AUTH_FAILURE);
+               hci_conn_drop(conn);
+               goto unlock;
+       }
+
        hci_conn_hold(conn);
        conn->disc_timeout = HCI_DISCONN_TIMEOUT;
        hci_conn_drop(conn);
@@ -5273,8 +5295,8 @@ static u8 bredr_oob_data_present(struct hci_conn *conn)
                 * available, then do not declare that OOB data is
                 * present.
                 */
-               if (!memcmp(data->rand256, ZERO_KEY, 16) ||
-                   !memcmp(data->hash256, ZERO_KEY, 16))
+               if (!crypto_memneq(data->rand256, ZERO_KEY, 16) ||
+                   !crypto_memneq(data->hash256, ZERO_KEY, 16))
                        return 0x00;
 
                return 0x02;
@@ -5284,8 +5306,8 @@ static u8 bredr_oob_data_present(struct hci_conn *conn)
         * not supported by the hardware, then check that if
         * P-192 data values are present.
         */
-       if (!memcmp(data->rand192, ZERO_KEY, 16) ||
-           !memcmp(data->hash192, ZERO_KEY, 16))
+       if (!crypto_memneq(data->rand192, ZERO_KEY, 16) ||
+           !crypto_memneq(data->hash192, ZERO_KEY, 16))
                return 0x00;
 
        return 0x01;
@@ -5302,7 +5324,7 @@ static void hci_io_capa_request_evt(struct hci_dev *hdev, void *data,
        hci_dev_lock(hdev);
 
        conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
-       if (!conn)
+       if (!conn || !hci_conn_ssp_enabled(conn))
                goto unlock;
 
        hci_conn_hold(conn);
@@ -5549,7 +5571,7 @@ static void hci_simple_pair_complete_evt(struct hci_dev *hdev, void *data,
        hci_dev_lock(hdev);
 
        conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
-       if (!conn)
+       if (!conn || !hci_conn_ssp_enabled(conn))
                goto unlock;
 
        /* Reset the authentication requirement to unknown */
@@ -7020,6 +7042,14 @@ unlock:
        hci_dev_unlock(hdev);
 }
 
+static int hci_iso_term_big_sync(struct hci_dev *hdev, void *data)
+{
+       u8 handle = PTR_UINT(data);
+
+       return hci_le_terminate_big_sync(hdev, handle,
+                                        HCI_ERROR_LOCAL_HOST_TERM);
+}
+
 static void hci_le_create_big_complete_evt(struct hci_dev *hdev, void *data,
                                           struct sk_buff *skb)
 {
@@ -7064,16 +7094,17 @@ static void hci_le_create_big_complete_evt(struct hci_dev *hdev, void *data,
                rcu_read_lock();
        }
 
+       rcu_read_unlock();
+
        if (!ev->status && !i)
                /* If no BISes have been connected for the BIG,
                 * terminate. This is in case all bound connections
                 * have been closed before the BIG creation
                 * has completed.
                 */
-               hci_le_terminate_big_sync(hdev, ev->handle,
-                                         HCI_ERROR_LOCAL_HOST_TERM);
+               hci_cmd_sync_queue(hdev, hci_iso_term_big_sync,
+                                  UINT_PTR(ev->handle), NULL);
 
-       rcu_read_unlock();
        hci_dev_unlock(hdev);
 }
 
index b9c5a98238374cccb4a59fbc3d41c7c465db1afd..0be75cf0efed86c450f5765c8f7b8b2b66c1c608 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 5e4f718073b7ea8b62670df610c6552aa6cd325e..3e7cd330d731aceda4e4ea11d60269cb3d0216ad 100644 (file)
@@ -488,7 +488,8 @@ static struct sk_buff *create_monitor_event(struct hci_dev *hdev, int event)
                ni->type = hdev->dev_type;
                ni->bus = hdev->bus;
                bacpy(&ni->bdaddr, &hdev->bdaddr);
-               memcpy(ni->name, hdev->name, 8);
+               memcpy_and_pad(ni->name, sizeof(ni->name), hdev->name,
+                              strnlen(hdev->name, sizeof(ni->name)), '\0');
 
                opcode = cpu_to_le16(HCI_MON_NEW_INDEX);
                break;
index 9b93653c6197300eb5f4c8d55dd3f38557b1976d..a15ab0b874a9d5cf5d6a2a77f3e93c8408aef83d 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;
@@ -5373,6 +5369,7 @@ int hci_abort_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, u8 reason)
 {
        int err = 0;
        u16 handle = conn->handle;
+       bool disconnect = false;
        struct hci_conn *c;
 
        switch (conn->state) {
@@ -5403,24 +5400,15 @@ int hci_abort_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, u8 reason)
                hci_dev_unlock(hdev);
                return 0;
        case BT_BOUND:
-               hci_dev_lock(hdev);
-               hci_conn_failed(conn, reason);
-               hci_dev_unlock(hdev);
-               return 0;
+               break;
        default:
-               hci_dev_lock(hdev);
-               conn->state = BT_CLOSED;
-               hci_disconn_cfm(conn, reason);
-               hci_conn_del(conn);
-               hci_dev_unlock(hdev);
-               return 0;
+               disconnect = true;
+               break;
        }
 
        hci_dev_lock(hdev);
 
-       /* Check if the connection hasn't been cleanup while waiting
-        * commands to complete.
-        */
+       /* Check if the connection has been cleaned up concurrently */
        c = hci_conn_hash_lookup_handle(hdev, handle);
        if (!c || c != conn) {
                err = 0;
@@ -5432,7 +5420,13 @@ int hci_abort_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, u8 reason)
         * or in case of LE it was still scanning so it can be cleanup
         * safely.
         */
-       hci_conn_failed(conn, reason);
+       if (disconnect) {
+               conn->state = BT_CLOSED;
+               hci_disconn_cfm(conn, reason);
+               hci_conn_del(conn);
+       } else {
+               hci_conn_failed(conn, reason);
+       }
 
 unlock:
        hci_dev_unlock(hdev);
index 16da946f5881bab7d3b3da2ab5046eb372c6953d..71248163ce9a5c76582037e7ad3ac1a3f2f7e008 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 9d7bc8b96b53a911d5add8d0b21736358441755f..7431f89e897b9549a0c35d9431e36b6de2e80022 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 c34a0b0901b07de9e2a3f172527a2bf1c0b6f0b7..c729528b5e85f3a28eff6bd346c18bc11288e7a8 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 15186247b59af52062907cacec994e736ddbc01b..033034d68f1f057349acdd2f127c427195be6b62 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 f02b5d3e47335e18eabf393bcfad2454be13a0c5..d1c6f206f42950963f1f3121cc152424eb6bd210 100644 (file)
@@ -948,21 +948,18 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
        if (!so->bound || so->tx.state == ISOTP_SHUTDOWN)
                return -EADDRNOTAVAIL;
 
-wait_free_buffer:
-       /* we do not support multiple buffers - for now */
-       if (wq_has_sleeper(&so->wait) && (msg->msg_flags & MSG_DONTWAIT))
-               return -EAGAIN;
+       while (cmpxchg(&so->tx.state, ISOTP_IDLE, ISOTP_SENDING) != ISOTP_IDLE) {
+               /* we do not support multiple buffers - for now */
+               if (msg->msg_flags & MSG_DONTWAIT)
+                       return -EAGAIN;
 
-       /* wait for complete transmission of current pdu */
-       err = wait_event_interruptible(so->wait, so->tx.state == ISOTP_IDLE);
-       if (err)
-               goto err_event_drop;
-
-       if (cmpxchg(&so->tx.state, ISOTP_IDLE, ISOTP_SENDING) != ISOTP_IDLE) {
                if (so->tx.state == ISOTP_SHUTDOWN)
                        return -EADDRNOTAVAIL;
 
-               goto wait_free_buffer;
+               /* wait for complete transmission of current pdu */
+               err = wait_event_interruptible(so->wait, so->tx.state == ISOTP_IDLE);
+               if (err)
+                       goto err_event_drop;
        }
 
        /* PDU size > default => try max_pdu_size */
index 10a41cd9c52353bf10db342d885afaa193e8c68e..3c8b78d9c4d1ce4ad98bb11a9373aaa394cbf0d6 100644 (file)
@@ -459,8 +459,8 @@ int ceph_tcp_connect(struct ceph_connection *con)
        set_sock_callbacks(sock, con);
 
        con_sock_state_connecting(con);
-       ret = sock->ops->connect(sock, (struct sockaddr *)&ss, sizeof(ss),
-                                O_NONBLOCK);
+       ret = kernel_connect(sock, (struct sockaddr *)&ss, sizeof(ss),
+                            O_NONBLOCK);
        if (ret == -EINPROGRESS) {
                dout("connect %s EINPROGRESS sk_state = %u\n",
                     ceph_pr_addr(&con->peer_addr),
index ccff2b6ef9583eb2f284111b7294794779f7ba35..9f3f8930c691478ff7b4380a4afcdff0b4a358dd 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>
@@ -345,7 +345,6 @@ int netdev_name_node_alt_create(struct net_device *dev, const char *name)
 static void __netdev_name_node_alt_destroy(struct netdev_name_node *name_node)
 {
        list_del(&name_node->list);
-       netdev_name_node_del(name_node);
        kfree(name_node->name);
        netdev_name_node_free(name_node);
 }
@@ -364,6 +363,8 @@ int netdev_name_node_alt_destroy(struct net_device *dev, const char *name)
        if (name_node == dev->name_node || name_node->dev != dev)
                return -EINVAL;
 
+       netdev_name_node_del(name_node);
+       synchronize_rcu();
        __netdev_name_node_alt_destroy(name_node);
 
        return 0;
@@ -380,6 +381,7 @@ static void netdev_name_node_alt_flush(struct net_device *dev)
 /* Device list insertion */
 static void list_netdevice(struct net_device *dev)
 {
+       struct netdev_name_node *name_node;
        struct net *net = dev_net(dev);
 
        ASSERT_RTNL();
@@ -390,6 +392,10 @@ static void list_netdevice(struct net_device *dev)
        hlist_add_head_rcu(&dev->index_hlist,
                           dev_index_hash(net, dev->ifindex));
        write_unlock(&dev_base_lock);
+
+       netdev_for_each_altname(dev, name_node)
+               netdev_name_node_add(net, name_node);
+
        /* We reserved the ifindex, this can't fail */
        WARN_ON(xa_store(&net->dev_by_index, dev->ifindex, dev, GFP_KERNEL));
 
@@ -401,12 +407,16 @@ static void list_netdevice(struct net_device *dev)
  */
 static void unlist_netdevice(struct net_device *dev, bool lock)
 {
+       struct netdev_name_node *name_node;
        struct net *net = dev_net(dev);
 
        ASSERT_RTNL();
 
        xa_erase(&net->dev_by_index, dev->ifindex);
 
+       netdev_for_each_altname(dev, name_node)
+               netdev_name_node_del(name_node);
+
        /* Unlink dev from the device chain */
        if (lock)
                write_lock(&dev_base_lock);
@@ -1080,13 +1090,14 @@ 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;
 
                for_each_netdev(net, d) {
                        struct netdev_name_node *name_node;
-                       list_for_each_entry(name_node, &d->name_node->list, list) {
+
+                       netdev_for_each_altname(d, name_node) {
                                if (!sscanf(name_node->name, name, &i))
                                        continue;
                                if (i < 0 || i >= max_netdevices)
@@ -1109,7 +1120,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);
@@ -1123,6 +1134,26 @@ static int __dev_alloc_name(struct net *net, const char *name, char *buf)
        return -ENFILE;
 }
 
+static int dev_prep_valid_name(struct net *net, struct net_device *dev,
+                              const char *want_name, char *out_name)
+{
+       int ret;
+
+       if (!dev_valid_name(want_name))
+               return -EINVAL;
+
+       if (strchr(want_name, '%')) {
+               ret = __dev_alloc_name(net, want_name, out_name);
+               return ret < 0 ? ret : 0;
+       } else if (netdev_name_in_use(net, want_name)) {
+               return -EEXIST;
+       } else if (out_name != want_name) {
+               strscpy(out_name, want_name, IFNAMSIZ);
+       }
+
+       return 0;
+}
+
 static int dev_alloc_name_ns(struct net *net,
                             struct net_device *dev,
                             const char *name)
@@ -1160,19 +1191,13 @@ EXPORT_SYMBOL(dev_alloc_name);
 static int dev_get_valid_name(struct net *net, struct net_device *dev,
                              const char *name)
 {
-       BUG_ON(!net);
-
-       if (!dev_valid_name(name))
-               return -EINVAL;
-
-       if (strchr(name, '%'))
-               return dev_alloc_name_ns(net, dev, name);
-       else if (netdev_name_in_use(net, name))
-               return -EEXIST;
-       else if (dev->name != name)
-               strscpy(dev->name, name, IFNAMSIZ);
+       char buf[IFNAMSIZ];
+       int ret;
 
-       return 0;
+       ret = dev_prep_valid_name(net, dev, name, buf);
+       if (ret >= 0)
+               strscpy(dev->name, buf, IFNAMSIZ);
+       return ret;
 }
 
 /**
@@ -3292,15 +3317,19 @@ int skb_checksum_help(struct sk_buff *skb)
 
        offset = skb_checksum_start_offset(skb);
        ret = -EINVAL;
-       if (WARN_ON_ONCE(offset >= skb_headlen(skb))) {
+       if (unlikely(offset >= skb_headlen(skb))) {
                DO_ONCE_LITE(skb_dump, KERN_ERR, skb, false);
+               WARN_ONCE(true, "offset (%d) >= skb_headlen() (%u)\n",
+                         offset, skb_headlen(skb));
                goto out;
        }
        csum = skb_checksum(skb, offset, skb->len - offset, 0);
 
        offset += skb->csum_offset;
-       if (WARN_ON_ONCE(offset + sizeof(__sum16) > skb_headlen(skb))) {
+       if (unlikely(offset + sizeof(__sum16) > skb_headlen(skb))) {
                DO_ONCE_LITE(skb_dump, KERN_ERR, skb, false);
+               WARN_ONCE(true, "offset+2 (%zu) > skb_headlen() (%u)\n",
+                         offset + sizeof(__sum16), skb_headlen(skb));
                goto out;
        }
        ret = skb_ensure_writable(skb, offset + sizeof(__sum16));
@@ -11033,7 +11062,9 @@ EXPORT_SYMBOL(unregister_netdev);
 int __dev_change_net_namespace(struct net_device *dev, struct net *net,
                               const char *pat, int new_ifindex)
 {
+       struct netdev_name_node *name_node;
        struct net *net_old = dev_net(dev);
+       char new_name[IFNAMSIZ] = {};
        int err, new_nsid;
 
        ASSERT_RTNL();
@@ -11060,10 +11091,15 @@ int __dev_change_net_namespace(struct net_device *dev, struct net *net,
                /* We get here if we can't use the current device name */
                if (!pat)
                        goto out;
-               err = dev_get_valid_name(net, dev, pat);
+               err = dev_prep_valid_name(net, dev, pat, new_name);
                if (err < 0)
                        goto out;
        }
+       /* Check that none of the altnames conflicts. */
+       err = -EEXIST;
+       netdev_for_each_altname(dev, name_node)
+               if (netdev_name_in_use(net, name_node->name))
+                       goto out;
 
        /* Check that new_ifindex isn't used yet. */
        if (new_ifindex) {
@@ -11131,6 +11167,9 @@ int __dev_change_net_namespace(struct net_device *dev, struct net *net,
        kobject_uevent(&dev->dev.kobj, KOBJ_ADD);
        netdev_adjacent_add_links(dev);
 
+       if (new_name[0]) /* Rename the netdev to prepared name */
+               strscpy(dev->name, new_name, IFNAMSIZ);
+
        /* Fixup kobjects */
        err = device_rename(&dev->dev, dev->name);
        WARN_ON(err);
index e075e198092cc18eef4d673dcf9950c1f0ad6426..fa2e9c5c4122422e351e9448408abf96914fe431 100644 (file)
@@ -62,6 +62,9 @@ struct netdev_name_node {
 int netdev_get_name(struct net *net, char *name, int ifindex);
 int dev_change_name(struct net_device *dev, const char *newname);
 
+#define netdev_for_each_altname(dev, namenode)                         \
+       list_for_each_entry((namenode), &(dev)->name_node->list, list)
+
 int netdev_name_node_alt_create(struct net_device *dev, const char *name);
 int netdev_name_node_alt_destroy(struct net_device *dev, const char *name);
 
index b3b3af0e78448ad399489f670a642eba12f8020c..272f09251343da46a1b3dbc6b1499c52c83d7725 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 6b76cd103195374f73786b7bb94fb2f4051a3c73..df81c1f0a57047e176b7c7e4809d2dae59ba6be5 100644 (file)
@@ -251,7 +251,8 @@ bool neigh_remove_one(struct neighbour *ndel, struct neigh_table *tbl)
 
 static int neigh_forced_gc(struct neigh_table *tbl)
 {
-       int max_clean = atomic_read(&tbl->gc_entries) - tbl->gc_thresh2;
+       int max_clean = atomic_read(&tbl->gc_entries) -
+                       READ_ONCE(tbl->gc_thresh2);
        unsigned long tref = jiffies - 5 * HZ;
        struct neighbour *n, *tmp;
        int shrunk = 0;
@@ -280,7 +281,7 @@ static int neigh_forced_gc(struct neigh_table *tbl)
                }
        }
 
-       tbl->last_flush = jiffies;
+       WRITE_ONCE(tbl->last_flush, jiffies);
 
        write_unlock_bh(&tbl->lock);
 
@@ -410,7 +411,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
@@ -464,17 +465,17 @@ static struct neighbour *neigh_alloc(struct neigh_table *tbl,
 {
        struct neighbour *n = NULL;
        unsigned long now = jiffies;
-       int entries;
+       int entries, gc_thresh3;
 
        if (exempt_from_gc)
                goto do_alloc;
 
        entries = atomic_inc_return(&tbl->gc_entries) - 1;
-       if (entries >= tbl->gc_thresh3 ||
-           (entries >= tbl->gc_thresh2 &&
-            time_after(now, tbl->last_flush + 5 * HZ))) {
-               if (!neigh_forced_gc(tbl) &&
-                   entries >= tbl->gc_thresh3) {
+       gc_thresh3 = READ_ONCE(tbl->gc_thresh3);
+       if (entries >= gc_thresh3 ||
+           (entries >= READ_ONCE(tbl->gc_thresh2) &&
+            time_after(now, READ_ONCE(tbl->last_flush) + 5 * HZ))) {
+               if (!neigh_forced_gc(tbl) && entries >= gc_thresh3) {
                        net_info_ratelimited("%s: neighbor table overflow!\n",
                                             tbl->id);
                        NEIGH_CACHE_STAT_INC(tbl, table_fulls);
@@ -920,7 +921,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 +933,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)
@@ -955,13 +956,14 @@ static void neigh_periodic_work(struct work_struct *work)
 
        if (time_after(jiffies, tbl->last_rand + 300 * HZ)) {
                struct neigh_parms *p;
-               tbl->last_rand = jiffies;
+
+               WRITE_ONCE(tbl->last_rand, jiffies);
                list_for_each_entry(p, &tbl->parms_list, list)
                        p->reachable_time =
                                neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
        }
 
-       if (atomic_read(&tbl->entries) < tbl->gc_thresh1)
+       if (atomic_read(&tbl->entries) < READ_ONCE(tbl->gc_thresh1))
                goto out;
 
        for (i = 0 ; i < (1 << nht->hash_shift); i++) {
@@ -988,7 +990,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 +1451,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();
@@ -2165,15 +2169,16 @@ static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,
        ndtmsg->ndtm_pad2   = 0;
 
        if (nla_put_string(skb, NDTA_NAME, tbl->id) ||
-           nla_put_msecs(skb, NDTA_GC_INTERVAL, tbl->gc_interval, NDTA_PAD) ||
-           nla_put_u32(skb, NDTA_THRESH1, tbl->gc_thresh1) ||
-           nla_put_u32(skb, NDTA_THRESH2, tbl->gc_thresh2) ||
-           nla_put_u32(skb, NDTA_THRESH3, tbl->gc_thresh3))
+           nla_put_msecs(skb, NDTA_GC_INTERVAL, READ_ONCE(tbl->gc_interval),
+                         NDTA_PAD) ||
+           nla_put_u32(skb, NDTA_THRESH1, READ_ONCE(tbl->gc_thresh1)) ||
+           nla_put_u32(skb, NDTA_THRESH2, READ_ONCE(tbl->gc_thresh2)) ||
+           nla_put_u32(skb, NDTA_THRESH3, READ_ONCE(tbl->gc_thresh3)))
                goto nla_put_failure;
        {
                unsigned long now = jiffies;
-               long flush_delta = now - tbl->last_flush;
-               long rand_delta = now - tbl->last_rand;
+               long flush_delta = now - READ_ONCE(tbl->last_flush);
+               long rand_delta = now - READ_ONCE(tbl->last_rand);
                struct neigh_hash_table *nht;
                struct ndt_config ndc = {
                        .ndtc_key_len           = tbl->key_len,
@@ -2181,7 +2186,7 @@ static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,
                        .ndtc_entries           = atomic_read(&tbl->entries),
                        .ndtc_last_flush        = jiffies_to_msecs(flush_delta),
                        .ndtc_last_rand         = jiffies_to_msecs(rand_delta),
-                       .ndtc_proxy_qlen        = tbl->proxy_queue.qlen,
+                       .ndtc_proxy_qlen        = READ_ONCE(tbl->proxy_queue.qlen),
                };
 
                rcu_read_lock();
@@ -2204,17 +2209,17 @@ static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,
                        struct neigh_statistics *st;
 
                        st = per_cpu_ptr(tbl->stats, cpu);
-                       ndst.ndts_allocs                += st->allocs;
-                       ndst.ndts_destroys              += st->destroys;
-                       ndst.ndts_hash_grows            += st->hash_grows;
-                       ndst.ndts_res_failed            += st->res_failed;
-                       ndst.ndts_lookups               += st->lookups;
-                       ndst.ndts_hits                  += st->hits;
-                       ndst.ndts_rcv_probes_mcast      += st->rcv_probes_mcast;
-                       ndst.ndts_rcv_probes_ucast      += st->rcv_probes_ucast;
-                       ndst.ndts_periodic_gc_runs      += st->periodic_gc_runs;
-                       ndst.ndts_forced_gc_runs        += st->forced_gc_runs;
-                       ndst.ndts_table_fulls           += st->table_fulls;
+                       ndst.ndts_allocs                += READ_ONCE(st->allocs);
+                       ndst.ndts_destroys              += READ_ONCE(st->destroys);
+                       ndst.ndts_hash_grows            += READ_ONCE(st->hash_grows);
+                       ndst.ndts_res_failed            += READ_ONCE(st->res_failed);
+                       ndst.ndts_lookups               += READ_ONCE(st->lookups);
+                       ndst.ndts_hits                  += READ_ONCE(st->hits);
+                       ndst.ndts_rcv_probes_mcast      += READ_ONCE(st->rcv_probes_mcast);
+                       ndst.ndts_rcv_probes_ucast      += READ_ONCE(st->rcv_probes_ucast);
+                       ndst.ndts_periodic_gc_runs      += READ_ONCE(st->periodic_gc_runs);
+                       ndst.ndts_forced_gc_runs        += READ_ONCE(st->forced_gc_runs);
+                       ndst.ndts_table_fulls           += READ_ONCE(st->table_fulls);
                }
 
                if (nla_put_64bit(skb, NDTA_STATS, sizeof(ndst), &ndst,
@@ -2443,16 +2448,16 @@ static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh,
                goto errout_tbl_lock;
 
        if (tb[NDTA_THRESH1])
-               tbl->gc_thresh1 = nla_get_u32(tb[NDTA_THRESH1]);
+               WRITE_ONCE(tbl->gc_thresh1, nla_get_u32(tb[NDTA_THRESH1]));
 
        if (tb[NDTA_THRESH2])
-               tbl->gc_thresh2 = nla_get_u32(tb[NDTA_THRESH2]);
+               WRITE_ONCE(tbl->gc_thresh2, nla_get_u32(tb[NDTA_THRESH2]));
 
        if (tb[NDTA_THRESH3])
-               tbl->gc_thresh3 = nla_get_u32(tb[NDTA_THRESH3]);
+               WRITE_ONCE(tbl->gc_thresh3, nla_get_u32(tb[NDTA_THRESH3]));
 
        if (tb[NDTA_GC_INTERVAL])
-               tbl->gc_interval = nla_get_msecs(tb[NDTA_GC_INTERVAL]);
+               WRITE_ONCE(tbl->gc_interval, nla_get_msecs(tb[NDTA_GC_INTERVAL]));
 
        err = 0;
 
@@ -3153,7 +3158,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 f56b8d69701475683561032d992c97585320af63..4d1696677c48c82f33cfa2ddf1b823429c5d9155 100644 (file)
@@ -669,19 +669,19 @@ static int pktgen_if_show(struct seq_file *seq, void *v)
        seq_puts(seq, "     Flags: ");
 
        for (i = 0; i < NR_PKT_FLAGS; i++) {
-               if (i == F_FLOW_SEQ)
+               if (i == FLOW_SEQ_SHIFT)
                        if (!pkt_dev->cflows)
                                continue;
 
-               if (pkt_dev->flags & (1 << i))
+               if (pkt_dev->flags & (1 << i)) {
                        seq_printf(seq, "%s  ", pkt_flag_names[i]);
-               else if (i == F_FLOW_SEQ)
-                       seq_puts(seq, "FLOW_RND  ");
-
 #ifdef CONFIG_XFRM
-               if (i == F_IPSEC && pkt_dev->spi)
-                       seq_printf(seq, "spi:%u", pkt_dev->spi);
+                       if (i == IPSEC_SHIFT && pkt_dev->spi)
+                               seq_printf(seq, "spi:%u  ", pkt_dev->spi);
 #endif
+               } else if (i == FLOW_SEQ_SHIFT) {
+                       seq_puts(seq, "FLOW_RND  ");
+               }
        }
 
        seq_puts(seq, "\n");
index 4a2ec33bfb517bdea7398e1dd8497d9075718c69..53c377d054f036a45daf9cc7f5679ba1f7cebf4c 100644 (file)
@@ -5503,13 +5503,11 @@ static unsigned int
 rtnl_offload_xstats_get_size_hw_s_info_one(const struct net_device *dev,
                                           enum netdev_offload_xstats_type type)
 {
-       bool enabled = netdev_offload_xstats_enabled(dev, type);
-
        return nla_total_size(0) +
                /* IFLA_OFFLOAD_XSTATS_HW_S_INFO_REQUEST */
                nla_total_size(sizeof(u8)) +
                /* IFLA_OFFLOAD_XSTATS_HW_S_INFO_USED */
-               (enabled ? nla_total_size(sizeof(u8)) : 0) +
+               nla_total_size(sizeof(u8)) +
                0;
 }
 
index cb11750b1df5fc49043333a2d89cc6d18dba06b9..4292c2ed18286683bd2dc536b9d0d2dec5866fba 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 f5c4e47df16505571d575ff367b31d9ef6998bd6..96fbcb9bbb30a51738c7121eef8735de1eb12d78 100644 (file)
@@ -117,7 +117,7 @@ EXPORT_SYMBOL(sk_stream_wait_close);
  */
 int sk_stream_wait_memory(struct sock *sk, long *timeo_p)
 {
-       int err = 0;
+       int ret, err = 0;
        long vm_wait = 0;
        long current_timeo = *timeo_p;
        DEFINE_WAIT_FUNC(wait, woken_wake_function);
@@ -142,11 +142,13 @@ int sk_stream_wait_memory(struct sock *sk, long *timeo_p)
 
                set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
                sk->sk_write_pending++;
-               sk_wait_event(sk, &current_timeo, READ_ONCE(sk->sk_err) ||
-                                                 (READ_ONCE(sk->sk_shutdown) & SEND_SHUTDOWN) ||
-                                                 (sk_stream_memory_free(sk) &&
-                                                 !vm_wait), &wait);
+               ret = sk_wait_event(sk, &current_timeo, READ_ONCE(sk->sk_err) ||
+                                   (READ_ONCE(sk->sk_shutdown) & SEND_SHUTDOWN) ||
+                                   (sk_stream_memory_free(sk) && !vm_wait),
+                                   &wait);
                sk->sk_write_pending--;
+               if (ret < 0)
+                       goto do_error;
 
                if (vm_wait) {
                        vm_wait -= current_timeo;
index 8f56e8723c7386c9f9344f1376823bfd0077c8c2..69453b936bd557c77a790a27ff64cc91e5a58296 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 33f6ccf6ba77b9bcc24054b09857aaee4bb71acf..c693a570682fba2ad93c7bceb8788bd9d51a0b41 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 638cad8d5c6542bcb58aa1184f3004374f2bd3db..51e6e81e31bb8ac93a404402a12196e3aae1b00d 100644 (file)
@@ -58,7 +58,6 @@ struct devlink_health_reporter {
        struct devlink *devlink;
        struct devlink_port *devlink_port;
        struct devlink_fmsg *dump_fmsg;
-       struct mutex dump_lock; /* lock parallel read/write from dump buffers */
        u64 graceful_period;
        bool auto_recover;
        bool auto_dump;
@@ -125,7 +124,6 @@ __devlink_health_reporter_create(struct devlink *devlink,
        reporter->graceful_period = graceful_period;
        reporter->auto_recover = !!ops->recover;
        reporter->auto_dump = !!ops->dump;
-       mutex_init(&reporter->dump_lock);
        return reporter;
 }
 
@@ -226,7 +224,6 @@ EXPORT_SYMBOL_GPL(devlink_health_reporter_create);
 static void
 devlink_health_reporter_free(struct devlink_health_reporter *reporter)
 {
-       mutex_destroy(&reporter->dump_lock);
        if (reporter->dump_fmsg)
                devlink_fmsg_free(reporter->dump_fmsg);
        kfree(reporter);
@@ -625,10 +622,10 @@ int devlink_health_report(struct devlink_health_reporter *reporter,
        }
 
        if (reporter->auto_dump) {
-               mutex_lock(&reporter->dump_lock);
+               devl_lock(devlink);
                /* store current dump of current error, for later analysis */
                devlink_health_do_dump(reporter, priv_ctx, NULL);
-               mutex_unlock(&reporter->dump_lock);
+               devl_unlock(devlink);
        }
 
        if (!reporter->auto_recover)
@@ -1262,7 +1259,7 @@ out:
 }
 
 static struct devlink_health_reporter *
-devlink_health_reporter_get_from_cb(struct netlink_callback *cb)
+devlink_health_reporter_get_from_cb_lock(struct netlink_callback *cb)
 {
        const struct genl_info *info = genl_info_dump(cb);
        struct devlink_health_reporter *reporter;
@@ -1272,10 +1269,12 @@ devlink_health_reporter_get_from_cb(struct netlink_callback *cb)
        devlink = devlink_get_from_attrs_lock(sock_net(cb->skb->sk), attrs);
        if (IS_ERR(devlink))
                return NULL;
-       devl_unlock(devlink);
 
        reporter = devlink_health_reporter_get_from_attrs(devlink, attrs);
-       devlink_put(devlink);
+       if (!reporter) {
+               devl_unlock(devlink);
+               devlink_put(devlink);
+       }
        return reporter;
 }
 
@@ -1284,16 +1283,20 @@ int devlink_nl_cmd_health_reporter_dump_get_dumpit(struct sk_buff *skb,
 {
        struct devlink_nl_dump_state *state = devlink_dump_state(cb);
        struct devlink_health_reporter *reporter;
+       struct devlink *devlink;
        int err;
 
-       reporter = devlink_health_reporter_get_from_cb(cb);
+       reporter = devlink_health_reporter_get_from_cb_lock(cb);
        if (!reporter)
                return -EINVAL;
 
-       if (!reporter->ops->dump)
+       devlink = reporter->devlink;
+       if (!reporter->ops->dump) {
+               devl_unlock(devlink);
+               devlink_put(devlink);
                return -EOPNOTSUPP;
+       }
 
-       mutex_lock(&reporter->dump_lock);
        if (!state->idx) {
                err = devlink_health_do_dump(reporter, NULL, cb->extack);
                if (err)
@@ -1309,7 +1312,8 @@ int devlink_nl_cmd_health_reporter_dump_get_dumpit(struct sk_buff *skb,
        err = devlink_fmsg_dumpit(reporter->dump_fmsg, skb, cb,
                                  DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET);
 unlock:
-       mutex_unlock(&reporter->dump_lock);
+       devl_unlock(devlink);
+       devlink_put(devlink);
        return err;
 }
 
@@ -1326,9 +1330,7 @@ int devlink_nl_cmd_health_reporter_dump_clear_doit(struct sk_buff *skb,
        if (!reporter->ops->dump)
                return -EOPNOTSUPP;
 
-       mutex_lock(&reporter->dump_lock);
        devlink_health_dump_clear(reporter);
-       mutex_unlock(&reporter->dump_lock);
        return 0;
 }
 
index b238a1afe9aeddf094046ba056cb8cd6a1660e77..b1e2e3b5027fc7b9a26c9bbdf61006b771b457a3 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 6d37bab35c8fcc42e77d1fc081a87d61658751c3..16ed7bfd29e4fbf39e204278950834b9e69b9f97 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 d0bc1dd8e65a8201751fddcc2356da89cd2c65e7..80c7302692c74cb52d429392cd57ae283a91f4f0 100644 (file)
@@ -87,29 +87,6 @@ struct nlmsghdr *handshake_genl_put(struct sk_buff *msg,
 }
 EXPORT_SYMBOL(handshake_genl_put);
 
-/*
- * dup() a kernel socket for use as a user space file descriptor
- * in the current process. The kernel socket must have an
- * instatiated struct file.
- *
- * Implicit argument: "current()"
- */
-static int handshake_dup(struct socket *sock)
-{
-       struct file *file;
-       int newfd;
-
-       file = get_file(sock->file);
-       newfd = get_unused_fd_flags(O_CLOEXEC);
-       if (newfd < 0) {
-               fput(file);
-               return newfd;
-       }
-
-       fd_install(newfd, file);
-       return newfd;
-}
-
 int handshake_nl_accept_doit(struct sk_buff *skb, struct genl_info *info)
 {
        struct net *net = sock_net(skb->sk);
@@ -133,17 +110,20 @@ int handshake_nl_accept_doit(struct sk_buff *skb, struct genl_info *info)
                goto out_status;
 
        sock = req->hr_sk->sk_socket;
-       fd = handshake_dup(sock);
+       fd = get_unused_fd_flags(O_CLOEXEC);
        if (fd < 0) {
                err = fd;
                goto out_complete;
        }
+
        err = req->hr_proto->hp_accept(req, info, fd);
        if (err) {
-               fput(sock->file);
+               put_unused_fd(fd);
                goto out_complete;
        }
 
+       fd_install(fd, get_file(sock->file));
+
        trace_handshake_cmd_accept(net, req, req->hr_sk, fd);
        return 0;
 
index b77f1189d19d1ff5dc76f4a7345efc7a65918399..6d14d935ee828d025d40ea237884d244cb56eb8e 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 6851e33df7d14607034807c64ebe3a0b860af7f1..18e01791ad799d9562923d4359df2aafab2abd08 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 3d2e30e204735604dfa44f27cd08a02aedcfb921..2713c9b06c4c0fbc37cece8d4929e0877b7c8f1d 100644 (file)
@@ -597,7 +597,6 @@ static long inet_wait_for_connect(struct sock *sk, long timeo, int writebias)
 
        add_wait_queue(sk_sleep(sk), &wait);
        sk->sk_write_pending += writebias;
-       sk->sk_wait_pending++;
 
        /* Basic assumption: if someone sets sk->sk_err, he _must_
         * change state of the socket from TCP_SYN_*.
@@ -613,7 +612,6 @@ static long inet_wait_for_connect(struct sock *sk, long timeo, int writebias)
        }
        remove_wait_queue(sk_sleep(sk), &wait);
        sk->sk_write_pending -= writebias;
-       sk->sk_wait_pending--;
        return timeo;
 }
 
@@ -642,6 +640,7 @@ int __inet_stream_connect(struct socket *sock, struct sockaddr *uaddr,
                        return -EINVAL;
 
                if (uaddr->sa_family == AF_UNSPEC) {
+                       sk->sk_disconnects++;
                        err = sk->sk_prot->disconnect(sk, flags);
                        sock->state = err ? SS_DISCONNECTING : SS_UNCONNECTED;
                        goto out;
@@ -696,6 +695,7 @@ int __inet_stream_connect(struct socket *sock, struct sockaddr *uaddr,
                int writebias = (sk->sk_protocol == IPPROTO_TCP) &&
                                tcp_sk(sk)->fastopen_req &&
                                tcp_sk(sk)->fastopen_req->data ? 1 : 0;
+               int dis = sk->sk_disconnects;
 
                /* Error code is set above */
                if (!timeo || !inet_wait_for_connect(sk, timeo, writebias))
@@ -704,6 +704,11 @@ int __inet_stream_connect(struct socket *sock, struct sockaddr *uaddr,
                err = sock_intr_errno(timeo);
                if (signal_pending(current))
                        goto out;
+
+               if (dis != sk->sk_disconnects) {
+                       err = -EPIPE;
+                       goto out;
+               }
        }
 
        /* Connection was closed by RST, timeout, ICMP error
@@ -725,6 +730,7 @@ out:
 sock_error:
        err = sock_error(sk) ? : -ECONNABORTED;
        sock->state = SS_UNCONNECTED;
+       sk->sk_disconnects++;
        if (sk->sk_prot->disconnect(sk, flags))
                sock->state = SS_DISCONNECTING;
        goto out;
index 2be2d49225573908ae3911208093be63500f60ef..4ccfc104f13a517ec15e5b609502708c289e3b57 100644 (file)
@@ -732,7 +732,9 @@ static inline int esp_remove_trailer(struct sk_buff *skb)
                skb->csum = csum_block_sub(skb->csum, csumdiff,
                                           skb->len - trimlen);
        }
-       pskb_trim(skb, skb->len - trimlen);
+       ret = pskb_trim(skb, skb->len - trimlen);
+       if (unlikely(ret))
+               return ret;
 
        ret = nexthdr[1];
 
@@ -784,7 +786,7 @@ int esp_input_done2(struct sk_buff *skb, int err)
 
                /*
                 * 1) if the NAT-T peer's IP or port changed then
-                *    advertize the change to the keying daemon.
+                *    advertise the change to the keying daemon.
                 *    This is an inbound SA, so just compare
                 *    SRC ports.
                 */
index eafa4a033515782b4ade9a81ec12cb22f5e51e35..5eb1b8d302bbd1c408c4999636b6cf4b81a0ad7e 100644 (file)
@@ -1325,15 +1325,18 @@ __be32 fib_info_update_nhc_saddr(struct net *net, struct fib_nh_common *nhc,
                                 unsigned char scope)
 {
        struct fib_nh *nh;
+       __be32 saddr;
 
        if (nhc->nhc_family != AF_INET)
                return inet_select_addr(nhc->nhc_dev, 0, scope);
 
        nh = container_of(nhc, struct fib_nh, nh_common);
-       nh->nh_saddr = inet_select_addr(nh->fib_nh_dev, nh->fib_nh_gw4, scope);
-       nh->nh_saddr_genid = atomic_read(&net->ipv4.dev_addr_genid);
+       saddr = inet_select_addr(nh->fib_nh_dev, nh->fib_nh_gw4, scope);
 
-       return nh->nh_saddr;
+       WRITE_ONCE(nh->nh_saddr, saddr);
+       WRITE_ONCE(nh->nh_saddr_genid, atomic_read(&net->ipv4.dev_addr_genid));
+
+       return saddr;
 }
 
 __be32 fib_result_prefsrc(struct net *net, struct fib_result *res)
@@ -1347,8 +1350,9 @@ __be32 fib_result_prefsrc(struct net *net, struct fib_result *res)
                struct fib_nh *nh;
 
                nh = container_of(nhc, struct fib_nh, nh_common);
-               if (nh->nh_saddr_genid == atomic_read(&net->ipv4.dev_addr_genid))
-                       return nh->nh_saddr;
+               if (READ_ONCE(nh->nh_saddr_genid) ==
+                   atomic_read(&net->ipv4.dev_addr_genid))
+                       return READ_ONCE(nh->nh_saddr);
        }
 
        return fib_info_update_nhc_saddr(net, nhc, res->fi->fib_scope);
@@ -1887,6 +1891,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 d13fb9e76b9718c674b82ea9069f98fb29f06425..9bdfdab906fe00cb048718eef932892181723a40 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 aeebe881668996057d1495c84eee0f0b644b7ad0..394a498c28232213c1c3fb6f98af922d61a25418 100644 (file)
@@ -1145,7 +1145,6 @@ struct sock *inet_csk_clone_lock(const struct sock *sk,
        if (newsk) {
                struct inet_connection_sock *newicsk = inet_csk(newsk);
 
-               newsk->sk_wait_pending = 0;
                inet_sk_set_state(newsk, TCP_SYN_RECV);
                newicsk->icsk_bind_hash = NULL;
                newicsk->icsk_bind2_hash = NULL;
index c32f5e28758be76d72cc33c754a10303e0905dbc..598c1b114d2c2256fa06735b823b38cef70a8a34 100644 (file)
@@ -149,8 +149,14 @@ static bool inet_bind2_bucket_addr_match(const struct inet_bind2_bucket *tb2,
                                         const struct sock *sk)
 {
 #if IS_ENABLED(CONFIG_IPV6)
-       if (sk->sk_family != tb2->family)
-               return false;
+       if (sk->sk_family != tb2->family) {
+               if (sk->sk_family == AF_INET)
+                       return ipv6_addr_v4mapped(&tb2->v6_rcv_saddr) &&
+                               tb2->v6_rcv_saddr.s6_addr32[3] == sk->sk_rcv_saddr;
+
+               return ipv6_addr_v4mapped(&sk->sk_v6_rcv_saddr) &&
+                       sk->sk_v6_rcv_saddr.s6_addr32[3] == tb2->rcv_saddr;
+       }
 
        if (sk->sk_family == AF_INET6)
                return ipv6_addr_equal(&tb2->v6_rcv_saddr,
@@ -819,19 +825,7 @@ static bool inet_bind2_bucket_match(const struct inet_bind2_bucket *tb,
            tb->l3mdev != l3mdev)
                return false;
 
-#if IS_ENABLED(CONFIG_IPV6)
-       if (sk->sk_family != tb->family) {
-               if (sk->sk_family == AF_INET)
-                       return ipv6_addr_v4mapped(&tb->v6_rcv_saddr) &&
-                               tb->v6_rcv_saddr.s6_addr32[3] == sk->sk_rcv_saddr;
-
-               return false;
-       }
-
-       if (sk->sk_family == AF_INET6)
-               return ipv6_addr_equal(&tb->v6_rcv_saddr, &sk->sk_v6_rcv_saddr);
-#endif
-       return tb->rcv_saddr == sk->sk_rcv_saddr;
+       return inet_bind2_bucket_addr_match(tb, sk);
 }
 
 bool inet_bind2_bucket_match_addr_any(const struct inet_bind2_bucket *tb, const struct net *net,
index 66f419e7f9a7f3cab5328abb8c374686dccd2f19..b214b5a2e045fec0513f4a7db69d048e355c52ae 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 0c3040a63ebdb15be2c60532e2bdfc3d0fc51a9c..3d3a24f795734eecd60fc761f25f48b7a27714d4 100644 (file)
@@ -831,7 +831,9 @@ ssize_t tcp_splice_read(struct socket *sock, loff_t *ppos,
                         */
                        if (!skb_queue_empty(&sk->sk_receive_queue))
                                break;
-                       sk_wait_data(sk, &timeo, NULL);
+                       ret = sk_wait_data(sk, &timeo, NULL);
+                       if (ret < 0)
+                               break;
                        if (signal_pending(current)) {
                                ret = sock_intr_errno(timeo);
                                break;
@@ -925,10 +927,11 @@ int tcp_send_mss(struct sock *sk, int *size_goal, int flags)
        return mss_now;
 }
 
-/* In some cases, both sendmsg() could have added an skb to the write queue,
- * but failed adding payload on it.  We need to remove it to consume less
+/* In some cases, sendmsg() could have added an skb to the write queue,
+ * but failed adding payload on it. We need to remove it to consume less
  * memory, but more importantly be able to generate EPOLLOUT for Edge Trigger
- * epoll() users.
+ * epoll() users. Another reason is that tcp_write_xmit() does not like
+ * finding an empty skb in the write queue.
  */
 void tcp_remove_empty_skb(struct sock *sk)
 {
@@ -1287,6 +1290,7 @@ new_segment:
 
 wait_for_space:
                set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
+               tcp_remove_empty_skb(sk);
                if (copied)
                        tcp_push(sk, flags & ~MSG_MORE, mss_now,
                                 TCP_NAGLE_PUSH, size_goal);
@@ -1621,16 +1625,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 +1644,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;
 }
@@ -2448,7 +2446,11 @@ static int tcp_recvmsg_locked(struct sock *sk, struct msghdr *msg, size_t len,
                        __sk_flush_backlog(sk);
                } else {
                        tcp_cleanup_rbuf(sk, copied);
-                       sk_wait_data(sk, &timeo, last);
+                       err = sk_wait_data(sk, &timeo, last);
+                       if (err < 0) {
+                               err = copied ? : err;
+                               goto out;
+                       }
                }
 
                if ((flags & MSG_PEEK) &&
@@ -2972,12 +2974,6 @@ int tcp_disconnect(struct sock *sk, int flags)
        int old_state = sk->sk_state;
        u32 seq;
 
-       /* Deny disconnect if other threads are blocked in sk_wait_event()
-        * or inet_wait_for_connect().
-        */
-       if (sk->sk_wait_pending)
-               return -EBUSY;
-
        if (old_state != TCP_CLOSE)
                tcp_set_state(sk, TCP_CLOSE);
 
index 81f0dff69e0b69bcc03bd932dcc42a8578939ecb..53b0d62fd2c2dbfcdd3b65bdc9f2b839a6f51687 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;
@@ -306,15 +307,22 @@ msg_bytes_ready:
                }
 
                data = tcp_msg_wait_data(sk, psock, timeo);
+               if (data < 0) {
+                       copied = data;
+                       goto unlock;
+               }
                if (data && !sk_psock_queue_empty(psock))
                        goto 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);
+
+unlock:
        release_sock(sk);
        sk_psock_put(sk, psock);
        return copied;
@@ -349,6 +357,10 @@ msg_bytes_ready:
 
                timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
                data = tcp_msg_wait_data(sk, psock, timeo);
+               if (data < 0) {
+                       ret = data;
+                       goto unlock;
+               }
                if (data) {
                        if (!sk_psock_queue_empty(psock))
                                goto msg_bytes_ready;
@@ -359,6 +371,8 @@ msg_bytes_ready:
                copied = -EAGAIN;
        }
        ret = copied;
+
+unlock:
        release_sock(sk);
        sk_psock_put(sk, psock);
        return ret;
index 06fe1cf645d5a386331548484de2beb68e846404..804821d6bd4d47bdc9e58c6afcd6fc77295b0da6 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.
@@ -2194,16 +2207,17 @@ void tcp_enter_loss(struct sock *sk)
  * restore sanity to the SACK scoreboard. If the apparent reneging
  * persists until this RTO then we'll clear the SACK scoreboard.
  */
-static bool tcp_check_sack_reneging(struct sock *sk, int flag)
+static bool tcp_check_sack_reneging(struct sock *sk, int *ack_flag)
 {
-       if (flag & FLAG_SACK_RENEGING &&
-           flag & FLAG_SND_UNA_ADVANCED) {
+       if (*ack_flag & FLAG_SACK_RENEGING &&
+           *ack_flag & FLAG_SND_UNA_ADVANCED) {
                struct tcp_sock *tp = tcp_sk(sk);
                unsigned long delay = max(usecs_to_jiffies(tp->srtt_us >> 4),
                                          msecs_to_jiffies(10));
 
                inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
                                          delay, TCP_RTO_MAX);
+               *ack_flag &= ~FLAG_SET_XMIT_TIMER;
                return true;
        }
        return false;
@@ -2973,7 +2987,7 @@ static void tcp_fastretrans_alert(struct sock *sk, const u32 prior_snd_una,
                tp->prior_ssthresh = 0;
 
        /* B. In all the states check for reneging SACKs. */
-       if (tcp_check_sack_reneging(sk, flag))
+       if (tcp_check_sack_reneging(sk, ack_flag))
                return;
 
        /* C. Check consistency of the current state. */
index 27140e5cdc060ddcdc8973759f68ed612a60617a..4167e8a48b60a13f67c2012b1f278216b673b13e 100644 (file)
@@ -1869,6 +1869,7 @@ bool tcp_add_backlog(struct sock *sk, struct sk_buff *skb,
 #ifdef CONFIG_TLS_DEVICE
            tail->decrypted != skb->decrypted ||
 #endif
+           !mptcp_skb_can_collapse(tail, skb) ||
            thtail->doff != th->doff ||
            memcmp(thtail + 1, th + 1, hdrlen - sizeof(*th)))
                goto no_coalesce;
index ccfc8bbf745586cd23dcf02d755d6981dc92742e..f0723460753c5d035022ce705a8ba533ce9ab2b8 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);
@@ -2457,6 +2456,7 @@ static int tcp_mtu_probe(struct sock *sk)
 
        /* build the payload, and be prepared to abort if this fails. */
        if (tcp_clone_payload(sk, nskb, probe_size)) {
+               tcp_skb_tsorted_anchor_cleanup(nskb);
                consume_skb(nskb);
                return -1;
        }
@@ -2542,6 +2542,18 @@ static bool tcp_pacing_check(struct sock *sk)
        return true;
 }
 
+static bool tcp_rtx_queue_empty_or_single_skb(const struct sock *sk)
+{
+       const struct rb_node *node = sk->tcp_rtx_queue.rb_node;
+
+       /* No skb in the rtx queue. */
+       if (!node)
+               return true;
+
+       /* Only one skb in rtx queue. */
+       return !node->rb_left && !node->rb_right;
+}
+
 /* TCP Small Queues :
  * Control number of packets in qdisc/devices to two packets / or ~1 ms.
  * (These limits are doubled for retransmits)
@@ -2579,12 +2591,12 @@ static bool tcp_small_queue_check(struct sock *sk, const struct sk_buff *skb,
                limit += extra_bytes;
        }
        if (refcount_read(&sk->sk_wmem_alloc) > limit) {
-               /* Always send skb if rtx queue is empty.
+               /* Always send skb if rtx queue is empty or has one skb.
                 * No need to wait for TX completion to call us back,
                 * after softirq/tasklet schedule.
                 * This helps when TX completions are delayed too much.
                 */
-               if (tcp_rtx_queue_empty(sk))
+               if (tcp_rtx_queue_empty_or_single_skb(sk))
                        return false;
 
                set_bit(TSQ_THROTTLED, &sk->sk_tsq_flags);
@@ -2788,7 +2800,7 @@ bool tcp_schedule_loss_probe(struct sock *sk, bool advancing_rto)
 {
        struct inet_connection_sock *icsk = inet_csk(sk);
        struct tcp_sock *tp = tcp_sk(sk);
-       u32 timeout, rto_delta_us;
+       u32 timeout, timeout_us, rto_delta_us;
        int early_retrans;
 
        /* Don't do any loss probe on a Fast Open connection before 3WHS
@@ -2812,11 +2824,12 @@ bool tcp_schedule_loss_probe(struct sock *sk, bool advancing_rto)
         * sample is available then probe after TCP_TIMEOUT_INIT.
         */
        if (tp->srtt_us) {
-               timeout = usecs_to_jiffies(tp->srtt_us >> 2);
+               timeout_us = tp->srtt_us >> 2;
                if (tp->packets_out == 1)
-                       timeout += TCP_RTO_MIN;
+                       timeout_us += tcp_rto_min_us(sk);
                else
-                       timeout += TCP_TIMEOUT_MIN;
+                       timeout_us += TCP_TIMEOUT_MIN_US;
+               timeout = usecs_to_jiffies(timeout_us);
        } else {
                timeout = TCP_TIMEOUT_INIT;
        }
index acf4869c5d3b568227aca71d95a765493e452a85..bba10110fbbc166914243614b306a18ab1a93a88 100644 (file)
@@ -104,7 +104,7 @@ bool tcp_rack_mark_lost(struct sock *sk)
        tp->rack.advanced = 0;
        tcp_rack_detect_loss(sk, &timeout);
        if (timeout) {
-               timeout = usecs_to_jiffies(timeout) + TCP_TIMEOUT_MIN;
+               timeout = usecs_to_jiffies(timeout + TCP_TIMEOUT_MIN_US);
                inet_csk_reset_xmit_timer(sk, ICSK_TIME_REO_TIMEOUT,
                                          timeout, inet_csk(sk)->icsk_rto);
        }
index fddd0cbdede15b1927d878b09a71a421f2140dac..2cc1a45742d823a793d95140910942fb83e7f331 100644 (file)
@@ -770,7 +770,9 @@ static inline int esp_remove_trailer(struct sk_buff *skb)
                skb->csum = csum_block_sub(skb->csum, csumdiff,
                                           skb->len - trimlen);
        }
-       pskb_trim(skb, skb->len - trimlen);
+       ret = pskb_trim(skb, skb->len - trimlen);
+       if (unlikely(ret))
+               return ret;
 
        ret = nexthdr[1];
 
@@ -831,7 +833,7 @@ int esp6_input_done2(struct sk_buff *skb, int err)
 
                /*
                 * 1) if the NAT-T peer's IP or port changed then
-                *    advertize the change to the keying daemon.
+                *    advertise the change to the keying daemon.
                 *    This is an inbound SA, so just compare
                 *    SRC ports.
                 */
index 3a88545a265d6bd064ecc41d33c9541a75fe0f4d..44b6949d72b2216b4d3934cd302bfff94ecae23d 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 41a680c76d2ea56ed4c6bdb7556005888e892e39..42fb6996b0777a9d0db3721dd566697f96d12041 100644 (file)
@@ -117,10 +117,10 @@ static void xfrm6_dst_destroy(struct dst_entry *dst)
 {
        struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
 
-       if (likely(xdst->u.rt6.rt6i_idev))
-               in6_dev_put(xdst->u.rt6.rt6i_idev);
        dst_destroy_metrics_generic(dst);
        rt6_uncached_list_del(&xdst->u.rt6);
+       if (likely(xdst->u.rt6.rt6i_idev))
+               in6_dev_put(xdst->u.rt6.rt6i_idev);
        xfrm_dst_destroy(xdst);
 }
 
index ed8ebb6f59097ac18bb284d1c48f9e801e9a92c2..11f3d375cec0003338c15e1e19cf8e4c99127958 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 45e7a5d9c7d94206f1af8f5ecf142d156deb6797..0e3a1753a51c6dcc904b004ec15aa2f9f2e1a413 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 e1900077bc4b94fbb52d112d837319cc1e3eceee..5542c93edfba0b0bdb9d167fbab633c103697cde 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 06bd406846d2984c3acbdadcaf1cc9c465678b66..98ef1fe1226e72f8e19f785f8489537635c39799 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 13050dc9321f197d6aaa1c55235302bfa2ecf6f1..a2db0585dce0d4a6841f8551712efaf605d3d06e 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,8 +911,7 @@ 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;
+               ret = -EALREADY;
                goto out;
        }
 
@@ -930,7 +936,10 @@ int ieee80211_key_link(struct ieee80211_key *key,
                ieee80211_key_free(key, delay_tailroom);
        }
 
+       key = NULL;
+
  out:
+       ieee80211_key_free_unused(key);
        mutex_unlock(&sdata->local->key_mtx);
 
        return ret;
index af8c5fc2db1497eb9f0fcfeb59491080a74f43ec..e31c312c124a1a9f81bc75779dcd8a5317f51b5a 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 f3d5bb0a59f1022ff7b48e5888fbb092dbf0a928..a1e526419e9d25ba4e95b53edbfdc94217e09851 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 f93eb38ae0b8dbc819c88290c643e885ad57f955..0c9198997482bcfa41b9b4781d3419d7e4b5bb53 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 e751cda5eef69e4a8842ffa7a4706f9a8c30d8a9..8f6b6f56b65b4353ea0be6a99358b30970dfcb29 100644 (file)
@@ -2468,8 +2468,7 @@ static int ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx)
 
                /* drop unicast public action frames when using MPF */
                if (is_unicast_ether_addr(mgmt->da) &&
-                   ieee80211_is_public_action((void *)rx->skb->data,
-                                              rx->skb->len))
+                   ieee80211_is_protected_dual_of_public_action(rx->skb))
                        return -EACCES;
        }
 
index 7fe7280e8437458015a3a9addfb5ff42a51cfb4f..d45d4be63dd877e52ebf61cc5d1c624724b4077b 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 c1250aa478083888697dd346a03838c251e1d635..b3a5c3e96a7205354692d86eb022ecebefa05d64 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));
 
@@ -317,11 +319,21 @@ 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 ab62fe447038ab12857489f9eb5d4aa8b43ec4a1..7a47a58aa54b446acf7451ba6bdc1b834adda327 100644 (file)
@@ -737,6 +737,8 @@ struct mctp_route *mctp_route_lookup(struct net *net, unsigned int dnet,
 {
        struct mctp_route *tmp, *rt = NULL;
 
+       rcu_read_lock();
+
        list_for_each_entry_rcu(tmp, &net->mctp.routes, list) {
                /* TODO: add metrics */
                if (mctp_rt_match_eid(tmp, dnet, daddr)) {
@@ -747,21 +749,29 @@ struct mctp_route *mctp_route_lookup(struct net *net, unsigned int dnet,
                }
        }
 
+       rcu_read_unlock();
+
        return rt;
 }
 
 static struct mctp_route *mctp_route_lookup_null(struct net *net,
                                                 struct net_device *dev)
 {
-       struct mctp_route *rt;
+       struct mctp_route *tmp, *rt = NULL;
 
-       list_for_each_entry_rcu(rt, &net->mctp.routes, list) {
-               if (rt->dev->dev == dev && rt->type == RTN_LOCAL &&
-                   refcount_inc_not_zero(&rt->refs))
-                       return rt;
+       rcu_read_lock();
+
+       list_for_each_entry_rcu(tmp, &net->mctp.routes, list) {
+               if (tmp->dev->dev == dev && tmp->type == RTN_LOCAL &&
+                   refcount_inc_not_zero(&tmp->refs)) {
+                       rt = tmp;
+                       break;
+               }
        }
 
-       return NULL;
+       rcu_read_unlock();
+
+       return rt;
 }
 
 static int mctp_do_fragment_route(struct mctp_route *rt, struct sk_buff *skb,
index c254accb14dee6ef4b692c3f4bc96bfa161e2d84..cd15ec73073e05a133a3130f90e45e33394e759f 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 b5a8aa4c1ebd6d6f30b312cb0e13d31ce3aea9cc..d042d32beb4df0955aec27e14bef72e63dc6361a 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 a7fc16f5175d22a4e741c79edd84f1ea72c676bc..886ab689a8aea920a1b3c4b22b64c3b3b7268f26 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);
        }
 }
 
@@ -1257,7 +1298,7 @@ alloc_skb:
        if (copy == 0) {
                u64 snd_una = READ_ONCE(msk->snd_una);
 
-               if (snd_una != msk->snd_nxt) {
+               if (snd_una != msk->snd_nxt || tcp_write_queue_tail(ssk)) {
                        tcp_remove_empty_skb(ssk);
                        return 0;
                }
@@ -1265,11 +1306,6 @@ alloc_skb:
                zero_window_probe = true;
                data_seq = snd_una - 1;
                copy = 1;
-
-               /* all mptcp-level data is acked, no skbs should be present into the
-                * ssk write queue
-                */
-               WARN_ON_ONCE(reuse_skb);
        }
 
        copy = min_t(size_t, copy, info->limit - info->sent);
@@ -1298,7 +1334,6 @@ alloc_skb:
        if (reuse_skb) {
                TCP_SKB_CB(skb)->tcp_flags &= ~TCPHDR_PSH;
                mpext->data_len += copy;
-               WARN_ON_ONCE(zero_window_probe);
                goto out;
        }
 
@@ -1586,8 +1621,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 +1685,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 +2255,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);
 
@@ -2313,6 +2348,26 @@ bool __mptcp_retransmit_pending_data(struct sock *sk)
 #define MPTCP_CF_PUSH          BIT(1)
 #define MPTCP_CF_FASTCLOSE     BIT(2)
 
+/* be sure to send a reset only if the caller asked for it, also
+ * clean completely the subflow status when the subflow reaches
+ * TCP_CLOSE state
+ */
+static void __mptcp_subflow_disconnect(struct sock *ssk,
+                                      struct mptcp_subflow_context *subflow,
+                                      unsigned int flags)
+{
+       if (((1 << ssk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN)) ||
+           (flags & MPTCP_CF_FASTCLOSE)) {
+               /* The MPTCP code never wait on the subflow sockets, TCP-level
+                * disconnect should never fail
+                */
+               WARN_ON_ONCE(tcp_disconnect(ssk, 0));
+               mptcp_subflow_ctx_reset(subflow);
+       } else {
+               tcp_shutdown(ssk, SEND_SHUTDOWN);
+       }
+}
+
 /* subflow sockets can be either outgoing (connect) or incoming
  * (accept).
  *
@@ -2329,18 +2384,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);
@@ -2354,7 +2405,7 @@ static void __mptcp_close_ssk(struct sock *sk, struct sock *ssk,
        lock_sock_nested(ssk, SINGLE_DEPTH_NESTING);
 
        if ((flags & MPTCP_CF_FASTCLOSE) && !__mptcp_check_fallback(msk)) {
-               /* be sure to force the tcp_disconnect() path,
+               /* be sure to force the tcp_close path
                 * to generate the egress reset
                 */
                ssk->sk_lingertime = 0;
@@ -2364,11 +2415,7 @@ static void __mptcp_close_ssk(struct sock *sk, struct sock *ssk,
 
        need_push = (flags & MPTCP_CF_PUSH) && __mptcp_retransmit_pending_data(sk);
        if (!dispose_it) {
-               /* The MPTCP code never wait on the subflow sockets, TCP-level
-                * disconnect should never fail
-                */
-               WARN_ON_ONCE(tcp_disconnect(ssk, 0));
-               mptcp_subflow_ctx_reset(subflow);
+               __mptcp_subflow_disconnect(ssk, subflow, flags);
                release_sock(ssk);
 
                goto out;
@@ -2392,6 +2439,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 +2450,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 +2509,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 +2643,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 +2683,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 +2719,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 +2767,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 +2858,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 +2942,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 +3025,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 +3061,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;
@@ -3059,12 +3108,6 @@ static int mptcp_disconnect(struct sock *sk, int flags)
 {
        struct mptcp_sock *msk = mptcp_sk(sk);
 
-       /* Deny disconnect if other threads are blocked in sk_wait_event()
-        * or inet_wait_for_connect().
-        */
-       if (sk->sk_wait_pending)
-               return -EBUSY;
-
        /* We are on the fastopen error path. We can't call straight into the
         * subflows cleanup code due to lock nesting (we are already under
         * msk->firstsocket lock).
@@ -3075,8 +3118,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);
@@ -3134,7 +3177,6 @@ struct sock *mptcp_sk_clone_init(const struct sock *sk,
                inet_sk(nsk)->pinet6 = mptcp_inet6_sk(nsk);
 #endif
 
-       nsk->sk_wait_pending = 0;
        __mptcp_init_sock(nsk);
 
        msk = mptcp_sk(nsk);
@@ -3386,24 +3428,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 +3968,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 7254b35625756b24fbe33a2139add079ee98fd63..3612545fa62e046b62a743fba72f9bc0fd7a4233 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 9bf3c7bc1762a0990401f7e07db1e0f395f4e567..9c1f8d1d63d24abad84605837c5b67b827aec1af 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 62fb1031763d14f82dcfee50191a21cb38ad8cf9..f8854bff286cbd7229e0c543689f892f40e80cab 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 e564b5174261159173bfda0756480ca554243b7d..35d2f9c9ada0252e01af3bee1faa1f63a0c94498 100644 (file)
@@ -682,6 +682,14 @@ __ip_set_put(struct ip_set *set)
 /* set->ref can be swapped out by ip_set_swap, netlink events (like dump) need
  * 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)
 {
@@ -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 da5af28ff57b5254c0ec8976c4180113037c96a0..4174076c66fa7795ecbdef18ca2b30f92765cd4d 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 c7a6114091ae59718f494f8bf10346f0632b761c..b21799d468d2815413cc1334cb6c5e5df7fe231d 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 0b513f7bf9f391e7f94a3b4ebce9d47a51fa6cb2..dd62cc12e7750734fec9be8a90fd0defcbc815e0 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 b6bcc8f2f46b7dc0c93e4e75ac9122809fc54be2..c6bd533983c1ff275796b789cdb973c09f646984 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 1d34d700bd09b279b8e06b274d4b004fdc00f15e..920a5a29ae1dceba6849aaad6d62701567d3ec99 100644 (file)
@@ -316,12 +316,6 @@ void flow_offload_refresh(struct nf_flowtable *flow_table,
 }
 EXPORT_SYMBOL_GPL(flow_offload_refresh);
 
-static bool nf_flow_is_outdated(const struct flow_offload *flow)
-{
-       return test_bit(IPS_SEEN_REPLY_BIT, &flow->ct->status) &&
-               !test_bit(NF_FLOW_HW_ESTABLISHED, &flow->flags);
-}
-
 static inline bool nf_flow_has_expired(const struct flow_offload *flow)
 {
        return nf_flow_timeout_delta(flow->timeout) <= 0;
@@ -407,12 +401,18 @@ nf_flow_table_iterate(struct nf_flowtable *flow_table,
        return err;
 }
 
+static bool nf_flow_custom_gc(struct nf_flowtable *flow_table,
+                             const struct flow_offload *flow)
+{
+       return flow_table->type->gc && flow_table->type->gc(flow);
+}
+
 static void nf_flow_offload_gc_step(struct nf_flowtable *flow_table,
                                    struct flow_offload *flow, void *data)
 {
        if (nf_flow_has_expired(flow) ||
            nf_ct_is_dying(flow->ct) ||
-           nf_flow_is_outdated(flow))
+           nf_flow_custom_gc(flow_table, flow))
                flow_offload_teardown(flow);
 
        if (test_bit(NF_FLOW_TEARDOWN, &flow->flags)) {
index e429ebba74b3d13b441f8130087e81153ee1032c..29c651804cb221ca9005f925bfb1f44d622c4859 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]) {
@@ -3160,7 +3166,7 @@ int nft_expr_inner_parse(const struct nft_ctx *ctx, const struct nlattr *nla,
        if (err < 0)
                return err;
 
-       if (!tb[NFTA_EXPR_DATA])
+       if (!tb[NFTA_EXPR_DATA] || !tb[NFTA_EXPR_NAME])
                return -EINVAL;
 
        type = __nft_expr_type_get(ctx->family, tb[NFTA_EXPR_NAME]);
@@ -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;
@@ -5541,7 +5556,6 @@ static int nf_tables_fill_setelem(struct sk_buff *skb,
        const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv);
        unsigned char *b = skb_tail_pointer(skb);
        struct nlattr *nest;
-       u64 timeout = 0;
 
        nest = nla_nest_start_noflag(skb, NFTA_LIST_ELEM);
        if (nest == NULL)
@@ -5577,15 +5591,11 @@ static int nf_tables_fill_setelem(struct sk_buff *skb,
                         htonl(*nft_set_ext_flags(ext))))
                goto nla_put_failure;
 
-       if (nft_set_ext_exists(ext, NFT_SET_EXT_TIMEOUT)) {
-               timeout = *nft_set_ext_timeout(ext);
-               if (nla_put_be64(skb, NFTA_SET_ELEM_TIMEOUT,
-                                nf_jiffies64_to_msecs(timeout),
-                                NFTA_SET_ELEM_PAD))
-                       goto nla_put_failure;
-       } else if (set->flags & NFT_SET_TIMEOUT) {
-               timeout = READ_ONCE(set->timeout);
-       }
+       if (nft_set_ext_exists(ext, NFT_SET_EXT_TIMEOUT) &&
+           nla_put_be64(skb, NFTA_SET_ELEM_TIMEOUT,
+                        nf_jiffies64_to_msecs(*nft_set_ext_timeout(ext)),
+                        NFTA_SET_ELEM_PAD))
+               goto nla_put_failure;
 
        if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPIRATION)) {
                u64 expires, now = get_jiffies_64();
@@ -5600,9 +5610,6 @@ static int nf_tables_fill_setelem(struct sk_buff *skb,
                                 nf_jiffies64_to_msecs(expires),
                                 NFTA_SET_ELEM_PAD))
                        goto nla_put_failure;
-
-               if (reset)
-                       *nft_set_ext_expiration(ext) = now + timeout;
        }
 
        if (nft_set_ext_exists(ext, NFT_SET_EXT_USERDATA)) {
@@ -7183,8 +7190,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);
@@ -7598,6 +7607,16 @@ nla_put_failure:
        return -1;
 }
 
+static void audit_log_obj_reset(const struct nft_table *table,
+                               unsigned int base_seq, unsigned int nentries)
+{
+       char *buf = kasprintf(GFP_ATOMIC, "%s:%u", table->name, base_seq);
+
+       audit_log_nfcfg(buf, table->family, nentries,
+                       AUDIT_NFT_OP_OBJ_RESET, GFP_ATOMIC);
+       kfree(buf);
+}
+
 struct nft_obj_filter {
        char            *table;
        u32             type;
@@ -7612,8 +7631,10 @@ static int nf_tables_dump_obj(struct sk_buff *skb, struct netlink_callback *cb)
        struct net *net = sock_net(skb->sk);
        int family = nfmsg->nfgen_family;
        struct nftables_pernet *nft_net;
+       unsigned int entries = 0;
        struct nft_object *obj;
        bool reset = false;
+       int rc = 0;
 
        if (NFNL_MSG_TYPE(cb->nlh->nlmsg_type) == NFT_MSG_GETOBJ_RESET)
                reset = true;
@@ -7626,6 +7647,7 @@ static int nf_tables_dump_obj(struct sk_buff *skb, struct netlink_callback *cb)
                if (family != NFPROTO_UNSPEC && family != table->family)
                        continue;
 
+               entries = 0;
                list_for_each_entry_rcu(obj, &table->objects, list) {
                        if (!nft_is_active(net, obj))
                                goto cont;
@@ -7641,34 +7663,27 @@ static int nf_tables_dump_obj(struct sk_buff *skb, struct netlink_callback *cb)
                            filter->type != NFT_OBJECT_UNSPEC &&
                            obj->ops->type->type != filter->type)
                                goto cont;
-                       if (reset) {
-                               char *buf = kasprintf(GFP_ATOMIC,
-                                                     "%s:%u",
-                                                     table->name,
-                                                     nft_net->base_seq);
-
-                               audit_log_nfcfg(buf,
-                                               family,
-                                               obj->handle,
-                                               AUDIT_NFT_OP_OBJ_RESET,
-                                               GFP_ATOMIC);
-                               kfree(buf);
-                       }
 
-                       if (nf_tables_fill_obj_info(skb, net, NETLINK_CB(cb->skb).portid,
-                                                   cb->nlh->nlmsg_seq,
-                                                   NFT_MSG_NEWOBJ,
-                                                   NLM_F_MULTI | NLM_F_APPEND,
-                                                   table->family, table,
-                                                   obj, reset) < 0)
-                               goto done;
+                       rc = nf_tables_fill_obj_info(skb, net,
+                                                    NETLINK_CB(cb->skb).portid,
+                                                    cb->nlh->nlmsg_seq,
+                                                    NFT_MSG_NEWOBJ,
+                                                    NLM_F_MULTI | NLM_F_APPEND,
+                                                    table->family, table,
+                                                    obj, reset);
+                       if (rc < 0)
+                               break;
 
+                       entries++;
                        nl_dump_check_consistent(cb, nlmsg_hdr(skb));
 cont:
                        idx++;
                }
+               if (reset && entries)
+                       audit_log_obj_reset(table, nft_net->base_seq, entries);
+               if (rc < 0)
+                       break;
        }
-done:
        rcu_read_unlock();
 
        cb->args[0] = idx;
@@ -7773,7 +7788,7 @@ static int nf_tables_getobj(struct sk_buff *skb, const struct nfnl_info *info,
 
                audit_log_nfcfg(buf,
                                family,
-                               obj->handle,
+                               1,
                                AUDIT_NFT_OP_OBJ_RESET,
                                GFP_ATOMIC);
                kfree(buf);
@@ -7854,24 +7869,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 +7899,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 +9589,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 +9612,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 +9638,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 +9656,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 +9670,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 +11103,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 53c9e76473ba17713871c7f60c19acc18c8b72d7..f03f4d4d7d88967d237c5064cd729ea6f83b40bf 100644 (file)
@@ -698,8 +698,8 @@ nfulnl_log_packet(struct net *net,
        unsigned int plen = 0;
        struct nfnl_log_net *log = nfnl_log_pernet(net);
        const struct nfnl_ct_hook *nfnl_ct = NULL;
+       enum ip_conntrack_info ctinfo = 0;
        struct nf_conn *ct = NULL;
-       enum ip_conntrack_info ctinfo;
 
        if (li_user && li_user->type == NF_LOG_TYPE_ULOG)
                li = li_user;
index 28e2873ba24e428f16ffa894db807c483d89b6a1..928312d01eb1d6028a2e5098a2044df0cafbefce 100644 (file)
@@ -298,6 +298,7 @@ static int nft_inner_init(const struct nft_ctx *ctx,
        int err;
 
        if (!tb[NFTA_INNER_FLAGS] ||
+           !tb[NFTA_INNER_NUM] ||
            !tb[NFTA_INNER_HDRSIZE] ||
            !tb[NFTA_INNER_TYPE] ||
            !tb[NFTA_INNER_EXPR])
index 8cb80098994793fb49c2ef43a2644d0c4425067b..0a689c8e0295dfed3511997abcac53fad4b56fd5 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)
@@ -168,11 +179,11 @@ void nft_payload_eval(const struct nft_expr *expr,
 
        switch (priv->base) {
        case NFT_PAYLOAD_LL_HEADER:
-               if (!skb_mac_header_was_set(skb))
+               if (!skb_mac_header_was_set(skb) || skb_mac_header_len(skb) == 0)
                        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 524763659f2510c2678e013b19a12a929f7630c5..2013de934cef096ac8fa512c1cd4bc18c7c52c10 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 6af9c9ed4b5c3049353fd50b16080f34cd660a6f..c0dcc40de358fb2f364ed15f05a5b166279887aa 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 25a75591583ebec982a53a67135721c7f4902047..2e164a319945f71ea83e991608b5590327b6578d 100644 (file)
@@ -147,7 +147,7 @@ struct nft_pipapo_match {
        unsigned long * __percpu *scratch;
        size_t bsize_max;
        struct rcu_head rcu;
-       struct nft_pipapo_field f[];
+       struct nft_pipapo_field f[] __counted_by(field_count);
 };
 
 /**
index f250b5399344afac46bfca4014367bf57cf18ffe..e34662f4a71e0f821e1557c6bc743638669bbabd 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;
 }
@@ -556,6 +568,8 @@ static void *nft_rbtree_deactivate(const struct net *net,
                                   nft_rbtree_interval_end(this)) {
                                parent = parent->rb_right;
                                continue;
+                       } else if (nft_set_elem_expired(&rbe->ext)) {
+                               break;
                        } else if (!nft_set_elem_active(&rbe->ext, genmask)) {
                                parent = parent->rb_left;
                                continue;
@@ -622,8 +636,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 +683,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 642b9d382fb46ddbc3523584c98e07da6860951a..eb086b06d60da48646739226ca084fa6f6f31b74 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 f60e424e060764916b6bd37e117c22ddea1b00ea..1dac28136e6a3565b216dd4e19a2a0fe3c159518 100644 (file)
@@ -203,17 +203,13 @@ static struct nfc_llcp_sock *nfc_llcp_sock_get(struct nfc_llcp_local *local,
 
                if (tmp_sock->ssap == ssap && tmp_sock->dsap == dsap) {
                        llcp_sock = tmp_sock;
+                       sock_hold(&llcp_sock->sk);
                        break;
                }
        }
 
        read_unlock(&local->sockets.lock);
 
-       if (llcp_sock == NULL)
-               return NULL;
-
-       sock_hold(&llcp_sock->sk);
-
        return llcp_sock;
 }
 
@@ -346,7 +342,8 @@ static int nfc_llcp_wks_sap(const char *service_name, size_t service_name_len)
 
 static
 struct nfc_llcp_sock *nfc_llcp_sock_from_sn(struct nfc_llcp_local *local,
-                                           const u8 *sn, size_t sn_len)
+                                           const u8 *sn, size_t sn_len,
+                                           bool needref)
 {
        struct sock *sk;
        struct nfc_llcp_sock *llcp_sock, *tmp_sock;
@@ -382,6 +379,8 @@ struct nfc_llcp_sock *nfc_llcp_sock_from_sn(struct nfc_llcp_local *local,
 
                if (memcmp(sn, tmp_sock->service_name, sn_len) == 0) {
                        llcp_sock = tmp_sock;
+                       if (needref)
+                               sock_hold(&llcp_sock->sk);
                        break;
                }
        }
@@ -423,7 +422,8 @@ u8 nfc_llcp_get_sdp_ssap(struct nfc_llcp_local *local,
                 * to this service name.
                 */
                if (nfc_llcp_sock_from_sn(local, sock->service_name,
-                                         sock->service_name_len) != NULL) {
+                                         sock->service_name_len,
+                                         false) != NULL) {
                        mutex_unlock(&local->sdp_lock);
 
                        return LLCP_SAP_MAX;
@@ -824,16 +824,7 @@ out:
 static struct nfc_llcp_sock *nfc_llcp_sock_get_sn(struct nfc_llcp_local *local,
                                                  const u8 *sn, size_t sn_len)
 {
-       struct nfc_llcp_sock *llcp_sock;
-
-       llcp_sock = nfc_llcp_sock_from_sn(local, sn, sn_len);
-
-       if (llcp_sock == NULL)
-               return NULL;
-
-       sock_hold(&llcp_sock->sk);
-
-       return llcp_sock;
+       return nfc_llcp_sock_from_sn(local, sn, sn_len, true);
 }
 
 static const u8 *nfc_llcp_connect_sn(const struct sk_buff *skb, size_t *sn_len)
@@ -1298,7 +1289,8 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local,
                        }
 
                        llcp_sock = nfc_llcp_sock_from_sn(local, service_name,
-                                                         service_name_len);
+                                                         service_name_len,
+                                                         true);
                        if (!llcp_sock) {
                                sap = 0;
                                goto add_snl;
@@ -1318,6 +1310,7 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local,
 
                                if (sap == LLCP_SAP_MAX) {
                                        sap = 0;
+                                       nfc_llcp_sock_put(llcp_sock);
                                        goto add_snl;
                                }
 
@@ -1335,6 +1328,7 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local,
 
                        pr_debug("%p %d\n", llcp_sock, sap);
 
+                       nfc_llcp_sock_put(llcp_sock);
 add_snl:
                        sdp = nfc_llcp_build_sdres_tlv(tid, sap);
                        if (sdp == NULL)
@@ -1636,7 +1630,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 fff755dde30d612e9c0f29bb0530e0edb28e0624..6c9592d051206f242b2249f3a5a57d4640333a2c 100644 (file)
@@ -909,6 +909,11 @@ static int nci_activate_target(struct nfc_dev *nfc_dev,
                return -EINVAL;
        }
 
+       if (protocol >= NFC_PROTO_MAX) {
+               pr_err("the requested nfc protocol is invalid\n");
+               return -EINVAL;
+       }
+
        if (!(nci_target->supported_protocols & (1 << protocol))) {
                pr_err("target does not support the requested protocol 0x%x\n",
                       protocol);
index 0935527d1d12b53115ee5f47a8026e280cdee31f..b68150c971d0b108dd97411fa9362e09d47caede 100644 (file)
@@ -151,6 +151,8 @@ static int send_acknowledge(struct nci_spi *nspi, u8 acknowledge)
        int ret;
 
        skb = nci_skb_alloc(nspi->ndev, 0, GFP_KERNEL);
+       if (!skb)
+               return -ENOMEM;
 
        /* add the NCI SPI header to the start of the buffer */
        hdr = skb_push(skb, NCI_SPI_HDR_LEN);
index 8f97648d652f5a4349570fa44013e211892037da..a84e00b5904be0fad471324d1492979403a2fab3 100644 (file)
@@ -3607,7 +3607,12 @@ static int packet_getname(struct socket *sock, struct sockaddr *uaddr,
        if (dev) {
                sll->sll_hatype = dev->type;
                sll->sll_halen = dev->addr_len;
-               memcpy(sll->sll_addr_flex, dev->dev_addr, dev->addr_len);
+
+               /* Let __fortify_memcpy_chk() know the actual buffer size. */
+               memcpy(((struct sockaddr_storage *)sll)->__data +
+                      offsetof(struct sockaddr_ll, sll_addr) -
+                      offsetofend(struct sockaddr_ll, sll_family),
+                      dev->dev_addr, dev->addr_len);
        } else {
                sll->sll_hatype = 0;    /* Bad: we have no ARPHRD_UNSPEC */
                sll->sll_halen = 0;
index d36f3f6b43510dde1ef2e98515b41c6890d76ebf..b15cf316b23a221d47eaf0e7c38200840cc2442b 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 f0c477c5d1db4e355afc370b563652bad4b52905..a0046e99d6df71987707a655cee0def985328b01 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 014fa24418c12ea29d7be7fb72028f44bf6bd9ce..53b3535a1e4a84c3e5ae9dee110af2df376c7f20 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 01fca7a10b4bb0d4108d2096a4dc30ae56f861b9..14cc8fe8584bd1ed595a1f6918ebf9dd10364ac8 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
@@ -1161,7 +1180,6 @@ static int rfkill_fop_open(struct inode *inode, struct file *file)
        init_waitqueue_head(&data->read_wait);
 
        mutex_lock(&rfkill_global_mutex);
-       mutex_lock(&data->mtx);
        /*
         * start getting events from elsewhere but hold mtx to get
         * startup events added first
@@ -1171,11 +1189,13 @@ 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);
+               mutex_lock(&data->mtx);
                list_add_tail(&ev->list, &data->events);
+               mutex_unlock(&data->mtx);
        }
        list_add(&data->list, &rfkill_fds);
-       mutex_unlock(&data->mtx);
        mutex_unlock(&rfkill_global_mutex);
 
        file->private_data = data;
@@ -1183,7 +1203,6 @@ static int rfkill_fop_open(struct inode *inode, struct file *file)
        return stream_open(inode, file);
 
  free:
-       mutex_unlock(&data->mtx);
        mutex_unlock(&rfkill_global_mutex);
        mutex_destroy(&data->mtx);
        list_for_each_entry_safe(ev, tmp, &data->events, list)
index e9d1b2f2ff0ad54e78e58ae57471798090f0a12d..5a81505fba9ac4091ad5ac968018979d50876c86 100644 (file)
@@ -108,13 +108,13 @@ static int rfkill_gpio_probe(struct platform_device *pdev)
 
        rfkill->clk = devm_clk_get(&pdev->dev, NULL);
 
-       gpio = devm_gpiod_get_optional(&pdev->dev, "reset", GPIOD_OUT_LOW);
+       gpio = devm_gpiod_get_optional(&pdev->dev, "reset", GPIOD_ASIS);
        if (IS_ERR(gpio))
                return PTR_ERR(gpio);
 
        rfkill->reset_gpio = gpio;
 
-       gpio = devm_gpiod_get_optional(&pdev->dev, "shutdown", GPIOD_OUT_LOW);
+       gpio = devm_gpiod_get_optional(&pdev->dev, "shutdown", GPIOD_ASIS);
        if (IS_ERR(gpio))
                return PTR_ERR(gpio);
 
index 7c652d14528be9da4904466c7452dbea6020fbfb..fb52d6f9aff939a77813bf0847315da950568873 100644 (file)
@@ -278,7 +278,16 @@ err_nat:
        return err;
 }
 
+static bool tcf_ct_flow_is_outdated(const struct flow_offload *flow)
+{
+       return test_bit(IPS_SEEN_REPLY_BIT, &flow->ct->status) &&
+              test_bit(IPS_HW_OFFLOAD_BIT, &flow->ct->status) &&
+              !test_bit(NF_FLOW_HW_PENDING, &flow->flags) &&
+              !test_bit(NF_FLOW_HW_ESTABLISHED, &flow->flags);
+}
+
 static struct nf_flowtable_type flowtable_ct = {
+       .gc             = tcf_ct_flow_is_outdated,
        .action         = tcf_ct_flow_table_fill_actions,
        .owner          = THIS_MODULE,
 };
index da4c179a4d41844e341a2c773d13588e18d76f93..6663e971a13e76e555ddb3cd9b0ea2e75be11c03 100644 (file)
@@ -366,7 +366,7 @@ static int u32_init(struct tcf_proto *tp)
        idr_init(&root_ht->handle_idr);
 
        if (tp_c == NULL) {
-               tp_c = kzalloc(struct_size(tp_c, hlist->ht, 1), GFP_KERNEL);
+               tp_c = kzalloc(sizeof(*tp_c), GFP_KERNEL);
                if (tp_c == NULL) {
                        kfree(root_ht);
                        return -ENOBUFS;
index 3554085bc2be21b2cce411b22f6b640ed9b0085d..880c5f16b29ccf322f2308450aac4c6f130a2472 100644 (file)
@@ -902,6 +902,14 @@ hfsc_change_usc(struct hfsc_class *cl, struct tc_service_curve *usc,
        cl->cl_flags |= HFSC_USC;
 }
 
+static void
+hfsc_upgrade_rt(struct hfsc_class *cl)
+{
+       cl->cl_fsc = cl->cl_rsc;
+       rtsc_init(&cl->cl_virtual, &cl->cl_fsc, cl->cl_vt, cl->cl_total);
+       cl->cl_flags |= HFSC_FSC;
+}
+
 static const struct nla_policy hfsc_policy[TCA_HFSC_MAX + 1] = {
        [TCA_HFSC_RSC]  = { .len = sizeof(struct tc_service_curve) },
        [TCA_HFSC_FSC]  = { .len = sizeof(struct tc_service_curve) },
@@ -1011,10 +1019,6 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
                if (parent == NULL)
                        return -ENOENT;
        }
-       if (!(parent->cl_flags & HFSC_FSC) && parent != &q->root) {
-               NL_SET_ERR_MSG(extack, "Invalid parent - parent class must have FSC");
-               return -EINVAL;
-       }
 
        if (classid == 0 || TC_H_MAJ(classid ^ sch->handle) != 0)
                return -EINVAL;
@@ -1065,6 +1069,12 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
        cl->cf_tree = RB_ROOT;
 
        sch_tree_lock(sch);
+       /* Check if the inner class is a misconfigured 'rt' */
+       if (!(parent->cl_flags & HFSC_FSC) && parent != &q->root) {
+               NL_SET_ERR_MSG(extack,
+                              "Forced curve change on parent 'rt' to 'sc'");
+               hfsc_upgrade_rt(parent);
+       }
        qdisc_class_hash_insert(&q->clhash, &cl->cl_common);
        list_add_tail(&cl->siblings, &parent->children);
        if (parent->level == 0)
index 796529167e8d2fd23bc9e0afd5e0a0ff7e92848e..c45c192b787873bdfa57e78022b415511a39f3a5 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 ab943e8fb1db5137ac93fc1728e2fa1b49fe4e9c..7f89e43154c091f6f7a3c995c1ba8abb62a8e767 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 1ab3c5a2c5ada6c36e771b887cfa25515dc18bfc..746be399676833c03140241de31d60ec90baae88 100644 (file)
@@ -2,6 +2,7 @@
 config SMC
        tristate "SMC socket protocol family"
        depends on INET && INFINIBAND
+       depends on m || ISM != m
        help
          SMC-R provides a "sockets over RDMA" solution making use of
          RDMA over Converged Ethernet (RoCE) technology to upgrade
index bacdd971615e43b9bdabcd1395caccd5320e549f..35ddebae88941b0c07d6ae1fa37511ada505c7a9 100644 (file)
@@ -1201,6 +1201,7 @@ static int smc_connect_rdma_v2_prepare(struct smc_sock *smc,
                (struct smc_clc_msg_accept_confirm_v2 *)aclc;
        struct smc_clc_first_contact_ext *fce =
                smc_get_clc_first_contact_ext(clc_v2, false);
+       struct net *net = sock_net(&smc->sk);
        int rc;
 
        if (!ini->first_contact_peer || aclc->hdr.version == SMC_V1)
@@ -1210,7 +1211,7 @@ static int smc_connect_rdma_v2_prepare(struct smc_sock *smc,
                memcpy(ini->smcrv2.nexthop_mac, &aclc->r0.lcl.mac, ETH_ALEN);
                ini->smcrv2.uses_gateway = false;
        } else {
-               if (smc_ib_find_route(smc->clcsock->sk->sk_rcv_saddr,
+               if (smc_ib_find_route(net, smc->clcsock->sk->sk_rcv_saddr,
                                      smc_ib_gid_to_ipv4(aclc->r0.lcl.gid),
                                      ini->smcrv2.nexthop_mac,
                                      &ini->smcrv2.uses_gateway))
@@ -2361,7 +2362,7 @@ static int smc_listen_find_device(struct smc_sock *new_smc,
                smc_find_ism_store_rc(rc, ini);
                return (!rc) ? 0 : ini->rc;
        }
-       return SMC_CLC_DECL_NOSMCDEV;
+       return prfx_rc;
 }
 
 /* listen worker: finish RDMA setup */
index 9b66d6aeeb1ae4e489337b4829928bd53efb3348..89981dbe46c946a2ef42d528959d8a53749fc98a 100644 (file)
@@ -193,7 +193,7 @@ bool smc_ib_port_active(struct smc_ib_device *smcibdev, u8 ibport)
        return smcibdev->pattr[ibport - 1].state == IB_PORT_ACTIVE;
 }
 
-int smc_ib_find_route(__be32 saddr, __be32 daddr,
+int smc_ib_find_route(struct net *net, __be32 saddr, __be32 daddr,
                      u8 nexthop_mac[], u8 *uses_gateway)
 {
        struct neighbour *neigh = NULL;
@@ -205,7 +205,7 @@ int smc_ib_find_route(__be32 saddr, __be32 daddr,
 
        if (daddr == cpu_to_be32(INADDR_NONE))
                goto out;
-       rt = ip_route_output_flow(&init_net, &fl4, NULL);
+       rt = ip_route_output_flow(net, &fl4, NULL);
        if (IS_ERR(rt))
                goto out;
        if (rt->rt_uses_gateway && rt->rt_gw_family != AF_INET)
@@ -235,6 +235,7 @@ static int smc_ib_determine_gid_rcu(const struct net_device *ndev,
        if (smcrv2 && attr->gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP &&
            smc_ib_gid_to_ipv4((u8 *)&attr->gid) != cpu_to_be32(INADDR_NONE)) {
                struct in_device *in_dev = __in_dev_get_rcu(ndev);
+               struct net *net = dev_net(ndev);
                const struct in_ifaddr *ifa;
                bool subnet_match = false;
 
@@ -248,7 +249,7 @@ static int smc_ib_determine_gid_rcu(const struct net_device *ndev,
                }
                if (!subnet_match)
                        goto out;
-               if (smcrv2->daddr && smc_ib_find_route(smcrv2->saddr,
+               if (smcrv2->daddr && smc_ib_find_route(net, smcrv2->saddr,
                                                       smcrv2->daddr,
                                                       smcrv2->nexthop_mac,
                                                       &smcrv2->uses_gateway))
index 4df5f8c8a0a1c77a9e3c0242144d433c61db15d8..ef8ac2b7546df57c2acddf193079b29166bd20c6 100644 (file)
@@ -112,7 +112,7 @@ void smc_ib_sync_sg_for_device(struct smc_link *lnk,
 int smc_ib_determine_gid(struct smc_ib_device *smcibdev, u8 ibport,
                         unsigned short vlan_id, u8 gid[], u8 *sgid_index,
                         struct smc_init_info_smcrv2 *smcrv2);
-int smc_ib_find_route(__be32 saddr, __be32 daddr,
+int smc_ib_find_route(struct net *net, __be32 saddr, __be32 daddr,
                      u8 nexthop_mac[], u8 *uses_gateway);
 bool smc_ib_is_valid_local_systemid(void);
 int smcr_nl_get_device(struct sk_buff *skb, struct netlink_callback *cb);
index aa8928975cc633cf169059713226d737e1634293..9d32058db2b5d62ca122d1ead0299427575dda35 100644 (file)
@@ -92,13 +92,14 @@ do { \
        typeof(_smc_stats) stats = (_smc_stats); \
        typeof(_tech) t = (_tech); \
        typeof(_len) l = (_len); \
-       int _pos = fls64((l) >> 13); \
+       int _pos; \
        typeof(_rc) r = (_rc); \
        int m = SMC_BUF_MAX - 1; \
        this_cpu_inc((*stats).smc[t].key ## _cnt); \
-       if (r <= 0) \
+       if (r <= 0 || l <= 0) \
                break; \
-       _pos = (_pos < m) ? ((l == 1 << (_pos + 12)) ? _pos - 1 : _pos) : m; \
+       _pos = fls64((l - 1) >> 13); \
+       _pos = (_pos <= m) ? _pos : m; \
        this_cpu_inc((*stats).smc[t].key ## _pd.buf[_pos]); \
        this_cpu_add((*stats).smc[t].key ## _bytes, r); \
 } \
@@ -138,9 +139,12 @@ while (0)
 do { \
        typeof(_len) _l = (_len); \
        typeof(_tech) t = (_tech); \
-       int _pos = fls((_l) >> 13); \
+       int _pos; \
        int m = SMC_BUF_MAX - 1; \
-       _pos = (_pos < m) ? ((_l == 1 << (_pos + 12)) ? _pos - 1 : _pos) : m; \
+       if (_l <= 0) \
+               break; \
+       _pos = fls((_l - 1) >> 13); \
+       _pos = (_pos <= m) ? _pos : m; \
        this_cpu_inc((*(_smc_stats)).smc[t].k ## _rmbsize.buf[_pos]); \
 } \
 while (0)
index c8b08b32f097ec5dfde66b42701be720ab05c826..c4a6f55329552d9c80a41b1b691ce305c22f09f8 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 2f16f9d179662442b94bb729f772fdb1b39c2a39..814b0169f972304e105e1a63dfcf6ce59f3428cd 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 de7678f8a23d26ff25acb5ff338181a44d5727d2..87f570fd3b00ead957f7e8541affb37be43ef3f8 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 8d75290f1a31d23d5f61439c18549ed76c36ced8..9c210273d06b7f51184c08d38c71929a87eef1c2 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 71cd916e384f173b30d2e96bfc504474d9e832d5..a15bf2ede89bf5f09843022b7b24004b433b4832 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 302fd749c4249a9644dbc907ca5f9d11f8014d2b..43c3f1c971b8fdf43e93b1616483fb2d8fef3d57 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 02f583ff9239539bc70528820fc8480dd8d1fb5f..002483e60c190d9b554b170ed9b2e1735cff945b 100644 (file)
@@ -139,8 +139,8 @@ void update_sk_prot(struct sock *sk, struct tls_context *ctx)
 
 int wait_on_pending_writer(struct sock *sk, long *timeo)
 {
-       int rc = 0;
        DEFINE_WAIT_FUNC(wait, woken_wake_function);
+       int ret, rc = 0;
 
        add_wait_queue(sk_sleep(sk), &wait);
        while (1) {
@@ -154,9 +154,13 @@ int wait_on_pending_writer(struct sock *sk, long *timeo)
                        break;
                }
 
-               if (sk_wait_event(sk, timeo,
-                                 !READ_ONCE(sk->sk_write_pending), &wait))
+               ret = sk_wait_event(sk, timeo,
+                                   !READ_ONCE(sk->sk_write_pending), &wait);
+               if (ret) {
+                       if (ret < 0)
+                               rc = ret;
                        break;
+               }
        }
        remove_wait_queue(sk_sleep(sk), &wait);
        return rc;
index d1fc295b83b59a03a472f8b9d3d740765bad7fbb..e9d1e83a859d1f72f5bec6039a03d025be231729 100644 (file)
@@ -1291,6 +1291,7 @@ tls_rx_rec_wait(struct sock *sk, struct sk_psock *psock, bool nonblock,
        struct tls_context *tls_ctx = tls_get_ctx(sk);
        struct tls_sw_context_rx *ctx = tls_sw_ctx_rx(tls_ctx);
        DEFINE_WAIT_FUNC(wait, woken_wake_function);
+       int ret = 0;
        long timeo;
 
        timeo = sock_rcvtimeo(sk, nonblock);
@@ -1302,6 +1303,9 @@ tls_rx_rec_wait(struct sock *sk, struct sk_psock *psock, bool nonblock,
                if (sk->sk_err)
                        return sock_error(sk);
 
+               if (ret < 0)
+                       return ret;
+
                if (!skb_queue_empty(&sk->sk_receive_queue)) {
                        tls_strp_check_rcv(&ctx->strp);
                        if (tls_strp_msg_ready(ctx))
@@ -1320,10 +1324,10 @@ tls_rx_rec_wait(struct sock *sk, struct sk_psock *psock, bool nonblock,
                released = true;
                add_wait_queue(sk_sleep(sk), &wait);
                sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk);
-               sk_wait_event(sk, &timeo,
-                             tls_strp_msg_ready(ctx) ||
-                             !sk_psock_queue_empty(psock),
-                             &wait);
+               ret = sk_wait_event(sk, &timeo,
+                                   tls_strp_msg_ready(ctx) ||
+                                   !sk_psock_queue_empty(psock),
+                                   &wait);
                sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk);
                remove_wait_queue(sk_sleep(sk), &wait);
 
@@ -1852,6 +1856,7 @@ static int tls_rx_reader_acquire(struct sock *sk, struct tls_sw_context_rx *ctx,
                                 bool nonblock)
 {
        long timeo;
+       int ret;
 
        timeo = sock_rcvtimeo(sk, nonblock);
 
@@ -1861,14 +1866,16 @@ static int tls_rx_reader_acquire(struct sock *sk, struct tls_sw_context_rx *ctx,
                ctx->reader_contended = 1;
 
                add_wait_queue(&ctx->wq, &wait);
-               sk_wait_event(sk, &timeo,
-                             !READ_ONCE(ctx->reader_present), &wait);
+               ret = sk_wait_event(sk, &timeo,
+                                   !READ_ONCE(ctx->reader_present), &wait);
                remove_wait_queue(&ctx->wq, &wait);
 
                if (timeo <= 0)
                        return -EAGAIN;
                if (signal_pending(current))
                        return sock_intr_errno(timeo);
+               if (ret < 0)
+                       return ret;
        }
 
        WRITE_ONCE(ctx->reader_present, 1);
index e95df847176b6df78066dbf1d2c1808385110a05..b80bf681327bd31c48a7b3022a35faf32a009e5b 100644 (file)
@@ -555,6 +555,11 @@ static int virtio_vsock_vqs_init(struct virtio_vsock *vsock)
 
        virtio_device_ready(vdev);
 
+       return 0;
+}
+
+static void virtio_vsock_vqs_start(struct virtio_vsock *vsock)
+{
        mutex_lock(&vsock->tx_lock);
        vsock->tx_run = true;
        mutex_unlock(&vsock->tx_lock);
@@ -569,7 +574,16 @@ static int virtio_vsock_vqs_init(struct virtio_vsock *vsock)
        vsock->event_run = true;
        mutex_unlock(&vsock->event_lock);
 
-       return 0;
+       /* virtio_transport_send_pkt() can queue packets once
+        * the_virtio_vsock is set, but they won't be processed until
+        * vsock->tx_run is set to true. We queue vsock->send_pkt_work
+        * when initialization finishes to send those packets queued
+        * earlier.
+        * We don't need to queue the other workers (rx, event) because
+        * as long as we don't fill the queues with empty buffers, the
+        * host can't send us any notification.
+        */
+       queue_work(virtio_vsock_workqueue, &vsock->send_pkt_work);
 }
 
 static void virtio_vsock_vqs_del(struct virtio_vsock *vsock)
@@ -664,6 +678,7 @@ static int virtio_vsock_probe(struct virtio_device *vdev)
                goto out;
 
        rcu_assign_pointer(the_virtio_vsock, vsock);
+       virtio_vsock_vqs_start(vsock);
 
        mutex_unlock(&the_virtio_vsock_mutex);
 
@@ -736,6 +751,7 @@ static int virtio_vsock_restore(struct virtio_device *vdev)
                goto out;
 
        rcu_assign_pointer(the_virtio_vsock, vsock);
+       virtio_vsock_vqs_start(vsock);
 
 out:
        mutex_unlock(&the_virtio_vsock_mutex);
index 25bc2e50a061593cebf2af38ffa5764cb5c37378..acec41c1809a82f3b7712c715433c3be881b56bf 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
@@ -1622,7 +1622,7 @@ void wiphy_work_queue(struct wiphy *wiphy, struct wiphy_work *work)
                list_add_tail(&work->entry, &rdev->wiphy_work_list);
        spin_unlock_irqrestore(&rdev->wiphy_work_lock, flags);
 
-       schedule_work(&rdev->wiphy_work);
+       queue_work(system_unbound_wq, &rdev->wiphy_work);
 }
 EXPORT_SYMBOL_GPL(wiphy_work_queue);
 
index 507d184b8b40bc31666b1da510bdca215c33dc94..ba9c7170afa44e1a37c11d750cf6fd6c4998ba7c 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 775cac4d61006f0221559e21232f913365cf529b..55a1d3633853fae0beb1f6f0fc6b539aa45a4a6c 100644 (file)
@@ -43,16 +43,18 @@ void cfg80211_rx_assoc_resp(struct net_device *dev,
 
        for (link_id = 0; link_id < ARRAY_SIZE(data->links); link_id++) {
                cr.links[link_id].status = data->links[link_id].status;
+               cr.links[link_id].bss = data->links[link_id].bss;
+
                WARN_ON_ONCE(cr.links[link_id].status != WLAN_STATUS_SUCCESS &&
                             (!cr.ap_mld_addr || !cr.links[link_id].bss));
 
-               cr.links[link_id].bss = data->links[link_id].bss;
                if (!cr.links[link_id].bss)
                        continue;
                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 de47838aca4f25af9fc6872225004441ca809cc1..931a03f4549c9fc1e85e20870742c935baca83a2 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 0cf1ce7b6934238626a9f3173e74af89ee0822cb..8210a6090ac161ff4a5cf8fadd9cf92053a7c2ca 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;
 
@@ -2121,7 +2125,7 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy,
        if (!res)
                goto drop;
 
-       rdev_inform_bss(rdev, &res->pub, ies, data->drv_data);
+       rdev_inform_bss(rdev, &res->pub, ies, drv_data->drv_data);
 
        if (data->bss_source == BSS_SOURCE_MBSSID) {
                /* this is a nontransmitting bss, we need to add it to
index f8905400ee07a0f69095349084c44037dd15e0bf..d2c2640300171a78fb9439868725caec61c99905 100644 (file)
@@ -34,6 +34,16 @@ struct xsk_queue *xskq_create(u32 nentries, bool umem_queue)
        q->ring_mask = nentries - 1;
 
        size = xskq_get_ring_size(q, umem_queue);
+
+       /* size which is overflowing or close to SIZE_MAX will become 0 in
+        * PAGE_ALIGN(), checking SIZE_MAX is enough due to the previous
+        * is_power_of_2(), the rest will be handled by vmalloc_user()
+        */
+       if (unlikely(size == SIZE_MAX)) {
+               kfree(q);
+               return NULL;
+       }
+
        size = PAGE_ALIGN(size);
 
        q->ring = vmalloc_user(size);
index b864740846902db7f0ab60c6d72465a51b96b1d7..e21cc71095bb27012f774f50ace5e3c2c52e243d 100644 (file)
@@ -380,8 +380,8 @@ static int xfrmi_rcv_cb(struct sk_buff *skb, int err)
        skb->dev = dev;
 
        if (err) {
-               dev->stats.rx_errors++;
-               dev->stats.rx_dropped++;
+               DEV_STATS_INC(dev, rx_errors);
+               DEV_STATS_INC(dev, rx_dropped);
 
                return 0;
        }
@@ -426,7 +426,6 @@ static int
 xfrmi_xmit2(struct sk_buff *skb, struct net_device *dev, struct flowi *fl)
 {
        struct xfrm_if *xi = netdev_priv(dev);
-       struct net_device_stats *stats = &xi->dev->stats;
        struct dst_entry *dst = skb_dst(skb);
        unsigned int length = skb->len;
        struct net_device *tdev;
@@ -473,7 +472,7 @@ xfrmi_xmit2(struct sk_buff *skb, struct net_device *dev, struct flowi *fl)
        tdev = dst->dev;
 
        if (tdev == dev) {
-               stats->collisions++;
+               DEV_STATS_INC(dev, collisions);
                net_warn_ratelimited("%s: Local routing loop detected!\n",
                                     dev->name);
                goto tx_err_dst_release;
@@ -512,13 +511,13 @@ xmit:
        if (net_xmit_eval(err) == 0) {
                dev_sw_netstats_tx_add(dev, 1, length);
        } else {
-               stats->tx_errors++;
-               stats->tx_aborted_errors++;
+               DEV_STATS_INC(dev, tx_errors);
+               DEV_STATS_INC(dev, tx_aborted_errors);
        }
 
        return 0;
 tx_err_link_failure:
-       stats->tx_carrier_errors++;
+       DEV_STATS_INC(dev, tx_carrier_errors);
        dst_link_failure(skb);
 tx_err_dst_release:
        dst_release(dst);
@@ -528,7 +527,6 @@ tx_err_dst_release:
 static netdev_tx_t xfrmi_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct xfrm_if *xi = netdev_priv(dev);
-       struct net_device_stats *stats = &xi->dev->stats;
        struct dst_entry *dst = skb_dst(skb);
        struct flowi fl;
        int ret;
@@ -545,7 +543,7 @@ static netdev_tx_t xfrmi_xmit(struct sk_buff *skb, struct net_device *dev)
                        dst = ip6_route_output(dev_net(dev), NULL, &fl.u.ip6);
                        if (dst->error) {
                                dst_release(dst);
-                               stats->tx_carrier_errors++;
+                               DEV_STATS_INC(dev, tx_carrier_errors);
                                goto tx_err;
                        }
                        skb_dst_set(skb, dst);
@@ -561,7 +559,7 @@ static netdev_tx_t xfrmi_xmit(struct sk_buff *skb, struct net_device *dev)
                        fl.u.ip4.flowi4_flags |= FLOWI_FLAG_ANYSRC;
                        rt = __ip_route_output_key(dev_net(dev), &fl.u.ip4);
                        if (IS_ERR(rt)) {
-                               stats->tx_carrier_errors++;
+                               DEV_STATS_INC(dev, tx_carrier_errors);
                                goto tx_err;
                        }
                        skb_dst_set(skb, &rt->dst);
@@ -580,8 +578,8 @@ static netdev_tx_t xfrmi_xmit(struct sk_buff *skb, struct net_device *dev)
        return NETDEV_TX_OK;
 
 tx_err:
-       stats->tx_errors++;
-       stats->tx_dropped++;
+       DEV_STATS_INC(dev, tx_errors);
+       DEV_STATS_INC(dev, tx_dropped);
        kfree_skb(skb);
        return NETDEV_TX_OK;
 }
index d6b405782b6361c4da2e06fae50befbd699aed15..d24b4d4f620ea02c900e99f0db9b08efef920663 100644 (file)
@@ -851,7 +851,7 @@ static void xfrm_policy_inexact_list_reinsert(struct net *net,
                struct hlist_node *newpos = NULL;
                bool matches_s, matches_d;
 
-               if (!policy->bydst_reinsert)
+               if (policy->walk.dead || !policy->bydst_reinsert)
                        continue;
 
                WARN_ON_ONCE(policy->family != family);
@@ -1256,8 +1256,11 @@ static void xfrm_hash_rebuild(struct work_struct *work)
                struct xfrm_pol_inexact_bin *bin;
                u8 dbits, sbits;
 
+               if (policy->walk.dead)
+                       continue;
+
                dir = xfrm_policy_id2dir(policy->index);
-               if (policy->walk.dead || dir >= XFRM_POLICY_MAX)
+               if (dir >= XFRM_POLICY_MAX)
                        continue;
 
                if ((dir & XFRM_POLICY_MASK) == XFRM_POLICY_OUT) {
@@ -1372,8 +1375,6 @@ EXPORT_SYMBOL(xfrm_policy_hash_rebuild);
  * of an absolute inpredictability of ordering of rules. This will not pass. */
 static u32 xfrm_gen_index(struct net *net, int dir, u32 index)
 {
-       static u32 idx_generator;
-
        for (;;) {
                struct hlist_head *list;
                struct xfrm_policy *p;
@@ -1381,8 +1382,8 @@ static u32 xfrm_gen_index(struct net *net, int dir, u32 index)
                int found;
 
                if (!index) {
-                       idx = (idx_generator | dir);
-                       idx_generator += 8;
+                       idx = (net->xfrm.idx_generator | dir);
+                       net->xfrm.idx_generator += 8;
                } else {
                        idx = index;
                        index = 0;
@@ -1823,9 +1824,11 @@ int xfrm_policy_flush(struct net *net, u8 type, bool task_valid)
 
 again:
        list_for_each_entry(pol, &net->xfrm.policy_all, walk.all) {
+               if (pol->walk.dead)
+                       continue;
+
                dir = xfrm_policy_id2dir(pol->index);
-               if (pol->walk.dead ||
-                   dir >= XFRM_POLICY_MAX ||
+               if (dir >= XFRM_POLICY_MAX ||
                    pol->type != type)
                        continue;
 
@@ -1862,9 +1865,11 @@ int xfrm_dev_policy_flush(struct net *net, struct net_device *dev,
 
 again:
        list_for_each_entry(pol, &net->xfrm.policy_all, walk.all) {
+               if (pol->walk.dead)
+                       continue;
+
                dir = xfrm_policy_id2dir(pol->index);
-               if (pol->walk.dead ||
-                   dir >= XFRM_POLICY_MAX ||
+               if (dir >= XFRM_POLICY_MAX ||
                    pol->xdo.dev != dev)
                        continue;
 
@@ -3215,7 +3220,7 @@ no_transform:
        }
 
        for (i = 0; i < num_pols; i++)
-               pols[i]->curlft.use_time = ktime_get_real_seconds();
+               WRITE_ONCE(pols[i]->curlft.use_time, ktime_get_real_seconds());
 
        if (num_xfrms < 0) {
                /* Prohibit the flow */
index 87958e864be02508a01085a3929901eb49b1c565..7dbf9abe0d0197fe88cece75e4c4d2f83c357174 100644 (file)
@@ -93,15 +93,14 @@ quiet_cmd_rustdoc = RUSTDOC $(if $(rustdoc_host),H, ) $<
 # and then retouch the generated files.
 rustdoc: rustdoc-core rustdoc-macros rustdoc-compiler_builtins \
     rustdoc-alloc rustdoc-kernel
-       $(Q)cp $(srctree)/Documentation/images/logo.svg $(rustdoc_output)
-       $(Q)cp $(srctree)/Documentation/images/COPYING-logo $(rustdoc_output)
+       $(Q)cp $(srctree)/Documentation/images/logo.svg $(rustdoc_output)/static.files/
+       $(Q)cp $(srctree)/Documentation/images/COPYING-logo $(rustdoc_output)/static.files/
        $(Q)find $(rustdoc_output) -name '*.html' -type f -print0 | xargs -0 sed -Ei \
-               -e 's:rust-logo\.svg:logo.svg:g' \
-               -e 's:rust-logo\.png:logo.svg:g' \
-               -e 's:favicon\.svg:logo.svg:g' \
-               -e 's:<link rel="alternate icon" type="image/png" href="[./]*favicon-(16x16|32x32)\.png">::g'
-       $(Q)echo '.logo-container > img { object-fit: contain; }' \
-               >> $(rustdoc_output)/rustdoc.css
+               -e 's:rust-logo-[0-9a-f]+\.svg:logo.svg:g' \
+               -e 's:favicon-[0-9a-f]+\.svg:logo.svg:g' \
+               -e 's:<link rel="alternate icon" type="image/png" href="[/.]+/static\.files/favicon-(16x16|32x32)-[0-9a-f]+\.png">::g'
+       $(Q)for f in $(rustdoc_output)/static.files/rustdoc-*.css; do \
+               echo ".logo-container > img { object-fit: contain; }" >> $$f; done
 
 rustdoc-macros: private rustdoc_host = yes
 rustdoc-macros: private rustc_target_flags = --crate-type proc-macro \
@@ -290,6 +289,7 @@ bindgen_skip_c_flags := -mno-fp-ret-in-387 -mpreferred-stack-boundary=% \
        -fno-reorder-blocks -fno-allow-store-data-races -fasan-shadow-offset=% \
        -fzero-call-used-regs=% -fno-stack-clash-protection \
        -fno-inline-functions-called-once -fsanitize=bounds-strict \
+       -fstrict-flex-arrays=% \
        --param=% --param asan-%
 
 # Derived from `scripts/Makefile.clang`.
index 05fcab6abfe63ef65e34b352f5f2e26352ae473e..032b64543953952ee95871c8781599d58bc99a7b 100644 (file)
@@ -37,7 +37,7 @@ pub mod code {
     declare_err!(E2BIG, "Argument list too long.");
     declare_err!(ENOEXEC, "Exec format error.");
     declare_err!(EBADF, "Bad file number.");
-    declare_err!(ECHILD, "Exec format error.");
+    declare_err!(ECHILD, "No child processes.");
     declare_err!(EAGAIN, "Try again.");
     declare_err!(ENOMEM, "Out of memory.");
     declare_err!(EACCES, "Permission denied.");
@@ -133,7 +133,7 @@ impl Error {
     /// Returns the error encoded as a pointer.
     #[allow(dead_code)]
     pub(crate) fn to_ptr<T>(self) -> *mut T {
-        // SAFETY: self.0 is a valid error due to its invariant.
+        // SAFETY: `self.0` is a valid error due to its invariant.
         unsafe { bindings::ERR_PTR(self.0.into()) as *mut _ }
     }
 
index 346f5ec506823e05fc4f2864223b2df574b0c842..0afd75472679f63d4cd60cac1feebe1c2a4f8c61 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 c0c8a85d7c81b56d8f8c66b96021898e482f7043..a45154cefa487a81ef87ba12a2f79c42f070df00 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 5179edd1b6271d676a43c2edff5e8ecc218ea6c6..c8047f4441e60ea944ae6fccedf0e4d0d7632dcd 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 38120f932b0dc1c9dcca19865223c9bb3881a844..7056751c29b1fb7171f70b29c79026363bcabd6b 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 de499dce52652798e8ed731a4544aecc07f15be5..b3dee80497cb2b1fdfa488d42c14294def73749a 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 bf3f8561aa6832cb98a848dd389624502b98ab12..d7dd0d04c70c9982bae9b86e54bf52dba295a2fd 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 ac3f2ee6d7a08de653037fd65d570cbd3343214c..3eee0143e0c5cc7671e640aad2368446e94805e0 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 ecddc807c536189ef281d542b86124cfb1c21666..a6bd817efc1a699b2500a555f2f1d9c901407aa5 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 c6fc50d67214c401f95f3e5aff3f17032eb8c950..85fb5c22529a761d9cc4509c74ea01cc790113e0 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 d61bde1225f23a362aa4c2edd64ec9ec32fc1987..22c0d217b8608f04b4c9c1803379b9546f12ed14 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 ba06484ac4aa9b6f7f05be7c63187cb22341df7b..1431cb997808d071d44efadba2b8a1d49117ee25 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 44302d98950e89aca5de30ca166b5e3ba6de9c7c..18320a248aa7daa080df9499668c400f4da22066 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 f26a1812dfa73e564aaf77f8197045c8e9a3a933..2db371d79930d0f2af7630f50901a3d69006e538 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 7cc84e137999cd8e5a38ac6913e4a9cbc58fc4d0..b141024830ecc831430c697858ce409a56c711af 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 6f597d03e7c157ae45476cfd888e64720d1604b0..b1425bf98c3befd7237c6b19920c86667dabe16e 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 4c2998034313587ac8a53f18ad708db6fb32e4a7..78988e44b8bcd23329dfd929e144c13163e8602b 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 68eb8c39afa6c58ea7994172ea1773b5ac654aed..8f4bace16050a16248c9c117af9cc0888bbf0463 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 25821d186b878f67a389c474ff3d0caf855be3da..da3054fdcc7d66050f51abc09cb2dd6ac309597e 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 dd4298876ac087954ae37e3f20ceea93b3362ed6..e3ed4e094ccd0e8311a053878cb9d5e7c429a46b 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 84621e3568482431d4334a5d4afb773dfb4a63a7..350bf4d299c2009571427b75b0378314c2965f05 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 2365f7dfde2664dfa3990e2e8ab848b2de5ada4d..eebc7e790ee2ab682ea024d6b82723252f995bd4 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 775cba3f1f028a03853394443ddc92e9aecad912..c215fa6f7a03713e946b276016fc80f5585d4d9e 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 63d40f1a914f8c710bcdc2e57cf3794102d475b7..241a697ce26b2585f7271ef6e9ae0cbcadce879b 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 02eed2dce435f24e41f2f5a5b06104d52c2f10e0..c57fac4f196819462aac2d0ebc11f03c16ce36fc 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 5cb92f7ccbcac991f95aa1fd2ecea60486fe9248..b57d72ea4503fa7504757eb6542b51e5b2e7b5e9 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 c471ac2aa450a1a4ee65d60ca5fad3e47d3d053f..401d8df28d8767a8b1159494d30ab497e6958ffc 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 1e89233853662046f4161a767877ad87f67a8967..c87be4be6df1d4afeb9c62936a57de4a02297bed 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 10112e1bb25dc2373c77ae3ef0d120d328a91030..7226cbf2d7de4c5736cbd31858c727bd7b4e2917 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 f935b56eeec7bfc1baceeb4285c49c3dadeb1c35..97728bf45474238d500aaead219a8d5e3396ae00 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 59242baed576410d5a2d82d854e79901f1e95842..59792f2fada1d578154c25e11d61ef8153b5689e 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 4beeb32fe2a7a9d0bbfb999bbbd6c9020bf3a58a..c33f67dd51331acf457d74b02926dc8392e8a673 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 0bc0025f7c199a6c678e2bf8c949b33fe882ff28..cc56fafd27b1253e301d58f493b89d17fbdaba08 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 1415baac9c361349932e2c67d6a97e9a18513527..08e34b184780187f66922448c40761e6281d84a2 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 f9b77353c2660e0242e30938f8837427e55585fd..c6031f74409964ebf4b10d0dffadc2ed46c29250 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 76b9c685560bf078ec856843f0db1f42969c7508..7adc1d373d65c377cf2db29f4a6bb63b57db0bb4 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 83e4acdd89aceddb9d8671728b752d3611f2f2d8..757a4d193e0fb5919778847693a3353f2825265b 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 dbf7aa88e0e31a48a751e91761cfa644f98ab1c1..bf685d01259d30070aaf3ac7f3ed3204bc30c5bd 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 765d95e7986171d2d2d3fed9ef2509db975f7074..ca765ac4765f4a27b77f81f466b647a9699f068d 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 b7e78bfcffd832a33df08cbc5d24b21b353c52d2..9677c09cf7a98ebd3d39b92edcc0ca1214d1d024 100644 (file)
@@ -7073,8 +7073,28 @@ 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 */
+       }
+}
+/* Fix none verb table of Headset Mic pin */
+static void alc_fixup_headset_mic(struct hda_codec *codec,
+                                  const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+       static const struct hda_pintbl pincfgs[] = {
+               { 0x19, 0x03a1103c },
+               { }
+       };
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               snd_hda_apply_pincfgs(codec, pincfgs);
+               alc_update_coef_idx(codec, 0x45, 0xf<<12 | 1<<10, 5<<12);
+               spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
+               break;
+       }
 }
 
 
@@ -7341,6 +7361,8 @@ 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,
+       ALC2XX_FIXUP_HEADSET_MIC,
 };
 
 /* A special fixup for Lenovo C940 and Yoga Duet 7;
@@ -9439,6 +9461,16 @@ 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,
+       },
+       [ALC2XX_FIXUP_HEADSET_MIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_headset_mic,
+       },
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -9713,6 +9745,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x89c6, "Zbook Fury 17 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x89ca, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
        SND_PCI_QUIRK(0x103c, 0x89d3, "HP EliteBook 645 G9 (MB 89D2)", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+       SND_PCI_QUIRK(0x103c, 0x8a20, "HP Laptop 15s-fq5xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
        SND_PCI_QUIRK(0x103c, 0x8a25, "HP Victus 16-d1xxx (MB 8A25)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
        SND_PCI_QUIRK(0x103c, 0x8a78, "HP Dev One", ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x103c, 0x8aa0, "HP ProBook 440 G9 (MB 8A9E)", ALC236_FIXUP_HP_GPIO_LED),
@@ -9782,6 +9815,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A),
        SND_PCI_QUIRK(0x1043, 0x1573, "ASUS GZ301V", ALC285_FIXUP_ASUS_HEADSET_MIC),
        SND_PCI_QUIRK(0x1043, 0x1662, "ASUS GV301QH", ALC294_FIXUP_ASUS_DUAL_SPK),
+       SND_PCI_QUIRK(0x1043, 0x1663, "ASUS GU603ZV", ALC285_FIXUP_ASUS_HEADSET_MIC),
        SND_PCI_QUIRK(0x1043, 0x1683, "ASUS UM3402YAR", ALC287_FIXUP_CS35L41_I2C_2),
        SND_PCI_QUIRK(0x1043, 0x16b2, "ASUS GU603", ALC289_FIXUP_ASUS_GA401),
        SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC),
@@ -9812,7 +9846,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 +9886,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 +10020,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 +10123,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 +10609,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},
@@ -10736,6 +10775,8 @@ static const struct snd_hda_pin_quirk alc269_fallback_pin_fixup_tbl[] = {
        SND_HDA_PIN_QUIRK(0x10ec0274, 0x1028, "Dell", ALC274_FIXUP_DELL_AIO_LINEOUT_VERB,
                {0x19, 0x40000000},
                {0x1a, 0x40000000}),
+       SND_HDA_PIN_QUIRK(0x10ec0256, 0x1043, "ASUS", ALC2XX_FIXUP_HEADSET_MIC,
+               {0x19, 0x40000000}),
        {}
 };
 
index b37c877c2c16057505fae4b206d74f96657c66f3..9dee0345f22cf1e550d38f1c3b3c7918e2f116c5 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 3ec15b46fa35696f007ce86b4cec4cc35128937a..15a864dcd7bd3a526ccd5a568c9dc46ad2e394c8 100644 (file)
@@ -213,6 +213,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "21J6"),
                }
        },
+       {
+               .driver_data = &acp6x_card,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "82QF"),
+               }
+       },
        {
                .driver_data = &acp6x_card,
                .matches = {
@@ -220,6 +227,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "82TL"),
                }
        },
+       {
+               .driver_data = &acp6x_card,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "82UG"),
+               }
+       },
        {
                .driver_data = &acp6x_card,
                .matches = {
@@ -227,6 +241,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
                        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 = {
@@ -262,6 +283,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "M6500RC"),
                }
        },
+       {
+               .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 = {
index 8ee1baa0326911d2ae39a5fa047e73a5e7aa7212..87dd0ccade4ce754b9962a4f931e2a80c2dc0ee8 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 9f4f2f4f23f5668c846f2a051eee64c533deb38f..d10e0e2380e852a5ba3b59f749fa685d923634c0 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 600b79c62ec48a5dec9d843cb036477c7867f20a..f9059780b7a7b648470344bf079d5cb8418b6ba7 100644 (file)
@@ -706,7 +706,7 @@ static void cs35l56_patch(struct cs35l56_private *cs35l56)
 
        mutex_lock(&cs35l56->base.irq_lock);
 
-       init_completion(&cs35l56->init_completion);
+       reinit_completion(&cs35l56->init_completion);
 
        cs35l56->soft_resetting = true;
        cs35l56_system_reset(&cs35l56->base, !!cs35l56->sdw_peripheral);
@@ -1186,6 +1186,12 @@ post_soft_reset:
        /* Registers could be dirty after soft reset or SoundWire enumeration */
        regcache_sync(cs35l56->base.regmap);
 
+       /* Set ASP1 DOUT to high-impedance when it is not transmitting audio data. */
+       ret = regmap_set_bits(cs35l56->base.regmap, CS35L56_ASP1_CONTROL3,
+                             CS35L56_ASP1_DOUT_HIZ_CTRL_MASK);
+       if (ret)
+               return dev_err_probe(cs35l56->base.dev, ret, "Failed to write ASP1_CONTROL3\n");
+
        cs35l56->base.init_done = true;
        complete(&cs35l56->init_completion);
 
@@ -1207,6 +1213,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 eeab07c850f9582e918815b44c2698fb5d3995f1..94a66a325303b673e30565192ea5af18353ac1b9 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <linux/acpi.h>
 #include <linux/device.h>
+#include <linux/gpio/consumer.h>
 #include <linux/iopoll.h>
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
@@ -344,6 +345,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 +365,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 a0de0329406a1ff2ea3dc8a29f4ec510335553dd..2961340f15e2ed05d7c551c8d5f68fd557181bdc 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 4bd7b85a5747158ecf808c41d970eaa4c15066ab..7785125b73ab9342f70bb3438d69693b6710688b 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 92e37bc1df9dcc640ea0220e0c165499ab36e3bb..9f5f1a92561d1ee3df8d79a467652f54e844c28e 100644 (file)
@@ -34,7 +34,7 @@ static const unsigned int cs42l43_accdet_db_ms[] = {
 static const unsigned int cs42l43_accdet_ramp_ms[] = { 10, 40, 90, 170 };
 
 static const unsigned int cs42l43_accdet_bias_sense[] = {
-       14, 23, 41, 50, 60, 68, 86, 95, 0,
+       14, 24, 43, 52, 61, 71, 90, 99, 0,
 };
 
 static int cs42l43_find_index(struct cs42l43_codec *priv, const char * const prop,
index 1a95c370fc4c9d6687650fe7a06f37d95c884084..5643c666d7d04bf2e507126a7ba4d28430b6925f 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 581b334a6631d72de5818d035cb1fbc331173f18..3bbe850916493249522c10e5bad4256112344efd 100644 (file)
@@ -59,9 +59,6 @@ static void da7219_aad_btn_det_work(struct work_struct *work)
        bool micbias_up = false;
        int retries = 0;
 
-       /* Disable ground switch */
-       snd_soc_component_update_bits(component, 0xFB, 0x01, 0x00);
-
        /* Drive headphones/lineout */
        snd_soc_component_update_bits(component, DA7219_HP_L_CTRL,
                            DA7219_HP_L_AMP_OE_MASK,
@@ -155,9 +152,6 @@ static void da7219_aad_hptest_work(struct work_struct *work)
                tonegen_freq_hptest = cpu_to_le16(DA7219_AAD_HPTEST_RAMP_FREQ_INT_OSC);
        }
 
-       /* Disable ground switch */
-       snd_soc_component_update_bits(component, 0xFB, 0x01, 0x00);
-
        /* Ensure gain ramping at fastest rate */
        gain_ramp_ctrl = snd_soc_component_read(component, DA7219_GAIN_RAMP_CTRL);
        snd_soc_component_write(component, DA7219_GAIN_RAMP_CTRL, DA7219_GAIN_RAMP_RATE_X8);
@@ -421,6 +415,11 @@ static irqreturn_t da7219_aad_irq_thread(int irq, void *data)
                         * handle a removal, and we can check at the end of
                         * hptest if we have a valid result or not.
                         */
+
+                       cancel_delayed_work_sync(&da7219_aad->jack_det_work);
+                       /* Disable ground switch */
+                       snd_soc_component_update_bits(component, 0xFB, 0x01, 0x00);
+
                        if (statusa & DA7219_JACK_TYPE_STS_MASK) {
                                report |= SND_JACK_HEADSET;
                                mask |= SND_JACK_HEADSET | SND_JACK_LINEOUT;
index 13689e718d36fee41152fe688ea043f7aa333a31..09eef6042aad6d53ad91fcef1cfe365f91c768be 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 ec6859ec0d38eca2e0db949e4cb1f87710a0c488..fff4a8b862a73200bcb7d411571e0664c8965f20 100644 (file)
@@ -1675,12 +1675,12 @@ static int wsa_macro_spk_boost_event(struct snd_soc_dapm_widget *w,
        u16 boost_path_ctl, boost_path_cfg1;
        u16 reg, reg_mix;
 
-       if (!strcmp(w->name, "WSA_RX INT0 CHAIN")) {
+       if (!snd_soc_dapm_widget_name_cmp(w, "WSA_RX INT0 CHAIN")) {
                boost_path_ctl = CDC_WSA_BOOST0_BOOST_PATH_CTL;
                boost_path_cfg1 = CDC_WSA_RX0_RX_PATH_CFG1;
                reg = CDC_WSA_RX0_RX_PATH_CTL;
                reg_mix = CDC_WSA_RX0_RX_PATH_MIX_CTL;
-       } else if (!strcmp(w->name, "WSA_RX INT1 CHAIN")) {
+       } else if (!snd_soc_dapm_widget_name_cmp(w, "WSA_RX INT1 CHAIN")) {
                boost_path_ctl = CDC_WSA_BOOST1_BOOST_PATH_CTL;
                boost_path_cfg1 = CDC_WSA_RX1_RX_PATH_CFG1;
                reg = CDC_WSA_RX1_RX_PATH_CTL;
index 15e1a62b9e571053284e3a2e8e8466fd5faf290f..e8cdc166bdaa99a948b03966d8cf67dbf49e7440 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 1a137ca3f496473b34cd26f688d2c22bb042b821..7938b52d741d8cd6f354ca61a149db09b41cede2 100644 (file)
@@ -3257,6 +3257,8 @@ int rt5645_set_jack_detect(struct snd_soc_component *component,
                                RT5645_GP1_PIN_IRQ, RT5645_GP1_PIN_IRQ);
                regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL1,
                                RT5645_DIG_GATE_CTRL, RT5645_DIG_GATE_CTRL);
+               regmap_update_bits(rt5645->regmap, RT5645_DEPOP_M1,
+                               RT5645_HP_CB_MASK, RT5645_HP_CB_PU);
        }
        rt5645_irq(0, rt5645);
 
index b05b4f73d8aa7311fc1f82043564727f579c3bfc..fbad1ed066260194285d2151769d0533527a0b65 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 86bd6c18a944012932d8a366e65b4b0969890b54..41076be238542bbe4ee94a44acff6c2ece4e8d31 100644 (file)
@@ -39,7 +39,7 @@ static void tas2780_reset(struct tas2780_priv *tas2780)
                usleep_range(2000, 2050);
        }
 
-       snd_soc_component_write(tas2780->component, TAS2780_SW_RST,
+       ret = snd_soc_component_write(tas2780->component, TAS2780_SW_RST,
                                TAS2780_RST);
        if (ret)
                dev_err(tas2780->dev, "%s:errCode:0x%x Reset error!\n",
index b976c1946286a9c07f65b048c683373a7112b12a..420bbf588efeaf1c0cc1d7700fa3d572ad6e816e 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 6951120057e55d97f9f6513363f354aa4ef03c7d..a1f04010da95f60278071292254d4f3489a40bba 100644 (file)
@@ -1278,7 +1278,31 @@ static int wcd9380_probe(struct sdw_slave *pdev,
        pm_runtime_set_active(dev);
        pm_runtime_enable(dev);
 
-       return component_add(dev, &wcd938x_sdw_component_ops);
+       ret = component_add(dev, &wcd938x_sdw_component_ops);
+       if (ret)
+               goto err_disable_rpm;
+
+       return 0;
+
+err_disable_rpm:
+       pm_runtime_disable(dev);
+       pm_runtime_set_suspended(dev);
+       pm_runtime_dont_use_autosuspend(dev);
+
+       return ret;
+}
+
+static int wcd9380_remove(struct sdw_slave *pdev)
+{
+       struct device *dev = &pdev->dev;
+
+       component_del(dev, &wcd938x_sdw_component_ops);
+
+       pm_runtime_disable(dev);
+       pm_runtime_set_suspended(dev);
+       pm_runtime_dont_use_autosuspend(dev);
+
+       return 0;
 }
 
 static const struct sdw_device_id wcd9380_slave_id[] = {
@@ -1320,6 +1344,7 @@ static const struct dev_pm_ops wcd938x_sdw_pm_ops = {
 
 static struct sdw_driver wcd9380_codec_driver = {
        .probe  = wcd9380_probe,
+       .remove = wcd9380_remove,
        .ops = &wcd9380_slave_ops,
        .id_table = wcd9380_slave_id,
        .driver = {
index a3c68066137775e62f7239244849159164f2e3f3..d27b919c63b4197e49331a57375ac784efbeb3d7 100644 (file)
@@ -3325,8 +3325,10 @@ static int wcd938x_populate_dt_data(struct wcd938x_priv *wcd938x, struct device
                return dev_err_probe(dev, ret, "Failed to get supplies\n");
 
        ret = regulator_bulk_enable(WCD938X_MAX_SUPPLY, wcd938x->supplies);
-       if (ret)
+       if (ret) {
+               regulator_bulk_free(WCD938X_MAX_SUPPLY, wcd938x->supplies);
                return dev_err_probe(dev, ret, "Failed to enable supplies\n");
+       }
 
        wcd938x_dt_parse_micbias_info(dev, wcd938x);
 
@@ -3435,7 +3437,8 @@ static int wcd938x_bind(struct device *dev)
        wcd938x->rxdev = wcd938x_sdw_device_get(wcd938x->rxnode);
        if (!wcd938x->rxdev) {
                dev_err(dev, "could not find slave with matching of node\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto err_unbind;
        }
        wcd938x->sdw_priv[AIF1_PB] = dev_get_drvdata(wcd938x->rxdev);
        wcd938x->sdw_priv[AIF1_PB]->wcd938x = wcd938x;
@@ -3443,46 +3446,47 @@ static int wcd938x_bind(struct device *dev)
        wcd938x->txdev = wcd938x_sdw_device_get(wcd938x->txnode);
        if (!wcd938x->txdev) {
                dev_err(dev, "could not find txslave with matching of node\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto err_put_rxdev;
        }
        wcd938x->sdw_priv[AIF1_CAP] = dev_get_drvdata(wcd938x->txdev);
        wcd938x->sdw_priv[AIF1_CAP]->wcd938x = wcd938x;
        wcd938x->tx_sdw_dev = dev_to_sdw_dev(wcd938x->txdev);
-       if (!wcd938x->tx_sdw_dev) {
-               dev_err(dev, "could not get txslave with matching of dev\n");
-               return -EINVAL;
-       }
 
        /* As TX is main CSR reg interface, which should not be suspended first.
         * expicilty add the dependency link */
        if (!device_link_add(wcd938x->rxdev, wcd938x->txdev, DL_FLAG_STATELESS |
                            DL_FLAG_PM_RUNTIME)) {
                dev_err(dev, "could not devlink tx and rx\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto err_put_txdev;
        }
 
        if (!device_link_add(dev, wcd938x->txdev, DL_FLAG_STATELESS |
                                        DL_FLAG_PM_RUNTIME)) {
                dev_err(dev, "could not devlink wcd and tx\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto err_remove_rxtx_link;
        }
 
        if (!device_link_add(dev, wcd938x->rxdev, DL_FLAG_STATELESS |
                                        DL_FLAG_PM_RUNTIME)) {
                dev_err(dev, "could not devlink wcd and rx\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto err_remove_tx_link;
        }
 
        wcd938x->regmap = dev_get_regmap(&wcd938x->tx_sdw_dev->dev, NULL);
        if (!wcd938x->regmap) {
                dev_err(dev, "could not get TX device regmap\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto err_remove_rx_link;
        }
 
        ret = wcd938x_irq_init(wcd938x, dev);
        if (ret) {
                dev_err(dev, "%s: IRQ init failed: %d\n", __func__, ret);
-               return ret;
+               goto err_remove_rx_link;
        }
 
        wcd938x->sdw_priv[AIF1_PB]->slave_irq = wcd938x->virq;
@@ -3491,27 +3495,45 @@ static int wcd938x_bind(struct device *dev)
        ret = wcd938x_set_micbias_data(wcd938x);
        if (ret < 0) {
                dev_err(dev, "%s: bad micbias pdata\n", __func__);
-               return ret;
+               goto err_remove_rx_link;
        }
 
        ret = snd_soc_register_component(dev, &soc_codec_dev_wcd938x,
                                         wcd938x_dais, ARRAY_SIZE(wcd938x_dais));
-       if (ret)
+       if (ret) {
                dev_err(dev, "%s: Codec registration failed\n",
                                __func__);
+               goto err_remove_rx_link;
+       }
 
-       return ret;
+       return 0;
 
+err_remove_rx_link:
+       device_link_remove(dev, wcd938x->rxdev);
+err_remove_tx_link:
+       device_link_remove(dev, wcd938x->txdev);
+err_remove_rxtx_link:
+       device_link_remove(wcd938x->rxdev, wcd938x->txdev);
+err_put_txdev:
+       put_device(wcd938x->txdev);
+err_put_rxdev:
+       put_device(wcd938x->rxdev);
+err_unbind:
+       component_unbind_all(dev, wcd938x);
+
+       return ret;
 }
 
 static void wcd938x_unbind(struct device *dev)
 {
        struct wcd938x_priv *wcd938x = dev_get_drvdata(dev);
 
+       snd_soc_unregister_component(dev);
        device_link_remove(dev, wcd938x->txdev);
        device_link_remove(dev, wcd938x->rxdev);
        device_link_remove(wcd938x->rxdev, wcd938x->txdev);
-       snd_soc_unregister_component(dev);
+       put_device(wcd938x->txdev);
+       put_device(wcd938x->rxdev);
        component_unbind_all(dev, wcd938x);
 }
 
@@ -3572,13 +3594,13 @@ static int wcd938x_probe(struct platform_device *pdev)
 
        ret = wcd938x_add_slave_components(wcd938x, dev, &match);
        if (ret)
-               return ret;
+               goto err_disable_regulators;
 
        wcd938x_reset(wcd938x);
 
        ret = component_master_add_with_match(dev, &wcd938x_comp_ops, match);
        if (ret)
-               return ret;
+               goto err_disable_regulators;
 
        pm_runtime_set_autosuspend_delay(dev, 1000);
        pm_runtime_use_autosuspend(dev);
@@ -3588,11 +3610,27 @@ static int wcd938x_probe(struct platform_device *pdev)
        pm_runtime_idle(dev);
 
        return 0;
+
+err_disable_regulators:
+       regulator_bulk_disable(WCD938X_MAX_SUPPLY, wcd938x->supplies);
+       regulator_bulk_free(WCD938X_MAX_SUPPLY, wcd938x->supplies);
+
+       return ret;
 }
 
 static void wcd938x_remove(struct platform_device *pdev)
 {
-       component_master_del(&pdev->dev, &wcd938x_comp_ops);
+       struct device *dev = &pdev->dev;
+       struct wcd938x_priv *wcd938x = dev_get_drvdata(dev);
+
+       component_master_del(dev, &wcd938x_comp_ops);
+
+       pm_runtime_disable(dev);
+       pm_runtime_set_suspended(dev);
+       pm_runtime_dont_use_autosuspend(dev);
+
+       regulator_bulk_disable(WCD938X_MAX_SUPPLY, wcd938x->supplies);
+       regulator_bulk_free(WCD938X_MAX_SUPPLY, wcd938x->supplies);
 }
 
 #if defined(CONFIG_OF)
index 0a50180750e8815c42040b4e433cd2f0381d3148..7689fe3cc86d657e332b820c94cb87396344ab9d 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 6fc34f41b1758094acb4ba653eeb1bb023712399..d1b9238d391e81c089e43a85534d77846d77e440 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 22c004179214d2973efdac2d5fa10300f9ec587b..9ea4be56d3b7092a8242ea545d9fb5ca6557ef21 100644 (file)
@@ -917,7 +917,7 @@ static int jh7110_i2stx0_clk_cfg(struct i2s_clk_config_data *config)
 
 static int dw_i2s_probe(struct platform_device *pdev)
 {
-       const struct i2s_platform_data *pdata = of_device_get_match_data(&pdev->dev);
+       const struct i2s_platform_data *pdata = pdev->dev.platform_data;
        struct dw_i2s_dev *dev;
        struct resource *res;
        int ret, irq;
index 76b5bfc288fde069e956ce74989fca71cbb1d246..bab7d34cf585bfed41bee48c8e6bce74ddd36e65 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 1e4020fae05abbbb55c403d261a50ba857b31e3e..8a9a30dd31e208d697b67c1a6788bc66e853fc38 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 0b58df56f4daa831baffc5dd294bfbc458add70e..aeb81aa61184fbc0889765ac1573a0a23ef3c2c6 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 d63782b8bdef8f8b27d9669dabdc550cd0445f5a..bb736d45c9e04e5de7de46698d55b1b16b5a8718 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 3c7b95db2eacc182b9d56a71c0847e76a5c910e0..b578f9a32d7f1cd62e9bdf4d84b92063a74c334d 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 5b18a4af022f19a1c14cf734f1df0f1f8609f64d..2588ec735dbdf2b2da39d85a6aeb7bc1c40b5c53 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 190f11366e84e0075625604f341d633f4b0075dd..274417e39e7de0972e0132846d944094843e650c 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 cb00bc86ac949a5a5592da5a40768271d88e87ba..8876558f19a1bacfd4b7d5b575b25602d885b68a 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 f8a3e8a91761aaf6903c4f1f50fcc1b1c00a463d..9904a9e33cccbec5f257e0d4678b8e85ba668b28 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 5a1c750e6ae6aeb368b53c7d6f801119960502b0..842649501e303afd0b078c1dd721065bc7244747 100644 (file)
@@ -376,6 +376,16 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
                /* 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, "0B14"),
+               },
+               /* No Jack */
+               .driver_data = (void *)SOF_SDW_TGL_HDMI,
+       },
+
        {
                .callback = sof_sdw_quirk_cb,
                .matches = {
index 8e995edf4c10da3e5328009eb1c027fb29e03f77..5103e75ac8309c898eb3449f414f262b400ff065 100644 (file)
@@ -655,18 +655,18 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_sdw_machines[] = {
                .drv_name = "sof_sdw",
                .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,
index 0304246d292238323d917902e241013662a4c44a..92498d1d6c8d761fdca339f65d7af2f0ad441609 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 d8688016907525eb80e6dd014e12d2916237b118..bc2f2849ecfbce1f5e12d8cdc7d56858b6c56798 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 b70034c07eeea517b2a4dc2bff6f3bf708497ac5..b8a3cb8b75978e8fa15d1270f12240f884ab24ca 100644 (file)
@@ -773,7 +773,7 @@ static int pxa_ssp_probe(struct snd_soc_dai *dai)
                if (IS_ERR(priv->extclk)) {
                        ret = PTR_ERR(priv->extclk);
                        if (ret == -EPROBE_DEFER)
-                               return ret;
+                               goto err_priv;
 
                        priv->extclk = NULL;
                }
index e29c2fee9521943bd961b5725b30a9024a00e72b..1bd7114c472a8bb8c9032a599b0da385710ee820 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 ba7c0ae82e0079ba5531307bfed98cab66d9e357..566033f7dd2ea7531e38730a3c091b4622b82688 100644 (file)
@@ -242,6 +242,7 @@ int snd_soc_component_notify_control(struct snd_soc_component *component,
        char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
        struct snd_kcontrol *kctl;
 
+       /* When updating, change also snd_soc_dapm_widget_name_cmp() */
        if (component->name_prefix)
                snprintf(name, ARRAY_SIZE(name), "%s %s", component->name_prefix, ctl);
        else
index cc442c52cdea959f9ddf9cddc0e84330effc61d6..9de98c01d815175f772f0e150fc710bad68edddb 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 f07e836783737ba4d54c948a88f103483853de9e..312e55579831563db5e4380d2b24a0c0af012a0c 100644 (file)
@@ -2728,6 +2728,18 @@ int snd_soc_dapm_update_dai(struct snd_pcm_substream *substream,
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_update_dai);
 
+int snd_soc_dapm_widget_name_cmp(struct snd_soc_dapm_widget *widget, const char *s)
+{
+       struct snd_soc_component *component = snd_soc_dapm_to_component(widget->dapm);
+       const char *wname = widget->name;
+
+       if (component->name_prefix)
+               wname += strlen(component->name_prefix) + 1; /* plus space */
+
+       return strcmp(wname, s);
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_widget_name_cmp);
+
 /*
  * dapm_update_widget_flags() - Re-compute widget sink and source flags
  * @w: The widget for which to update the flags
index d0653d775c87ac1f22b274f6aea9426210827bf4..cad222eb9a293a6dfb9fad3d1aeb5e68ddb7fd2f 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 eb07238768511a7c7478a6a2556e5a72f0b52ec0..54704250c0a2c43e42ad09ce631953233c444b1e 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 11607c5f5d5a82f4c8c97abb7e6582cfca36677c..9c746e4edef71c2e9cfa94b8ed4fc61b888c8c54 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 9935e457b467b02b1609e31c40ab3a0e480719af..a7ae76efc2dddb480c0415bf02b75dab20878c24 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 30db685cc5f4b99ae47fe95e9367abc330c2b349..2d1616b81485c53b0f436ef57bcbabaebb03c184 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 b84ca58da9d5da72d4158dabd51564f046630fe7..f9412517eaf29be8345c00ad574ed643dd2066d5 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 02181490f12a6f1b550e0463dcae039161a0993b..95696b3d7c4cfbadb5a3307954a0c9ace19e07cd 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 f2a30cd3137875b69a3f6248d50267dcff24d193..7cb63e6b24dc96f59eea968ae1f718990dedbe18 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 e7ef77012c3586649f364d538c42ab4c89496c48..e5405f854a910c279596b6803c73d9d21b9170c1 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 1f2c5018bf5aceded1267d64d5974dc8e3495ec5..4737e776d3837d60135523f64e1dc89f298e23e0 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 371943350fdf9b09c1e0e9d1fa4e2e3dc2fb7f59..666057d50ea0d2fb6d920bd0432704535496ff95 100644 (file)
@@ -336,8 +336,8 @@ static void cx81801_hangup(struct tty_struct *tty)
 }
 
 /* Line discipline .receive_buf() */
-static void cx81801_receive(struct tty_struct *tty, const u8 *cp,
-               const char *fp, int count)
+static void cx81801_receive(struct tty_struct *tty, const u8 *cp, const u8 *fp,
+                           size_t count)
 {
        struct snd_soc_component *component = tty->disc_data;
        const unsigned char *c;
index 49f63f878e6fe8b7acbaa363dfebf3b2114dd753..b5cbf1f195c48cbe16c0da96488880fcad450b10 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 9105ec623120a964802af82502b247bd9df47051..409fc11646948e40ec6b03be6840c150c04db8b7 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 9d11bb08667e7a664017a5ec8530e5ff4ade91f9..d260be8cb6bc03e8c5c2b2a3dc5ff5759ff2588d 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 598659d761cc94a419b7df7960dcd502bf4188e4..4e64842245e1900f160ef0687ed1e8d7da3dcaac 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 63b0398c327656b543cca5962bb8991ee8b287cd..55ecf766ca6780447d1ed9103328366bfa7f57b2 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 a00a53e15ab73883e2d289aabe06db84b3208e8a..1d111350197f3169a8eec402d77980dd617c6b95 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 4798f9d18fe881650c0b2bbdbed93fa59c262753..9de35df1afc31f7e66fd014c9fce250900dd1ca5 100644 (file)
@@ -26,6 +26,6 @@
 #ifndef __NR_setns
 #define __NR_setns 346
 #endif
-#ifdef __NR_seccomp
+#ifndef __NR_seccomp
 #define __NR_seccomp 354
 #endif
diff --git a/tools/build/feature/test-llvm.cpp b/tools/build/feature/test-llvm.cpp
new file mode 100644 (file)
index 0000000..88a3d1b
--- /dev/null
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/raw_ostream.h"
+#define NUM_VERSION (((LLVM_VERSION_MAJOR) << 16) + (LLVM_VERSION_MINOR << 8) + LLVM_VERSION_PATCH)
+
+#if NUM_VERSION < 0x030900
+# error "LLVM version too low"
+#endif
+int main()
+{
+       llvm::errs() << "Hello World!\n";
+       llvm::llvm_shutdown();
+       return 0;
+}
index 27f5e7dfc2f761ad2d2ec9ff8fba996ef046d319..264eeb9c46a9f5ea9264829b41eda164e72d0d2e 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 d10fe35b7f259d4928816626d72d7986fde6dcba..ae5a7a8249a208cf5782e8627ba4354959d38e2b 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 71e54b1e379645fd8ce2233801f3e2c619699ee6..2f882d5cb30f5c014af5deec2738f8460dcc23ad 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 a03d9bba515148a72192cf2b9cddab32d047858d..f3c82ab5b14cd77819030096b81e0b67cba0df1d 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)
 {
diff --git a/tools/include/linux/rwsem.h b/tools/include/linux/rwsem.h
new file mode 100644 (file)
index 0000000..83971b3
--- /dev/null
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+#ifndef _TOOLS__RWSEM_H
+#define _TOOLS__RWSEM_H
+
+#include <pthread.h>
+
+struct rw_semaphore {
+       pthread_rwlock_t lock;
+};
+
+static inline int init_rwsem(struct rw_semaphore *sem)
+{
+       return pthread_rwlock_init(&sem->lock, NULL);
+}
+
+static inline int exit_rwsem(struct rw_semaphore *sem)
+{
+       return pthread_rwlock_destroy(&sem->lock);
+}
+
+static inline int down_read(struct rw_semaphore *sem)
+{
+       return pthread_rwlock_rdlock(&sem->lock);
+}
+
+static inline int up_read(struct rw_semaphore *sem)
+{
+       return pthread_rwlock_unlock(&sem->lock);
+}
+
+static inline int down_write(struct rw_semaphore *sem)
+{
+       return pthread_rwlock_wrlock(&sem->lock);
+}
+
+static inline int up_write(struct rw_semaphore *sem)
+{
+       return pthread_rwlock_unlock(&sem->lock);
+}
+#endif /* _TOOLS_RWSEM_H */
index 102fd9217f1f9b96438f14e7d9ef643d123ebc43..f6bc226af0c1d1c4d26c1c2d3f7a963c34c728eb 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 64415b9fac77f9960e2e643ae69789f23b3f890b..28c26a00a7625f5597020673b740b7cb40e60446 100644 (file)
@@ -167,7 +167,9 @@ void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_
        __asm__ volatile (
                "xor  %ebp, %ebp\n"       /* zero the stack frame                                */
                "mov  %esp, %eax\n"       /* save stack pointer to %eax, as arg1 of _start_c     */
-               "and  $-16, %esp\n"       /* last pushed argument must be 16-byte aligned        */
+               "add  $12, %esp\n"        /* avoid over-estimating after the 'and' & 'sub' below */
+               "and  $-16, %esp\n"       /* the %esp must be 16-byte aligned on 'call'          */
+               "sub  $12, %esp\n"        /* sub 12 to keep it aligned after the push %eax       */
                "push %eax\n"             /* push arg1 on stack to support plain stack modes too */
                "call _start_c\n"         /* transfer to c runtime                               */
                "hlt\n"                   /* ensure it does not return                           */
index a5f33fef167204417f92ec8620133313cca32c18..a05655b4ce1d7f132c0ae782ec47df9bb077f5ac 100644 (file)
@@ -13,6 +13,7 @@ const unsigned long *_auxv __attribute__((weak));
 static void __stack_chk_init(void);
 static void exit(int);
 
+__attribute__((weak))
 void _start_c(long *sp)
 {
        long argc;
index fd6c1cb585db43c4e9bbbcffc8ee19a34325debe..abe087c53b4b04348431716c1cb638b99d5a788a 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 a87bbbbca2d48ada91efcc8aaab469ba51f0224a..794c1d857677d9b9b2e20222f671f15fbb86c4aa 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 8790b3962e4b85f22593f8f9c9f8d94eaf6981f3..0448700890f77d9a4fffa6fed5c17aa02b9f718b 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 3a8d8499fab6e68b950a5c04861c0d643906883a..2cb2518500cbb7018d4eaaa3b7992f25f44c8cca 100644 (file)
 static const char * const devlink_op_strmap[] = {
        [3] = "get",
        [7] = "port-get",
-       [DEVLINK_CMD_SB_GET] = "sb-get",
-       [DEVLINK_CMD_SB_POOL_GET] = "sb-pool-get",
-       [DEVLINK_CMD_SB_PORT_POOL_GET] = "sb-port-pool-get",
-       [DEVLINK_CMD_SB_TC_POOL_BIND_GET] = "sb-tc-pool-bind-get",
+       [13] = "sb-get",
+       [17] = "sb-pool-get",
+       [21] = "sb-port-pool-get",
+       [25] = "sb-tc-pool-bind-get",
        [DEVLINK_CMD_PARAM_GET] = "param-get",
        [DEVLINK_CMD_REGION_GET] = "region-get",
        [DEVLINK_CMD_INFO_GET] = "info-get",
        [DEVLINK_CMD_HEALTH_REPORTER_GET] = "health-reporter-get",
-       [DEVLINK_CMD_TRAP_GET] = "trap-get",
-       [DEVLINK_CMD_TRAP_GROUP_GET] = "trap-group-get",
-       [DEVLINK_CMD_TRAP_POLICER_GET] = "trap-policer-get",
-       [DEVLINK_CMD_RATE_GET] = "rate-get",
-       [DEVLINK_CMD_LINECARD_GET] = "linecard-get",
+       [63] = "trap-get",
+       [67] = "trap-group-get",
+       [71] = "trap-policer-get",
+       [76] = "rate-get",
+       [80] = "linecard-get",
        [DEVLINK_CMD_SELFTESTS_GET] = "selftests-get",
 };
 
@@ -838,7 +838,7 @@ devlink_sb_get(struct ynl_sock *ys, struct devlink_sb_get_req *req)
        rsp = calloc(1, sizeof(*rsp));
        yrs.yarg.data = rsp;
        yrs.cb = devlink_sb_get_rsp_parse;
-       yrs.rsp_cmd = DEVLINK_CMD_SB_GET;
+       yrs.rsp_cmd = 13;
 
        err = ynl_exec(ys, nlh, &yrs);
        if (err < 0)
@@ -876,7 +876,7 @@ devlink_sb_get_dump(struct ynl_sock *ys, struct devlink_sb_get_req_dump *req)
        yds.ys = ys;
        yds.alloc_sz = sizeof(struct devlink_sb_get_list);
        yds.cb = devlink_sb_get_rsp_parse;
-       yds.rsp_cmd = DEVLINK_CMD_SB_GET;
+       yds.rsp_cmd = 13;
        yds.rsp_policy = &devlink_nest;
 
        nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_SB_GET, 1);
@@ -987,7 +987,7 @@ devlink_sb_pool_get(struct ynl_sock *ys, struct devlink_sb_pool_get_req *req)
        rsp = calloc(1, sizeof(*rsp));
        yrs.yarg.data = rsp;
        yrs.cb = devlink_sb_pool_get_rsp_parse;
-       yrs.rsp_cmd = DEVLINK_CMD_SB_POOL_GET;
+       yrs.rsp_cmd = 17;
 
        err = ynl_exec(ys, nlh, &yrs);
        if (err < 0)
@@ -1026,7 +1026,7 @@ devlink_sb_pool_get_dump(struct ynl_sock *ys,
        yds.ys = ys;
        yds.alloc_sz = sizeof(struct devlink_sb_pool_get_list);
        yds.cb = devlink_sb_pool_get_rsp_parse;
-       yds.rsp_cmd = DEVLINK_CMD_SB_POOL_GET;
+       yds.rsp_cmd = 17;
        yds.rsp_policy = &devlink_nest;
 
        nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_SB_POOL_GET, 1);
@@ -1147,7 +1147,7 @@ devlink_sb_port_pool_get(struct ynl_sock *ys,
        rsp = calloc(1, sizeof(*rsp));
        yrs.yarg.data = rsp;
        yrs.cb = devlink_sb_port_pool_get_rsp_parse;
-       yrs.rsp_cmd = DEVLINK_CMD_SB_PORT_POOL_GET;
+       yrs.rsp_cmd = 21;
 
        err = ynl_exec(ys, nlh, &yrs);
        if (err < 0)
@@ -1187,7 +1187,7 @@ devlink_sb_port_pool_get_dump(struct ynl_sock *ys,
        yds.ys = ys;
        yds.alloc_sz = sizeof(struct devlink_sb_port_pool_get_list);
        yds.cb = devlink_sb_port_pool_get_rsp_parse;
-       yds.rsp_cmd = DEVLINK_CMD_SB_PORT_POOL_GET;
+       yds.rsp_cmd = 21;
        yds.rsp_policy = &devlink_nest;
 
        nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_SB_PORT_POOL_GET, 1);
@@ -1316,7 +1316,7 @@ devlink_sb_tc_pool_bind_get(struct ynl_sock *ys,
        rsp = calloc(1, sizeof(*rsp));
        yrs.yarg.data = rsp;
        yrs.cb = devlink_sb_tc_pool_bind_get_rsp_parse;
-       yrs.rsp_cmd = DEVLINK_CMD_SB_TC_POOL_BIND_GET;
+       yrs.rsp_cmd = 25;
 
        err = ynl_exec(ys, nlh, &yrs);
        if (err < 0)
@@ -1356,7 +1356,7 @@ devlink_sb_tc_pool_bind_get_dump(struct ynl_sock *ys,
        yds.ys = ys;
        yds.alloc_sz = sizeof(struct devlink_sb_tc_pool_bind_get_list);
        yds.cb = devlink_sb_tc_pool_bind_get_rsp_parse;
-       yds.rsp_cmd = DEVLINK_CMD_SB_TC_POOL_BIND_GET;
+       yds.rsp_cmd = 25;
        yds.rsp_policy = &devlink_nest;
 
        nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_SB_TC_POOL_BIND_GET, 1);
@@ -2183,7 +2183,7 @@ devlink_trap_get(struct ynl_sock *ys, struct devlink_trap_get_req *req)
        rsp = calloc(1, sizeof(*rsp));
        yrs.yarg.data = rsp;
        yrs.cb = devlink_trap_get_rsp_parse;
-       yrs.rsp_cmd = DEVLINK_CMD_TRAP_GET;
+       yrs.rsp_cmd = 63;
 
        err = ynl_exec(ys, nlh, &yrs);
        if (err < 0)
@@ -2223,7 +2223,7 @@ devlink_trap_get_dump(struct ynl_sock *ys,
        yds.ys = ys;
        yds.alloc_sz = sizeof(struct devlink_trap_get_list);
        yds.cb = devlink_trap_get_rsp_parse;
-       yds.rsp_cmd = DEVLINK_CMD_TRAP_GET;
+       yds.rsp_cmd = 63;
        yds.rsp_policy = &devlink_nest;
 
        nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_TRAP_GET, 1);
@@ -2336,7 +2336,7 @@ devlink_trap_group_get(struct ynl_sock *ys,
        rsp = calloc(1, sizeof(*rsp));
        yrs.yarg.data = rsp;
        yrs.cb = devlink_trap_group_get_rsp_parse;
-       yrs.rsp_cmd = DEVLINK_CMD_TRAP_GROUP_GET;
+       yrs.rsp_cmd = 67;
 
        err = ynl_exec(ys, nlh, &yrs);
        if (err < 0)
@@ -2376,7 +2376,7 @@ devlink_trap_group_get_dump(struct ynl_sock *ys,
        yds.ys = ys;
        yds.alloc_sz = sizeof(struct devlink_trap_group_get_list);
        yds.cb = devlink_trap_group_get_rsp_parse;
-       yds.rsp_cmd = DEVLINK_CMD_TRAP_GROUP_GET;
+       yds.rsp_cmd = 67;
        yds.rsp_policy = &devlink_nest;
 
        nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_TRAP_GROUP_GET, 1);
@@ -2483,7 +2483,7 @@ devlink_trap_policer_get(struct ynl_sock *ys,
        rsp = calloc(1, sizeof(*rsp));
        yrs.yarg.data = rsp;
        yrs.cb = devlink_trap_policer_get_rsp_parse;
-       yrs.rsp_cmd = DEVLINK_CMD_TRAP_POLICER_GET;
+       yrs.rsp_cmd = 71;
 
        err = ynl_exec(ys, nlh, &yrs);
        if (err < 0)
@@ -2523,7 +2523,7 @@ devlink_trap_policer_get_dump(struct ynl_sock *ys,
        yds.ys = ys;
        yds.alloc_sz = sizeof(struct devlink_trap_policer_get_list);
        yds.cb = devlink_trap_policer_get_rsp_parse;
-       yds.rsp_cmd = DEVLINK_CMD_TRAP_POLICER_GET;
+       yds.rsp_cmd = 71;
        yds.rsp_policy = &devlink_nest;
 
        nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_TRAP_POLICER_GET, 1);
@@ -2642,7 +2642,7 @@ devlink_rate_get(struct ynl_sock *ys, struct devlink_rate_get_req *req)
        rsp = calloc(1, sizeof(*rsp));
        yrs.yarg.data = rsp;
        yrs.cb = devlink_rate_get_rsp_parse;
-       yrs.rsp_cmd = DEVLINK_CMD_RATE_GET;
+       yrs.rsp_cmd = 76;
 
        err = ynl_exec(ys, nlh, &yrs);
        if (err < 0)
@@ -2682,7 +2682,7 @@ devlink_rate_get_dump(struct ynl_sock *ys,
        yds.ys = ys;
        yds.alloc_sz = sizeof(struct devlink_rate_get_list);
        yds.cb = devlink_rate_get_rsp_parse;
-       yds.rsp_cmd = DEVLINK_CMD_RATE_GET;
+       yds.rsp_cmd = 76;
        yds.rsp_policy = &devlink_nest;
 
        nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_RATE_GET, 1);
@@ -2786,7 +2786,7 @@ devlink_linecard_get(struct ynl_sock *ys, struct devlink_linecard_get_req *req)
        rsp = calloc(1, sizeof(*rsp));
        yrs.yarg.data = rsp;
        yrs.cb = devlink_linecard_get_rsp_parse;
-       yrs.rsp_cmd = DEVLINK_CMD_LINECARD_GET;
+       yrs.rsp_cmd = 80;
 
        err = ynl_exec(ys, nlh, &yrs);
        if (err < 0)
@@ -2825,7 +2825,7 @@ devlink_linecard_get_dump(struct ynl_sock *ys,
        yds.ys = ys;
        yds.alloc_sz = sizeof(struct devlink_linecard_get_list);
        yds.cb = devlink_linecard_get_rsp_parse;
-       yds.rsp_cmd = DEVLINK_CMD_LINECARD_GET;
+       yds.rsp_cmd = 80;
        yds.rsp_policy = &devlink_nest;
 
        nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_LINECARD_GET, 1);
index cfda2511badf3ad0f4ca561eab0b01fd538495f5..cb5e757f6621c885f441e3f258591b0f32ffb84b 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 8c0b08b7a80ec4b75fbc059054cf745ac89ad3dc..20e50586e8a26c345b89682b7078e929034edfa5 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 a6935af2235cab6cbc993a2efdb3e6fb18abcaeb..0122cc156952cf55b630584a983702d12eddcc62 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 227538b0ce801eeba96e10d8214e7847b77cee88..1d6eee30eceb22abb1b9f7916a91b25823579e24 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 b04ebcde4036163660b79efd792f69e80da553b9..a01c40131493b76dc75c354b2e60b5321944d198 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 4314c91978509a49fc93dfe25a5070279f4f589f..e21caadda7c11566c9ceefcc427bf87d9fd051c9 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 72f263d491211f65de95b39eab8ec71a7d01d489..4083b1abeaabe6057c929fd8b78ced041b57cd24 100644 (file)
@@ -289,6 +289,15 @@ static int check_attr(void *ctx)
        return 0;
 }
 
+static int check_object_code(void *ctx, const struct perf_dlfilter_sample *sample)
+{
+       __u8 buf[15];
+
+       CHECK(perf_dlfilter_fns.object_code(ctx, sample->ip, buf, sizeof(buf)) > 0);
+
+       return 0;
+}
+
 static int do_checks(void *data, const struct perf_dlfilter_sample *sample, void *ctx, bool early)
 {
        struct filter_data *d = data;
@@ -314,7 +323,8 @@ static int do_checks(void *data, const struct perf_dlfilter_sample *sample, void
        if (early && !d->do_early)
                return 0;
 
-       if (check_al(ctx) || check_addr_al(ctx) || check_address_al(ctx, sample))
+       if (check_al(ctx) || check_addr_al(ctx) || check_address_al(ctx, sample) ||
+           check_object_code(ctx, sample))
                return -1;
 
        if (early)
index 38e593d92920c7fd96d6246326049b0b527d5f29..32ff619e881caa501c05b713f9f5baaa45862de9 100644 (file)
@@ -308,6 +308,15 @@ static int check_attr(void *ctx)
        return 0;
 }
 
+static int check_object_code(void *ctx, const struct perf_dlfilter_sample *sample)
+{
+       __u8 buf[15];
+
+       CHECK(perf_dlfilter_fns.object_code(ctx, sample->ip, buf, sizeof(buf)) > 0);
+
+       return 0;
+}
+
 static int do_checks(void *data, const struct perf_dlfilter_sample *sample, void *ctx, bool early)
 {
        struct filter_data *d = data;
@@ -333,7 +342,8 @@ static int do_checks(void *data, const struct perf_dlfilter_sample *sample, void
        if (early && !d->do_early)
                return 0;
 
-       if (check_al(ctx) || check_addr_al(ctx) || check_address_al(ctx, sample))
+       if (check_al(ctx) || check_addr_al(ctx) || check_address_al(ctx, sample) ||
+           check_object_code(ctx, sample))
                return -1;
 
        if (early)
index a7e88332276d0827fde76fad3d6b260a0c36e226..72ba4a9239c6bff6da2685c311e60c19e3b85562 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 0e9ec65d92aedf343390caf8767fe88490f11c86..3e673f25d5fd85b49b2f66a76f4cdb603edbf9ce 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 90ce22f9c1a940049dd2fca3c83b6b51b43f136d..939ec769bf4a5abf5687eb5a9d7016b6226bd0ec 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 1dbf27822ee28f385d4ba93a116eb3117e26cd43..4a1dc21b0450bcc8812cd662c629de9b664ec9cf 100644 (file)
@@ -282,13 +282,21 @@ static struct perf_event_attr *dlfilter__attr(void *ctx)
        return &d->evsel->core.attr;
 }
 
+static __s32 code_read(__u64 ip, struct map *map, struct machine *machine, void *buf, __u32 len)
+{
+       u64 offset = map__map_ip(map, ip);
+
+       if (ip + len >= map__end(map))
+               len = map__end(map) - ip;
+
+       return dso__data_read_offset(map__dso(map), machine, offset, buf, len);
+}
+
 static __s32 dlfilter__object_code(void *ctx, __u64 ip, void *buf, __u32 len)
 {
        struct dlfilter *d = (struct dlfilter *)ctx;
        struct addr_location *al;
        struct addr_location a;
-       struct map *map;
-       u64 offset;
        __s32 ret;
 
        if (!d->ctx_valid)
@@ -298,27 +306,17 @@ static __s32 dlfilter__object_code(void *ctx, __u64 ip, void *buf, __u32 len)
        if (!al)
                return -1;
 
-       map = al->map;
-
-       if (map && ip >= map__start(map) && ip < map__end(map) &&
+       if (al->map && ip >= map__start(al->map) && ip < map__end(al->map) &&
            machine__kernel_ip(d->machine, ip) == machine__kernel_ip(d->machine, d->sample->ip))
-               goto have_map;
+               return code_read(ip, al->map, d->machine, buf, len);
 
        addr_location__init(&a);
+
        thread__find_map_fb(al->thread, d->sample->cpumode, ip, &a);
-       if (!a.map) {
-               ret = -1;
-               goto out;
-       }
+       ret = a.map ? code_read(ip, a.map, d->machine, buf, len) : -1;
 
-       map = a.map;
-have_map:
-       offset = map__map_ip(map, ip);
-       if (ip + len >= map__end(map))
-               len = map__end(map) - ip;
-       ret = dso__data_read_offset(map__dso(map), d->machine, offset, buf, len);
-out:
        addr_location__exit(&a);
+
        return ret;
 }
 
index 0a5bf1937a7c536fa05a5268c7ea12778dec389b..c12f8320e6682d50d0ec6a12e3e4d15802b9972c 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 d85602aa4b9f35a941c96d2e5f8e523169aa04b2..d515ba8a0e160c97d69c7c1e83b964fa7120021c 100644 (file)
@@ -295,7 +295,7 @@ static int perf_pmu__parse_scale(struct perf_pmu *pmu, struct perf_pmu_alias *al
        len = perf_pmu__event_source_devices_scnprintf(path, sizeof(path));
        if (!len)
                return 0;
-       scnprintf(path + len, sizeof(path) - len, "%s/%s.scale", pmu->name, alias->name);
+       scnprintf(path + len, sizeof(path) - len, "%s/events/%s.scale", pmu->name, alias->name);
 
        fd = open(path, O_RDONLY);
        if (fd == -1)
@@ -330,7 +330,7 @@ static int perf_pmu__parse_unit(struct perf_pmu *pmu, struct perf_pmu_alias *ali
        len = perf_pmu__event_source_devices_scnprintf(path, sizeof(path));
        if (!len)
                return 0;
-       scnprintf(path + len, sizeof(path) - len, "%s/%s.unit", pmu->name, alias->name);
+       scnprintf(path + len, sizeof(path) - len, "%s/events/%s.unit", pmu->name, alias->name);
 
        fd = open(path, O_RDONLY);
        if (fd == -1)
@@ -364,7 +364,7 @@ perf_pmu__parse_per_pkg(struct perf_pmu *pmu, struct perf_pmu_alias *alias)
        len = perf_pmu__event_source_devices_scnprintf(path, sizeof(path));
        if (!len)
                return 0;
-       scnprintf(path + len, sizeof(path) - len, "%s/%s.per-pkg", pmu->name, alias->name);
+       scnprintf(path + len, sizeof(path) - len, "%s/events/%s.per-pkg", pmu->name, alias->name);
 
        fd = open(path, O_RDONLY);
        if (fd == -1)
@@ -385,7 +385,7 @@ static int perf_pmu__parse_snapshot(struct perf_pmu *pmu, struct perf_pmu_alias
        len = perf_pmu__event_source_devices_scnprintf(path, sizeof(path));
        if (!len)
                return 0;
-       scnprintf(path + len, sizeof(path) - len, "%s/%s.snapshot", pmu->name, alias->name);
+       scnprintf(path + len, sizeof(path) - len, "%s/events/%s.snapshot", pmu->name, alias->name);
 
        fd = open(path, O_RDONLY);
        if (fd == -1)
@@ -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 fdb7f5db730822e93d7732026218609cda4a054c..f6c6e5474c3afbcb238eae15e71cadb4c986f411 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 7b0909e8b759d446aa90931f062230d9a5d9e091..d3d58851864e7c7f842e201a1032bf195d50bd7a 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 411647094cc37f832ecc69c829a57036a800c9db..57bf2688edfd68ca8dbc5724da1e78aff9897e59 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 4f23302ee6779a4b6b7e7007e2fea98b60094a4c..b5ec59aa62d72ab2ad3f51ffd5d2b4fb6722a8a3 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 42806add0114ddae25499281e4ea65e73c40360b..1a21d6beebc682f8cd96e6a038dd4b9620438bdf 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 d7aafe5a1993aaf45aa1c7b237db72a15a27f224..2f1685a3eae14221610a8c861ee4d4d118186ae5 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 c95d63e553f4d2eec044968c9c36d77313d570c8..21e482b23f5028f6e35fae82d4416a821659048e 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 2f5e3c462194f0ba8b871f018c933e4351d17f70..c0a39818c5a4bbf99191973a5cf61a0756ee4d90 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 357adc722cbae846657e6f4149447cf71db56ff2..a52ecd43dbe30f81aec81aa8b384c85023e94350 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 7f768d335698764527bb997413bcf63beef35991..3babaf3eee5c455ddbc5cf23d49b56ae02e0e3c9 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 1c7584e8dd9ea969f1f4cb15516425861d0dc9aa..e41eb33b27046c61007ba8a7cbbc44aa199efcfc 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 b650b2e617b8fe8d9526d4a27d0fe19037838032..2e70a6048278459e889574972ce29221510221a3 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 a53c254c60580798bd42d492ad20a9db00c2dc0d..4aabeaa525d474c45c3871ca62c94307d91ed5ca 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 3b77d8a422dbf6ad4d4ebf990f69c5e1ba0e482f..261228eb68e810ce096407c1d80dde41ca398c37 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 179fe300534f5c56501544e70468ec4a514a545f..4041cfa670eb4c0448baf5aefa4f35ba7f87651a 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 064cc5e8d9ade372415b852712270e84847f80ff..dda7060e86a097ced15715e33b182402068379e8 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 6c93215be8a3a5ccfb23e4e9520c556bf6642252..67f985f7d2157d43bec0f453abc518f348c6fbc1 100644 (file)
@@ -45,7 +45,7 @@ static inline __u32 ifindex_from_link_fd(int fd)
        return link_info.tcx.ifindex;
 }
 
-static inline void __assert_mprog_count(int target, int expected, bool miniq, int ifindex)
+static inline void __assert_mprog_count(int target, int expected, int ifindex)
 {
        __u32 count = 0, attach_flags = 0;
        int err;
@@ -53,20 +53,22 @@ static inline void __assert_mprog_count(int target, int expected, bool miniq, in
        err = bpf_prog_query(ifindex, target, 0, &attach_flags,
                             NULL, &count);
        ASSERT_EQ(count, expected, "count");
-       if (!expected && !miniq)
-               ASSERT_EQ(err, -ENOENT, "prog_query");
-       else
-               ASSERT_EQ(err, 0, "prog_query");
+       ASSERT_EQ(err, 0, "prog_query");
 }
 
 static inline void assert_mprog_count(int target, int expected)
 {
-       __assert_mprog_count(target, expected, false, loopback);
+       __assert_mprog_count(target, expected, loopback);
 }
 
 static inline void assert_mprog_count_ifindex(int ifindex, int target, int expected)
 {
-       __assert_mprog_count(target, expected, false, ifindex);
+       __assert_mprog_count(target, expected, ifindex);
+}
+
+static inline void tc_skel_reset_all_seen(struct test_tc_link *skel)
+{
+       memset(skel->bss, 0, sizeof(*skel->bss));
 }
 
 #endif /* TC_HELPERS */
index 74fc1fe9ee26146338c4e130b89c9bd3cf006412..bc984114468556d8c2113522b4da5d79b288050c 100644 (file)
@@ -65,6 +65,7 @@ void serial_test_tc_links_basic(void)
        ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
        ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]");
 
+       tc_skel_reset_all_seen(skel);
        ASSERT_OK(system(ping_cmd), ping_cmd);
 
        ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
@@ -97,6 +98,7 @@ void serial_test_tc_links_basic(void)
        ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
        ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]");
 
+       tc_skel_reset_all_seen(skel);
        ASSERT_OK(system(ping_cmd), ping_cmd);
 
        ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
@@ -187,6 +189,7 @@ static void test_tc_links_before_target(int target)
        ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
        ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]");
 
+       tc_skel_reset_all_seen(skel);
        ASSERT_OK(system(ping_cmd), ping_cmd);
 
        ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
@@ -194,9 +197,6 @@ static void test_tc_links_before_target(int target)
        ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
        ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
 
-       skel->bss->seen_tc1 = false;
-       skel->bss->seen_tc2 = false;
-
        LIBBPF_OPTS_RESET(optl,
                .flags = BPF_F_BEFORE,
                .relative_fd = bpf_program__fd(skel->progs.tc2),
@@ -246,6 +246,7 @@ static void test_tc_links_before_target(int target)
        ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
        ASSERT_EQ(optq.link_ids[4], 0, "link_ids[4]");
 
+       tc_skel_reset_all_seen(skel);
        ASSERT_OK(system(ping_cmd), ping_cmd);
 
        ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
@@ -342,6 +343,7 @@ static void test_tc_links_after_target(int target)
        ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
        ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]");
 
+       tc_skel_reset_all_seen(skel);
        ASSERT_OK(system(ping_cmd), ping_cmd);
 
        ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
@@ -349,9 +351,6 @@ static void test_tc_links_after_target(int target)
        ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
        ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
 
-       skel->bss->seen_tc1 = false;
-       skel->bss->seen_tc2 = false;
-
        LIBBPF_OPTS_RESET(optl,
                .flags = BPF_F_AFTER,
                .relative_fd = bpf_program__fd(skel->progs.tc1),
@@ -401,6 +400,7 @@ static void test_tc_links_after_target(int target)
        ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
        ASSERT_EQ(optq.link_ids[4], 0, "link_ids[4]");
 
+       tc_skel_reset_all_seen(skel);
        ASSERT_OK(system(ping_cmd), ping_cmd);
 
        ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
@@ -502,6 +502,7 @@ static void test_tc_links_revision_target(int target)
        ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
        ASSERT_EQ(optq.link_ids[2], 0, "prog_ids[2]");
 
+       tc_skel_reset_all_seen(skel);
        ASSERT_OK(system(ping_cmd), ping_cmd);
 
        ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
@@ -581,22 +582,20 @@ static void test_tc_chain_classic(int target, bool chain_tc_old)
 
        assert_mprog_count(target, 2);
 
+       tc_skel_reset_all_seen(skel);
        ASSERT_OK(system(ping_cmd), ping_cmd);
 
        ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
        ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
        ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3");
 
-       skel->bss->seen_tc1 = false;
-       skel->bss->seen_tc2 = false;
-       skel->bss->seen_tc3 = false;
-
        err = bpf_link__detach(skel->links.tc2);
        if (!ASSERT_OK(err, "prog_detach"))
                goto cleanup;
 
        assert_mprog_count(target, 1);
 
+       tc_skel_reset_all_seen(skel);
        ASSERT_OK(system(ping_cmd), ping_cmd);
 
        ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
@@ -707,16 +706,13 @@ static void test_tc_links_replace_target(int target)
        ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
        ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]");
 
+       tc_skel_reset_all_seen(skel);
        ASSERT_OK(system(ping_cmd), ping_cmd);
 
        ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
        ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
        ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
 
-       skel->bss->seen_tc1 = false;
-       skel->bss->seen_tc2 = false;
-       skel->bss->seen_tc3 = false;
-
        LIBBPF_OPTS_RESET(optl,
                .flags = BPF_F_REPLACE,
                .relative_fd = bpf_program__fd(skel->progs.tc2),
@@ -781,16 +777,13 @@ static void test_tc_links_replace_target(int target)
        ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
        ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]");
 
+       tc_skel_reset_all_seen(skel);
        ASSERT_OK(system(ping_cmd), ping_cmd);
 
        ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
        ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
        ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");
 
-       skel->bss->seen_tc1 = false;
-       skel->bss->seen_tc2 = false;
-       skel->bss->seen_tc3 = false;
-
        err = bpf_link__detach(skel->links.tc2);
        if (!ASSERT_OK(err, "link_detach"))
                goto cleanup;
@@ -812,16 +805,13 @@ static void test_tc_links_replace_target(int target)
        ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
        ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]");
 
+       tc_skel_reset_all_seen(skel);
        ASSERT_OK(system(ping_cmd), ping_cmd);
 
        ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
        ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
        ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
 
-       skel->bss->seen_tc1 = false;
-       skel->bss->seen_tc2 = false;
-       skel->bss->seen_tc3 = false;
-
        err = bpf_link__update_program(skel->links.tc1, skel->progs.tc1);
        if (!ASSERT_OK(err, "link_update_self"))
                goto cleanup;
@@ -843,6 +833,7 @@ static void test_tc_links_replace_target(int target)
        ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
        ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]");
 
+       tc_skel_reset_all_seen(skel);
        ASSERT_OK(system(ping_cmd), ping_cmd);
 
        ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
@@ -1254,6 +1245,7 @@ static void test_tc_links_prepend_target(int target)
        ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
        ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]");
 
+       tc_skel_reset_all_seen(skel);
        ASSERT_OK(system(ping_cmd), ping_cmd);
 
        ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
@@ -1261,9 +1253,6 @@ static void test_tc_links_prepend_target(int target)
        ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
        ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
 
-       skel->bss->seen_tc1 = false;
-       skel->bss->seen_tc2 = false;
-
        LIBBPF_OPTS_RESET(optl,
                .flags = BPF_F_BEFORE,
        );
@@ -1311,6 +1300,7 @@ static void test_tc_links_prepend_target(int target)
        ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
        ASSERT_EQ(optq.link_ids[4], 0, "link_ids[4]");
 
+       tc_skel_reset_all_seen(skel);
        ASSERT_OK(system(ping_cmd), ping_cmd);
 
        ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
@@ -1411,6 +1401,7 @@ static void test_tc_links_append_target(int target)
        ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
        ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]");
 
+       tc_skel_reset_all_seen(skel);
        ASSERT_OK(system(ping_cmd), ping_cmd);
 
        ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
@@ -1418,9 +1409,6 @@ static void test_tc_links_append_target(int target)
        ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
        ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
 
-       skel->bss->seen_tc1 = false;
-       skel->bss->seen_tc2 = false;
-
        LIBBPF_OPTS_RESET(optl,
                .flags = BPF_F_AFTER,
        );
@@ -1468,6 +1456,7 @@ static void test_tc_links_append_target(int target)
        ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
        ASSERT_EQ(optq.link_ids[4], 0, "link_ids[4]");
 
+       tc_skel_reset_all_seen(skel);
        ASSERT_OK(system(ping_cmd), ping_cmd);
 
        ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
@@ -1637,38 +1626,33 @@ static void test_tc_chain_mixed(int target)
 
        assert_mprog_count(target, 1);
 
+       tc_skel_reset_all_seen(skel);
        ASSERT_OK(system(ping_cmd), ping_cmd);
 
        ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
        ASSERT_EQ(skel->bss->seen_tc5, false, "seen_tc5");
        ASSERT_EQ(skel->bss->seen_tc6, true, "seen_tc6");
 
-       skel->bss->seen_tc4 = false;
-       skel->bss->seen_tc5 = false;
-       skel->bss->seen_tc6 = false;
-
        err = bpf_link__update_program(skel->links.tc6, skel->progs.tc4);
        if (!ASSERT_OK(err, "link_update"))
                goto cleanup;
 
        assert_mprog_count(target, 1);
 
+       tc_skel_reset_all_seen(skel);
        ASSERT_OK(system(ping_cmd), ping_cmd);
 
        ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");
        ASSERT_EQ(skel->bss->seen_tc5, true, "seen_tc5");
        ASSERT_EQ(skel->bss->seen_tc6, false, "seen_tc6");
 
-       skel->bss->seen_tc4 = false;
-       skel->bss->seen_tc5 = false;
-       skel->bss->seen_tc6 = false;
-
        err = bpf_link__detach(skel->links.tc6);
        if (!ASSERT_OK(err, "prog_detach"))
                goto cleanup;
 
-       __assert_mprog_count(target, 0, true, loopback);
+       assert_mprog_count(target, 0);
 
+       tc_skel_reset_all_seen(skel);
        ASSERT_OK(system(ping_cmd), ping_cmd);
 
        ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
@@ -1758,22 +1742,20 @@ static void test_tc_links_ingress(int target, bool chain_tc_old,
 
        assert_mprog_count(target, 2);
 
+       tc_skel_reset_all_seen(skel);
        ASSERT_OK(system(ping_cmd), ping_cmd);
 
        ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
        ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
        ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3");
 
-       skel->bss->seen_tc1 = false;
-       skel->bss->seen_tc2 = false;
-       skel->bss->seen_tc3 = false;
-
        err = bpf_link__detach(skel->links.tc2);
        if (!ASSERT_OK(err, "prog_detach"))
                goto cleanup;
 
        assert_mprog_count(target, 1);
 
+       tc_skel_reset_all_seen(skel);
        ASSERT_OK(system(ping_cmd), ping_cmd);
 
        ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
index 7a2ecd4eca5dd397d317d488ab09038e898a87ba..ca506d2fcf58869288df87ac4c8e6541032247fe 100644 (file)
@@ -59,6 +59,7 @@ void serial_test_tc_opts_basic(void)
        ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
        ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
 
+       tc_skel_reset_all_seen(skel);
        ASSERT_OK(system(ping_cmd), ping_cmd);
 
        ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
@@ -83,6 +84,7 @@ void serial_test_tc_opts_basic(void)
        ASSERT_EQ(optq.prog_ids[0], id2, "prog_ids[0]");
        ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
 
+       tc_skel_reset_all_seen(skel);
        ASSERT_OK(system(ping_cmd), ping_cmd);
 
        ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
@@ -163,6 +165,7 @@ static void test_tc_opts_before_target(int target)
        ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");
        ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
 
+       tc_skel_reset_all_seen(skel);
        ASSERT_OK(system(ping_cmd), ping_cmd);
 
        ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
@@ -219,6 +222,7 @@ static void test_tc_opts_before_target(int target)
        ASSERT_EQ(optq.prog_ids[3], id2, "prog_ids[3]");
        ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
 
+       tc_skel_reset_all_seen(skel);
        ASSERT_OK(system(ping_cmd), ping_cmd);
 
        ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
@@ -313,6 +317,7 @@ static void test_tc_opts_after_target(int target)
        ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");
        ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
 
+       tc_skel_reset_all_seen(skel);
        ASSERT_OK(system(ping_cmd), ping_cmd);
 
        ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
@@ -369,6 +374,7 @@ static void test_tc_opts_after_target(int target)
        ASSERT_EQ(optq.prog_ids[3], id4, "prog_ids[3]");
        ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
 
+       tc_skel_reset_all_seen(skel);
        ASSERT_OK(system(ping_cmd), ping_cmd);
 
        ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
@@ -514,6 +520,7 @@ static void test_tc_opts_revision_target(int target)
        ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");
        ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
 
+       tc_skel_reset_all_seen(skel);
        ASSERT_OK(system(ping_cmd), ping_cmd);
 
        ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
@@ -608,22 +615,20 @@ static void test_tc_chain_classic(int target, bool chain_tc_old)
 
        assert_mprog_count(target, 2);
 
+       tc_skel_reset_all_seen(skel);
        ASSERT_OK(system(ping_cmd), ping_cmd);
 
        ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
        ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
        ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3");
 
-       skel->bss->seen_tc1 = false;
-       skel->bss->seen_tc2 = false;
-       skel->bss->seen_tc3 = false;
-
        err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
        if (!ASSERT_OK(err, "prog_detach"))
                goto cleanup_detach;
 
        assert_mprog_count(target, 1);
 
+       tc_skel_reset_all_seen(skel);
        ASSERT_OK(system(ping_cmd), ping_cmd);
 
        ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
@@ -635,7 +640,7 @@ cleanup_detach:
        if (!ASSERT_OK(err, "prog_detach"))
                goto cleanup;
 
-       __assert_mprog_count(target, 0, chain_tc_old, loopback);
+       assert_mprog_count(target, 0);
 cleanup:
        if (tc_attached) {
                tc_opts.flags = tc_opts.prog_fd = tc_opts.prog_id = 0;
@@ -730,16 +735,13 @@ static void test_tc_opts_replace_target(int target)
        ASSERT_EQ(optq.prog_attach_flags[1], 0, "prog_flags[1]");
        ASSERT_EQ(optq.prog_attach_flags[2], 0, "prog_flags[2]");
 
+       tc_skel_reset_all_seen(skel);
        ASSERT_OK(system(ping_cmd), ping_cmd);
 
        ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
        ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
        ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
 
-       skel->bss->seen_tc1 = false;
-       skel->bss->seen_tc2 = false;
-       skel->bss->seen_tc3 = false;
-
        LIBBPF_OPTS_RESET(opta,
                .flags = BPF_F_REPLACE,
                .replace_prog_fd = fd2,
@@ -767,16 +769,13 @@ static void test_tc_opts_replace_target(int target)
        ASSERT_EQ(optq.prog_ids[1], id1, "prog_ids[1]");
        ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
 
+       tc_skel_reset_all_seen(skel);
        ASSERT_OK(system(ping_cmd), ping_cmd);
 
        ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
        ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
        ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");
 
-       skel->bss->seen_tc1 = false;
-       skel->bss->seen_tc2 = false;
-       skel->bss->seen_tc3 = false;
-
        LIBBPF_OPTS_RESET(opta,
                .flags = BPF_F_REPLACE | BPF_F_BEFORE,
                .replace_prog_fd = fd3,
@@ -805,6 +804,7 @@ static void test_tc_opts_replace_target(int target)
        ASSERT_EQ(optq.prog_ids[1], id1, "prog_ids[1]");
        ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
 
+       tc_skel_reset_all_seen(skel);
        ASSERT_OK(system(ping_cmd), ping_cmd);
 
        ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
@@ -1084,6 +1084,7 @@ static void test_tc_opts_prepend_target(int target)
        ASSERT_EQ(optq.prog_ids[1], id1, "prog_ids[1]");
        ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
 
+       tc_skel_reset_all_seen(skel);
        ASSERT_OK(system(ping_cmd), ping_cmd);
 
        ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
@@ -1124,6 +1125,7 @@ static void test_tc_opts_prepend_target(int target)
        ASSERT_EQ(optq.prog_ids[3], id1, "prog_ids[3]");
        ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
 
+       tc_skel_reset_all_seen(skel);
        ASSERT_OK(system(ping_cmd), ping_cmd);
 
        ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
@@ -1222,6 +1224,7 @@ static void test_tc_opts_append_target(int target)
        ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");
        ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
 
+       tc_skel_reset_all_seen(skel);
        ASSERT_OK(system(ping_cmd), ping_cmd);
 
        ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
@@ -1262,6 +1265,7 @@ static void test_tc_opts_append_target(int target)
        ASSERT_EQ(optq.prog_ids[3], id4, "prog_ids[3]");
        ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
 
+       tc_skel_reset_all_seen(skel);
        ASSERT_OK(system(ping_cmd), ping_cmd);
 
        ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
@@ -2250,7 +2254,7 @@ static void test_tc_opts_delete_empty(int target, bool chain_tc_old)
                                       BPF_TC_INGRESS : BPF_TC_EGRESS;
                err = bpf_tc_hook_create(&tc_hook);
                ASSERT_OK(err, "bpf_tc_hook_create");
-               __assert_mprog_count(target, 0, true, loopback);
+               assert_mprog_count(target, 0);
        }
        err = bpf_prog_detach_opts(0, loopback, target, &optd);
        ASSERT_EQ(err, -ENOENT, "prog_detach");
@@ -2316,16 +2320,13 @@ static void test_tc_chain_mixed(int target)
 
        assert_mprog_count(target, 1);
 
+       tc_skel_reset_all_seen(skel);
        ASSERT_OK(system(ping_cmd), ping_cmd);
 
        ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
        ASSERT_EQ(skel->bss->seen_tc5, false, "seen_tc5");
        ASSERT_EQ(skel->bss->seen_tc6, true, "seen_tc6");
 
-       skel->bss->seen_tc4 = false;
-       skel->bss->seen_tc5 = false;
-       skel->bss->seen_tc6 = false;
-
        LIBBPF_OPTS_RESET(opta,
                .flags = BPF_F_REPLACE,
                .replace_prog_fd = fd3,
@@ -2339,21 +2340,19 @@ static void test_tc_chain_mixed(int target)
 
        assert_mprog_count(target, 1);
 
+       tc_skel_reset_all_seen(skel);
        ASSERT_OK(system(ping_cmd), ping_cmd);
 
        ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");
        ASSERT_EQ(skel->bss->seen_tc5, true, "seen_tc5");
        ASSERT_EQ(skel->bss->seen_tc6, false, "seen_tc6");
 
-       skel->bss->seen_tc4 = false;
-       skel->bss->seen_tc5 = false;
-       skel->bss->seen_tc6 = false;
-
 cleanup_opts:
        err = bpf_prog_detach_opts(detach_fd, loopback, target, &optd);
        ASSERT_OK(err, "prog_detach");
-       __assert_mprog_count(target, 0, true, loopback);
+       assert_mprog_count(target, 0);
 
+       tc_skel_reset_all_seen(skel);
        ASSERT_OK(system(ping_cmd), ping_cmd);
 
        ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
@@ -2378,3 +2377,313 @@ 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);
+}
+
+static void test_tc_opts_query_target(int target)
+{
+       const size_t attr_size = offsetofend(union bpf_attr, query);
+       LIBBPF_OPTS(bpf_prog_attach_opts, opta);
+       LIBBPF_OPTS(bpf_prog_detach_opts, optd);
+       LIBBPF_OPTS(bpf_prog_query_opts, optq);
+       __u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;
+       struct test_tc_link *skel;
+       union bpf_attr attr;
+       __u32 prog_ids[5];
+       int err;
+
+       skel = test_tc_link__open_and_load();
+       if (!ASSERT_OK_PTR(skel, "skel_load"))
+               goto cleanup;
+
+       fd1 = bpf_program__fd(skel->progs.tc1);
+       fd2 = bpf_program__fd(skel->progs.tc2);
+       fd3 = bpf_program__fd(skel->progs.tc3);
+       fd4 = bpf_program__fd(skel->progs.tc4);
+
+       id1 = id_from_prog_fd(fd1);
+       id2 = id_from_prog_fd(fd2);
+       id3 = id_from_prog_fd(fd3);
+       id4 = id_from_prog_fd(fd4);
+
+       assert_mprog_count(target, 0);
+
+       LIBBPF_OPTS_RESET(opta,
+               .expected_revision = 1,
+       );
+
+       err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
+       if (!ASSERT_EQ(err, 0, "prog_attach"))
+               goto cleanup;
+
+       assert_mprog_count(target, 1);
+
+       LIBBPF_OPTS_RESET(opta,
+               .expected_revision = 2,
+       );
+
+       err = bpf_prog_attach_opts(fd2, loopback, target, &opta);
+       if (!ASSERT_EQ(err, 0, "prog_attach"))
+               goto cleanup1;
+
+       assert_mprog_count(target, 2);
+
+       LIBBPF_OPTS_RESET(opta,
+               .expected_revision = 3,
+       );
+
+       err = bpf_prog_attach_opts(fd3, loopback, target, &opta);
+       if (!ASSERT_EQ(err, 0, "prog_attach"))
+               goto cleanup2;
+
+       assert_mprog_count(target, 3);
+
+       LIBBPF_OPTS_RESET(opta,
+               .expected_revision = 4,
+       );
+
+       err = bpf_prog_attach_opts(fd4, loopback, target, &opta);
+       if (!ASSERT_EQ(err, 0, "prog_attach"))
+               goto cleanup3;
+
+       assert_mprog_count(target, 4);
+
+       /* Test 1: Double query via libbpf API */
+       err = bpf_prog_query_opts(loopback, target, &optq);
+       if (!ASSERT_OK(err, "prog_query"))
+               goto cleanup4;
+
+       ASSERT_EQ(optq.count, 4, "count");
+       ASSERT_EQ(optq.revision, 5, "revision");
+       ASSERT_EQ(optq.prog_ids, NULL, "prog_ids");
+       ASSERT_EQ(optq.link_ids, NULL, "link_ids");
+
+       memset(prog_ids, 0, sizeof(prog_ids));
+       optq.prog_ids = prog_ids;
+
+       err = bpf_prog_query_opts(loopback, target, &optq);
+       if (!ASSERT_OK(err, "prog_query"))
+               goto cleanup4;
+
+       ASSERT_EQ(optq.count, 4, "count");
+       ASSERT_EQ(optq.revision, 5, "revision");
+       ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
+       ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");
+       ASSERT_EQ(optq.prog_ids[2], id3, "prog_ids[2]");
+       ASSERT_EQ(optq.prog_ids[3], id4, "prog_ids[3]");
+       ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
+       ASSERT_EQ(optq.link_ids, NULL, "link_ids");
+
+       /* Test 2: Double query via bpf_attr & bpf(2) directly */
+       memset(&attr, 0, attr_size);
+       attr.query.target_ifindex = loopback;
+       attr.query.attach_type = target;
+
+       err = syscall(__NR_bpf, BPF_PROG_QUERY, &attr, attr_size);
+       if (!ASSERT_OK(err, "prog_query"))
+               goto cleanup4;
+
+       ASSERT_EQ(attr.query.count, 4, "count");
+       ASSERT_EQ(attr.query.revision, 5, "revision");
+       ASSERT_EQ(attr.query.query_flags, 0, "query_flags");
+       ASSERT_EQ(attr.query.attach_flags, 0, "attach_flags");
+       ASSERT_EQ(attr.query.target_ifindex, loopback, "target_ifindex");
+       ASSERT_EQ(attr.query.attach_type, target, "attach_type");
+       ASSERT_EQ(attr.query.prog_ids, 0, "prog_ids");
+       ASSERT_EQ(attr.query.prog_attach_flags, 0, "prog_attach_flags");
+       ASSERT_EQ(attr.query.link_ids, 0, "link_ids");
+       ASSERT_EQ(attr.query.link_attach_flags, 0, "link_attach_flags");
+
+       memset(prog_ids, 0, sizeof(prog_ids));
+       attr.query.prog_ids = ptr_to_u64(prog_ids);
+
+       err = syscall(__NR_bpf, BPF_PROG_QUERY, &attr, attr_size);
+       if (!ASSERT_OK(err, "prog_query"))
+               goto cleanup4;
+
+       ASSERT_EQ(attr.query.count, 4, "count");
+       ASSERT_EQ(attr.query.revision, 5, "revision");
+       ASSERT_EQ(attr.query.query_flags, 0, "query_flags");
+       ASSERT_EQ(attr.query.attach_flags, 0, "attach_flags");
+       ASSERT_EQ(attr.query.target_ifindex, loopback, "target_ifindex");
+       ASSERT_EQ(attr.query.attach_type, target, "attach_type");
+       ASSERT_EQ(attr.query.prog_ids, ptr_to_u64(prog_ids), "prog_ids");
+       ASSERT_EQ(prog_ids[0], id1, "prog_ids[0]");
+       ASSERT_EQ(prog_ids[1], id2, "prog_ids[1]");
+       ASSERT_EQ(prog_ids[2], id3, "prog_ids[2]");
+       ASSERT_EQ(prog_ids[3], id4, "prog_ids[3]");
+       ASSERT_EQ(prog_ids[4], 0, "prog_ids[4]");
+       ASSERT_EQ(attr.query.prog_attach_flags, 0, "prog_attach_flags");
+       ASSERT_EQ(attr.query.link_ids, 0, "link_ids");
+       ASSERT_EQ(attr.query.link_attach_flags, 0, "link_attach_flags");
+
+cleanup4:
+       err = bpf_prog_detach_opts(fd4, loopback, target, &optd);
+       ASSERT_OK(err, "prog_detach");
+       assert_mprog_count(target, 3);
+
+cleanup3:
+       err = bpf_prog_detach_opts(fd3, loopback, target, &optd);
+       ASSERT_OK(err, "prog_detach");
+       assert_mprog_count(target, 2);
+
+cleanup2:
+       err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
+       ASSERT_OK(err, "prog_detach");
+       assert_mprog_count(target, 1);
+
+cleanup1:
+       err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
+       ASSERT_OK(err, "prog_detach");
+       assert_mprog_count(target, 0);
+
+cleanup:
+       test_tc_link__destroy(skel);
+}
+
+void serial_test_tc_opts_query(void)
+{
+       test_tc_opts_query_target(BPF_TCX_INGRESS);
+       test_tc_opts_query_target(BPF_TCX_EGRESS);
+}
+
+static void test_tc_opts_query_attach_target(int target)
+{
+       LIBBPF_OPTS(bpf_prog_attach_opts, opta);
+       LIBBPF_OPTS(bpf_prog_detach_opts, optd);
+       LIBBPF_OPTS(bpf_prog_query_opts, optq);
+       struct test_tc_link *skel;
+       __u32 prog_ids[2];
+       __u32 fd1, id1;
+       int err;
+
+       skel = test_tc_link__open_and_load();
+       if (!ASSERT_OK_PTR(skel, "skel_load"))
+               goto cleanup;
+
+       fd1 = bpf_program__fd(skel->progs.tc1);
+       id1 = id_from_prog_fd(fd1);
+
+       err = bpf_prog_query_opts(loopback, target, &optq);
+       if (!ASSERT_OK(err, "prog_query"))
+               goto cleanup;
+
+       ASSERT_EQ(optq.count, 0, "count");
+       ASSERT_EQ(optq.revision, 1, "revision");
+
+       LIBBPF_OPTS_RESET(opta,
+               .expected_revision = optq.revision,
+       );
+
+       err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
+       if (!ASSERT_EQ(err, 0, "prog_attach"))
+               goto cleanup;
+
+       memset(prog_ids, 0, sizeof(prog_ids));
+       optq.prog_ids = prog_ids;
+       optq.count = ARRAY_SIZE(prog_ids);
+
+       err = bpf_prog_query_opts(loopback, target, &optq);
+       if (!ASSERT_OK(err, "prog_query"))
+               goto cleanup1;
+
+       ASSERT_EQ(optq.count, 1, "count");
+       ASSERT_EQ(optq.revision, 2, "revision");
+       ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
+       ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
+
+cleanup1:
+       err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
+       ASSERT_OK(err, "prog_detach");
+       assert_mprog_count(target, 0);
+cleanup:
+       test_tc_link__destroy(skel);
+}
+
+void serial_test_tc_opts_query_attach(void)
+{
+       test_tc_opts_query_attach_target(BPF_TCX_INGRESS);
+       test_tc_opts_query_attach_target(BPF_TCX_EGRESS);
+}
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);
+}
index 290c21dbe65ab5546efdc17a50782515f0a20a43..ce2c61d62fc6c1cc00ae08b0545ffa6a4701a1bb 100644 (file)
@@ -2,6 +2,7 @@
 /* Copyright (c) 2021 Facebook */
 #include <test_progs.h>
 #include "timer.skel.h"
+#include "timer_failure.skel.h"
 
 static int timer(struct timer *timer_skel)
 {
@@ -49,10 +50,11 @@ void serial_test_timer(void)
 
        timer_skel = timer__open_and_load();
        if (!ASSERT_OK_PTR(timer_skel, "timer_skel_load"))
-               goto cleanup;
+               return;
 
        err = timer(timer_skel);
        ASSERT_OK(err, "timer");
-cleanup:
        timer__destroy(timer_skel);
+
+       RUN_TESTS(timer_failure);
 }
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 d9660e7200e2d145a33d14ac58ad3c56e168b6d3..c997e3e3d3fb4a0a863cd1a4cec46148d20c060d 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;
+}
diff --git a/tools/testing/selftests/bpf/progs/timer_failure.c b/tools/testing/selftests/bpf/progs/timer_failure.c
new file mode 100644 (file)
index 0000000..226d33b
--- /dev/null
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */
+
+#include <linux/bpf.h>
+#include <time.h>
+#include <errno.h>
+#include <bpf/bpf_helpers.h>
+#include "bpf_misc.h"
+#include "bpf_tcp_helpers.h"
+
+char _license[] SEC("license") = "GPL";
+
+struct elem {
+       struct bpf_timer t;
+};
+
+struct {
+       __uint(type, BPF_MAP_TYPE_ARRAY);
+       __uint(max_entries, 1);
+       __type(key, int);
+       __type(value, struct elem);
+} timer_map SEC(".maps");
+
+static int timer_cb_ret1(void *map, int *key, struct bpf_timer *timer)
+{
+       if (bpf_get_smp_processor_id() % 2)
+               return 1;
+       else
+               return 0;
+}
+
+SEC("fentry/bpf_fentry_test1")
+__failure __msg("should have been in (0x0; 0x0)")
+int BPF_PROG2(test_ret_1, int, a)
+{
+       int key = 0;
+       struct bpf_timer *timer;
+
+       timer = bpf_map_lookup_elem(&timer_map, &key);
+       if (timer) {
+               bpf_timer_init(timer, &timer_map, CLOCK_BOOTTIME);
+               bpf_timer_set_callback(timer, timer_cb_ret1);
+               bpf_timer_start(timer, 1000, 0);
+       }
+
+       return 0;
+}
index 31f1c935cd07d2b8f19398912e59433fd558420d..98107e0452d338aee8e2f722e939dab95b6e0e52 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 20839f8e43f2a8a51d1f9472436ddc362e87bf3a..71ec34bf1501e275cbf229861dc6daad59fd905f 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
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_non_uniq_symbol.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_non_uniq_symbol.tc
new file mode 100644 (file)
index 0000000..bc95144
--- /dev/null
@@ -0,0 +1,13 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: Test failure of registering kprobe on non unique symbol
+# requires: kprobe_events
+
+SYMBOL='name_show'
+
+# We skip this test on kernel where SYMBOL is unique or does not exist.
+if [ "$(grep -c -E "[[:alnum:]]+ t ${SYMBOL}" /proc/kallsyms)" -le '1' ]; then
+       exit_unsupported
+fi
+
+! echo "p:test_non_unique ${SYMBOL}" > kprobe_events
index a3bb36fb3cfc55a423d31c10e86c1fe16b79ca0e..fb01c3f8d3da2a26c515ab8a1c3d0a86b54d0032 100644 (file)
@@ -66,6 +66,7 @@ TEST_GEN_PROGS_x86_64 += x86_64/dirty_log_page_splitting_test
 TEST_GEN_PROGS_x86_64 += x86_64/get_msr_index_features
 TEST_GEN_PROGS_x86_64 += x86_64/exit_on_emulation_failure_test
 TEST_GEN_PROGS_x86_64 += x86_64/fix_hypercall_test
+TEST_GEN_PROGS_x86_64 += x86_64/hwcr_msr_test
 TEST_GEN_PROGS_x86_64 += x86_64/hyperv_clock
 TEST_GEN_PROGS_x86_64 += x86_64/hyperv_cpuid
 TEST_GEN_PROGS_x86_64 += x86_64/hyperv_evmcs
index 112bc1da732a44e7343e0563f49a04dadc333ccb..ce33d306c2cba7d740697d9625d239be95891ee3 100644 (file)
@@ -1,7 +1,5 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * tools/testing/selftests/kvm/include/kvm_util.h
- *
  * Copyright (C) 2018, Google LLC.
  */
 #ifndef SELFTEST_KVM_UCALL_COMMON_H
index 4fd04211252672a7e24ccdb117ddf6ddbedf9a9a..25bc61dac5fbe69bcc62195dde70ef53f56868b0 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 c4a69d8aeb68ccb1f05f3191c1d8a42b4cbad20f..74627514c4d44dd26eef814f4de9bb5074931bcf 100644 (file)
@@ -200,6 +200,13 @@ repeat:
                        ++fmt;
                }
 
+               /*
+                * Play nice with %llu, %llx, etc.  KVM selftests only support
+                * 64-bit builds, so just treat %ll* the same as %l*.
+                */
+               if (qualifier == 'l' && *fmt == 'l')
+                       ++fmt;
+
                /* default base */
                base = 10;
 
index 7168e25c194e1d201f2dcc1009244cce52d3636a..89153a333e83c2bfbde806d1b15b51c62fc2aa3d 100644 (file)
@@ -1,7 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * tools/testing/selftests/kvm/lib/x86_64/processor.c
- *
  * Copyright (C) 2021, Google LLC.
  */
 
index 20eb2e730800e3a7075bc2af258ba0fafc8c9e5e..8698d1ab60d00f72399571b62b49314f3a8c401f 100644 (file)
@@ -1033,9 +1033,8 @@ static bool test_loop(const struct test_data *data,
                      struct test_result *rbestruntime)
 {
        uint64_t maxslots;
-       struct test_result result;
+       struct test_result result = {};
 
-       result.nloops = 0;
        if (!test_execute(targs->nslots, &maxslots, targs->seconds, data,
                          &result.nloops,
                          &result.slot_runtime, &result.guest_runtime)) {
@@ -1089,7 +1088,7 @@ int main(int argc, char *argv[])
                .seconds = 5,
                .runs = 1,
        };
-       struct test_result rbestslottime;
+       struct test_result rbestslottime = {};
        int tctr;
 
        if (!check_memory_sizes())
@@ -1098,11 +1097,10 @@ int main(int argc, char *argv[])
        if (!parse_args(argc, argv, &targs))
                return -1;
 
-       rbestslottime.slottimens = 0;
        for (tctr = targs.tfirst; tctr <= targs.tlast; tctr++) {
                const struct test_data *data = &tests[tctr];
                unsigned int runctr;
-               struct test_result rbestruntime;
+               struct test_result rbestruntime = {};
 
                if (tctr > targs.tfirst)
                        pr_info("\n");
@@ -1110,7 +1108,6 @@ int main(int argc, char *argv[])
                pr_info("Testing %s performance with %i runs, %d seconds each\n",
                        data->name, targs.runs, targs.seconds);
 
-               rbestruntime.runtimens = 0;
                for (runctr = 0; runctr < targs.runs; runctr++)
                        if (!test_loop(data, &targs,
                                       &rbestslottime, &rbestruntime))
index 9f99ea42f45ff9ff3ecf0089f666d264e7bc8b04..6bedaea95395151fa6436d4c5e582022e6d2bb88 100644 (file)
@@ -25,6 +25,8 @@ bool filter_reg(__u64 reg)
         * the visibility of the ISA_EXT register itself.
         *
         * Based on above, we should filter-out all ISA_EXT registers.
+        *
+        * Note: The below list is alphabetically sorted.
         */
        case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_A:
        case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_C:
@@ -33,21 +35,23 @@ bool filter_reg(__u64 reg)
        case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_H:
        case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_I:
        case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_M:
-       case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_SVPBMT:
+       case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_V:
+       case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_SMSTATEEN:
+       case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_SSAIA:
        case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_SSTC:
        case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_SVINVAL:
-       case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZIHINTPAUSE:
-       case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZICBOM:
-       case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZICBOZ:
-       case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZBB:
-       case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_SSAIA:
-       case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_V:
        case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_SVNAPOT:
+       case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_SVPBMT:
        case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZBA:
+       case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZBB:
        case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZBS:
+       case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZICBOM:
+       case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZICBOZ:
        case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZICNTR:
+       case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZICOND:
        case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZICSR:
        case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZIFENCEI:
+       case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZIHINTPAUSE:
        case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZIHPM:
                return true;
        /* AIA registers are always available when Ssaia can't be disabled */
@@ -112,11 +116,13 @@ void finalize_vcpu(struct kvm_vcpu *vcpu, struct vcpu_reg_list *c)
        }
 }
 
-static const char *config_id_to_str(__u64 id)
+static const char *config_id_to_str(const char *prefix, __u64 id)
 {
        /* reg_off is the offset into struct kvm_riscv_config */
        __u64 reg_off = id & ~(REG_MASK | KVM_REG_RISCV_CONFIG);
 
+       assert((id & KVM_REG_RISCV_TYPE_MASK) == KVM_REG_RISCV_CONFIG);
+
        switch (reg_off) {
        case KVM_REG_RISCV_CONFIG_REG(isa):
                return "KVM_REG_RISCV_CONFIG_REG(isa)";
@@ -134,11 +140,7 @@ static const char *config_id_to_str(__u64 id)
                return "KVM_REG_RISCV_CONFIG_REG(satp_mode)";
        }
 
-       /*
-        * Config regs would grow regularly with new pseudo reg added, so
-        * just show raw id to indicate a new pseudo config reg.
-        */
-       return strdup_printf("KVM_REG_RISCV_CONFIG_REG(%lld) /* UNKNOWN */", reg_off);
+       return strdup_printf("%lld /* UNKNOWN */", reg_off);
 }
 
 static const char *core_id_to_str(const char *prefix, __u64 id)
@@ -146,6 +148,8 @@ static const char *core_id_to_str(const char *prefix, __u64 id)
        /* reg_off is the offset into struct kvm_riscv_core */
        __u64 reg_off = id & ~(REG_MASK | KVM_REG_RISCV_CORE);
 
+       assert((id & KVM_REG_RISCV_TYPE_MASK) == KVM_REG_RISCV_CORE);
+
        switch (reg_off) {
        case KVM_REG_RISCV_CORE_REG(regs.pc):
                return "KVM_REG_RISCV_CORE_REG(regs.pc)";
@@ -176,14 +180,15 @@ static const char *core_id_to_str(const char *prefix, __u64 id)
                return "KVM_REG_RISCV_CORE_REG(mode)";
        }
 
-       TEST_FAIL("%s: Unknown core reg id: 0x%llx", prefix, id);
-       return NULL;
+       return strdup_printf("%lld /* UNKNOWN */", reg_off);
 }
 
 #define RISCV_CSR_GENERAL(csr) \
        "KVM_REG_RISCV_CSR_GENERAL | KVM_REG_RISCV_CSR_REG(" #csr ")"
 #define RISCV_CSR_AIA(csr) \
        "KVM_REG_RISCV_CSR_AIA | KVM_REG_RISCV_CSR_REG(" #csr ")"
+#define RISCV_CSR_SMSTATEEN(csr) \
+       "KVM_REG_RISCV_CSR_SMSTATEEN | KVM_REG_RISCV_CSR_REG(" #csr ")"
 
 static const char *general_csr_id_to_str(__u64 reg_off)
 {
@@ -209,10 +214,11 @@ static const char *general_csr_id_to_str(__u64 reg_off)
                return RISCV_CSR_GENERAL(satp);
        case KVM_REG_RISCV_CSR_REG(scounteren):
                return RISCV_CSR_GENERAL(scounteren);
+       case KVM_REG_RISCV_CSR_REG(senvcfg):
+               return RISCV_CSR_GENERAL(senvcfg);
        }
 
-       TEST_FAIL("Unknown general csr reg: 0x%llx", reg_off);
-       return NULL;
+       return strdup_printf("KVM_REG_RISCV_CSR_GENERAL | %lld /* UNKNOWN */", reg_off);
 }
 
 static const char *aia_csr_id_to_str(__u64 reg_off)
@@ -235,7 +241,18 @@ static const char *aia_csr_id_to_str(__u64 reg_off)
                return RISCV_CSR_AIA(iprio2h);
        }
 
-       TEST_FAIL("Unknown aia csr reg: 0x%llx", reg_off);
+       return strdup_printf("KVM_REG_RISCV_CSR_AIA | %lld /* UNKNOWN */", reg_off);
+}
+
+static const char *smstateen_csr_id_to_str(__u64 reg_off)
+{
+       /* reg_off is the offset into struct kvm_riscv_smstateen_csr */
+       switch (reg_off) {
+       case KVM_REG_RISCV_CSR_SMSTATEEN_REG(sstateen0):
+               return RISCV_CSR_SMSTATEEN(sstateen0);
+       }
+
+       TEST_FAIL("Unknown smstateen csr reg: 0x%llx", reg_off);
        return NULL;
 }
 
@@ -244,6 +261,8 @@ static const char *csr_id_to_str(const char *prefix, __u64 id)
        __u64 reg_off = id & ~(REG_MASK | KVM_REG_RISCV_CSR);
        __u64 reg_subtype = reg_off & KVM_REG_RISCV_SUBTYPE_MASK;
 
+       assert((id & KVM_REG_RISCV_TYPE_MASK) == KVM_REG_RISCV_CSR);
+
        reg_off &= ~KVM_REG_RISCV_SUBTYPE_MASK;
 
        switch (reg_subtype) {
@@ -251,10 +270,11 @@ static const char *csr_id_to_str(const char *prefix, __u64 id)
                return general_csr_id_to_str(reg_off);
        case KVM_REG_RISCV_CSR_AIA:
                return aia_csr_id_to_str(reg_off);
+       case KVM_REG_RISCV_CSR_SMSTATEEN:
+               return smstateen_csr_id_to_str(reg_off);
        }
 
-       TEST_FAIL("%s: Unknown csr subtype: 0x%llx", prefix, reg_subtype);
-       return NULL;
+       return strdup_printf("%lld | %lld /* UNKNOWN */", reg_subtype, reg_off);
 }
 
 static const char *timer_id_to_str(const char *prefix, __u64 id)
@@ -262,6 +282,8 @@ static const char *timer_id_to_str(const char *prefix, __u64 id)
        /* reg_off is the offset into struct kvm_riscv_timer */
        __u64 reg_off = id & ~(REG_MASK | KVM_REG_RISCV_TIMER);
 
+       assert((id & KVM_REG_RISCV_TYPE_MASK) == KVM_REG_RISCV_TIMER);
+
        switch (reg_off) {
        case KVM_REG_RISCV_TIMER_REG(frequency):
                return "KVM_REG_RISCV_TIMER_REG(frequency)";
@@ -273,8 +295,7 @@ static const char *timer_id_to_str(const char *prefix, __u64 id)
                return "KVM_REG_RISCV_TIMER_REG(state)";
        }
 
-       TEST_FAIL("%s: Unknown timer reg id: 0x%llx", prefix, id);
-       return NULL;
+       return strdup_printf("%lld /* UNKNOWN */", reg_off);
 }
 
 static const char *fp_f_id_to_str(const char *prefix, __u64 id)
@@ -282,6 +303,8 @@ static const char *fp_f_id_to_str(const char *prefix, __u64 id)
        /* reg_off is the offset into struct __riscv_f_ext_state */
        __u64 reg_off = id & ~(REG_MASK | KVM_REG_RISCV_FP_F);
 
+       assert((id & KVM_REG_RISCV_TYPE_MASK) == KVM_REG_RISCV_FP_F);
+
        switch (reg_off) {
        case KVM_REG_RISCV_FP_F_REG(f[0]) ...
             KVM_REG_RISCV_FP_F_REG(f[31]):
@@ -290,8 +313,7 @@ static const char *fp_f_id_to_str(const char *prefix, __u64 id)
                return "KVM_REG_RISCV_FP_F_REG(fcsr)";
        }
 
-       TEST_FAIL("%s: Unknown fp_f reg id: 0x%llx", prefix, id);
-       return NULL;
+       return strdup_printf("%lld /* UNKNOWN */", reg_off);
 }
 
 static const char *fp_d_id_to_str(const char *prefix, __u64 id)
@@ -299,6 +321,8 @@ static const char *fp_d_id_to_str(const char *prefix, __u64 id)
        /* reg_off is the offset into struct __riscv_d_ext_state */
        __u64 reg_off = id & ~(REG_MASK | KVM_REG_RISCV_FP_D);
 
+       assert((id & KVM_REG_RISCV_TYPE_MASK) == KVM_REG_RISCV_FP_D);
+
        switch (reg_off) {
        case KVM_REG_RISCV_FP_D_REG(f[0]) ...
             KVM_REG_RISCV_FP_D_REG(f[31]):
@@ -307,96 +331,93 @@ static const char *fp_d_id_to_str(const char *prefix, __u64 id)
                return "KVM_REG_RISCV_FP_D_REG(fcsr)";
        }
 
-       TEST_FAIL("%s: Unknown fp_d reg id: 0x%llx", prefix, id);
-       return NULL;
+       return strdup_printf("%lld /* UNKNOWN */", reg_off);
 }
 
-static const char *isa_ext_id_to_str(__u64 id)
+#define KVM_ISA_EXT_ARR(ext)           \
+[KVM_RISCV_ISA_EXT_##ext] = "KVM_RISCV_ISA_EXT_" #ext
+
+static const char *isa_ext_id_to_str(const char *prefix, __u64 id)
 {
        /* reg_off is the offset into unsigned long kvm_isa_ext_arr[] */
        __u64 reg_off = id & ~(REG_MASK | KVM_REG_RISCV_ISA_EXT);
 
+       assert((id & KVM_REG_RISCV_TYPE_MASK) == KVM_REG_RISCV_ISA_EXT);
+
        static const char * const kvm_isa_ext_reg_name[] = {
-               "KVM_RISCV_ISA_EXT_A",
-               "KVM_RISCV_ISA_EXT_C",
-               "KVM_RISCV_ISA_EXT_D",
-               "KVM_RISCV_ISA_EXT_F",
-               "KVM_RISCV_ISA_EXT_H",
-               "KVM_RISCV_ISA_EXT_I",
-               "KVM_RISCV_ISA_EXT_M",
-               "KVM_RISCV_ISA_EXT_SVPBMT",
-               "KVM_RISCV_ISA_EXT_SSTC",
-               "KVM_RISCV_ISA_EXT_SVINVAL",
-               "KVM_RISCV_ISA_EXT_ZIHINTPAUSE",
-               "KVM_RISCV_ISA_EXT_ZICBOM",
-               "KVM_RISCV_ISA_EXT_ZICBOZ",
-               "KVM_RISCV_ISA_EXT_ZBB",
-               "KVM_RISCV_ISA_EXT_SSAIA",
-               "KVM_RISCV_ISA_EXT_V",
-               "KVM_RISCV_ISA_EXT_SVNAPOT",
-               "KVM_RISCV_ISA_EXT_ZBA",
-               "KVM_RISCV_ISA_EXT_ZBS",
-               "KVM_RISCV_ISA_EXT_ZICNTR",
-               "KVM_RISCV_ISA_EXT_ZICSR",
-               "KVM_RISCV_ISA_EXT_ZIFENCEI",
-               "KVM_RISCV_ISA_EXT_ZIHPM",
+               KVM_ISA_EXT_ARR(A),
+               KVM_ISA_EXT_ARR(C),
+               KVM_ISA_EXT_ARR(D),
+               KVM_ISA_EXT_ARR(F),
+               KVM_ISA_EXT_ARR(H),
+               KVM_ISA_EXT_ARR(I),
+               KVM_ISA_EXT_ARR(M),
+               KVM_ISA_EXT_ARR(V),
+               KVM_ISA_EXT_ARR(SMSTATEEN),
+               KVM_ISA_EXT_ARR(SSAIA),
+               KVM_ISA_EXT_ARR(SSTC),
+               KVM_ISA_EXT_ARR(SVINVAL),
+               KVM_ISA_EXT_ARR(SVNAPOT),
+               KVM_ISA_EXT_ARR(SVPBMT),
+               KVM_ISA_EXT_ARR(ZBA),
+               KVM_ISA_EXT_ARR(ZBB),
+               KVM_ISA_EXT_ARR(ZBS),
+               KVM_ISA_EXT_ARR(ZICBOM),
+               KVM_ISA_EXT_ARR(ZICBOZ),
+               KVM_ISA_EXT_ARR(ZICNTR),
+               KVM_ISA_EXT_ARR(ZICOND),
+               KVM_ISA_EXT_ARR(ZICSR),
+               KVM_ISA_EXT_ARR(ZIFENCEI),
+               KVM_ISA_EXT_ARR(ZIHINTPAUSE),
+               KVM_ISA_EXT_ARR(ZIHPM),
        };
 
-       if (reg_off >= ARRAY_SIZE(kvm_isa_ext_reg_name)) {
-               /*
-                * isa_ext regs would grow regularly with new isa extension added, so
-                * just show "reg" to indicate a new extension.
-                */
+       if (reg_off >= ARRAY_SIZE(kvm_isa_ext_reg_name))
                return strdup_printf("%lld /* UNKNOWN */", reg_off);
-       }
 
        return kvm_isa_ext_reg_name[reg_off];
 }
 
+#define KVM_SBI_EXT_ARR(ext)           \
+[ext] = "KVM_REG_RISCV_SBI_SINGLE | " #ext
+
 static const char *sbi_ext_single_id_to_str(__u64 reg_off)
 {
        /* reg_off is KVM_RISCV_SBI_EXT_ID */
        static const char * const kvm_sbi_ext_reg_name[] = {
-               "KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_V01",
-               "KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_TIME",
-               "KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_IPI",
-               "KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_RFENCE",
-               "KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_SRST",
-               "KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_HSM",
-               "KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_PMU",
-               "KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_EXPERIMENTAL",
-               "KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_VENDOR",
+               KVM_SBI_EXT_ARR(KVM_RISCV_SBI_EXT_V01),
+               KVM_SBI_EXT_ARR(KVM_RISCV_SBI_EXT_TIME),
+               KVM_SBI_EXT_ARR(KVM_RISCV_SBI_EXT_IPI),
+               KVM_SBI_EXT_ARR(KVM_RISCV_SBI_EXT_RFENCE),
+               KVM_SBI_EXT_ARR(KVM_RISCV_SBI_EXT_SRST),
+               KVM_SBI_EXT_ARR(KVM_RISCV_SBI_EXT_HSM),
+               KVM_SBI_EXT_ARR(KVM_RISCV_SBI_EXT_PMU),
+               KVM_SBI_EXT_ARR(KVM_RISCV_SBI_EXT_EXPERIMENTAL),
+               KVM_SBI_EXT_ARR(KVM_RISCV_SBI_EXT_VENDOR),
+               KVM_SBI_EXT_ARR(KVM_RISCV_SBI_EXT_DBCN),
        };
 
-       if (reg_off >= ARRAY_SIZE(kvm_sbi_ext_reg_name)) {
-               /*
-                * sbi_ext regs would grow regularly with new sbi extension added, so
-                * just show "reg" to indicate a new extension.
-                */
+       if (reg_off >= ARRAY_SIZE(kvm_sbi_ext_reg_name))
                return strdup_printf("KVM_REG_RISCV_SBI_SINGLE | %lld /* UNKNOWN */", reg_off);
-       }
 
        return kvm_sbi_ext_reg_name[reg_off];
 }
 
 static const char *sbi_ext_multi_id_to_str(__u64 reg_subtype, __u64 reg_off)
 {
-       if (reg_off > KVM_REG_RISCV_SBI_MULTI_REG_LAST) {
-               /*
-                * sbi_ext regs would grow regularly with new sbi extension added, so
-                * just show "reg" to indicate a new extension.
-                */
-               return strdup_printf("%lld /* UNKNOWN */", reg_off);
-       }
+       const char *unknown = "";
+
+       if (reg_off > KVM_REG_RISCV_SBI_MULTI_REG_LAST)
+               unknown = " /* UNKNOWN */";
 
        switch (reg_subtype) {
        case KVM_REG_RISCV_SBI_MULTI_EN:
-               return strdup_printf("KVM_REG_RISCV_SBI_MULTI_EN | %lld", reg_off);
+               return strdup_printf("KVM_REG_RISCV_SBI_MULTI_EN | %lld%s", reg_off, unknown);
        case KVM_REG_RISCV_SBI_MULTI_DIS:
-               return strdup_printf("KVM_REG_RISCV_SBI_MULTI_DIS | %lld", reg_off);
+               return strdup_printf("KVM_REG_RISCV_SBI_MULTI_DIS | %lld%s", reg_off, unknown);
        }
 
-       return NULL;
+       return strdup_printf("%lld | %lld /* UNKNOWN */", reg_subtype, reg_off);
 }
 
 static const char *sbi_ext_id_to_str(const char *prefix, __u64 id)
@@ -404,6 +425,8 @@ static const char *sbi_ext_id_to_str(const char *prefix, __u64 id)
        __u64 reg_off = id & ~(REG_MASK | KVM_REG_RISCV_SBI_EXT);
        __u64 reg_subtype = reg_off & KVM_REG_RISCV_SUBTYPE_MASK;
 
+       assert((id & KVM_REG_RISCV_TYPE_MASK) == KVM_REG_RISCV_SBI_EXT);
+
        reg_off &= ~KVM_REG_RISCV_SUBTYPE_MASK;
 
        switch (reg_subtype) {
@@ -414,8 +437,7 @@ static const char *sbi_ext_id_to_str(const char *prefix, __u64 id)
                return sbi_ext_multi_id_to_str(reg_subtype, reg_off);
        }
 
-       TEST_FAIL("%s: Unknown sbi ext subtype: 0x%llx", prefix, reg_subtype);
-       return NULL;
+       return strdup_printf("%lld | %lld /* UNKNOWN */", reg_subtype, reg_off);
 }
 
 void print_reg(const char *prefix, __u64 id)
@@ -436,14 +458,14 @@ void print_reg(const char *prefix, __u64 id)
                reg_size = "KVM_REG_SIZE_U128";
                break;
        default:
-               TEST_FAIL("%s: Unexpected reg size: 0x%llx in reg id: 0x%llx",
-                         prefix, (id & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT, id);
+               printf("\tKVM_REG_RISCV | (%lld << KVM_REG_SIZE_SHIFT) | 0x%llx /* UNKNOWN */,",
+                      (id & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT, id & REG_MASK);
        }
 
        switch (id & KVM_REG_RISCV_TYPE_MASK) {
        case KVM_REG_RISCV_CONFIG:
                printf("\tKVM_REG_RISCV | %s | KVM_REG_RISCV_CONFIG | %s,\n",
-                               reg_size, config_id_to_str(id));
+                               reg_size, config_id_to_str(prefix, id));
                break;
        case KVM_REG_RISCV_CORE:
                printf("\tKVM_REG_RISCV | %s | KVM_REG_RISCV_CORE | %s,\n",
@@ -467,15 +489,15 @@ void print_reg(const char *prefix, __u64 id)
                break;
        case KVM_REG_RISCV_ISA_EXT:
                printf("\tKVM_REG_RISCV | %s | KVM_REG_RISCV_ISA_EXT | %s,\n",
-                               reg_size, isa_ext_id_to_str(id));
+                               reg_size, isa_ext_id_to_str(prefix, id));
                break;
        case KVM_REG_RISCV_SBI_EXT:
                printf("\tKVM_REG_RISCV | %s | KVM_REG_RISCV_SBI_EXT | %s,\n",
                                reg_size, sbi_ext_id_to_str(prefix, id));
                break;
        default:
-               TEST_FAIL("%s: Unexpected reg type: 0x%llx in reg id: 0x%llx", prefix,
-                               (id & KVM_REG_RISCV_TYPE_MASK) >> KVM_REG_RISCV_TYPE_SHIFT, id);
+               printf("\tKVM_REG_RISCV | %s | 0x%llx /* UNKNOWN */,",
+                               reg_size, id & REG_MASK);
        }
 }
 
@@ -532,6 +554,7 @@ static __u64 base_regs[] = {
        KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CSR | KVM_REG_RISCV_CSR_GENERAL | KVM_REG_RISCV_CSR_REG(sip),
        KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CSR | KVM_REG_RISCV_CSR_GENERAL | KVM_REG_RISCV_CSR_REG(satp),
        KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CSR | KVM_REG_RISCV_CSR_GENERAL | KVM_REG_RISCV_CSR_REG(scounteren),
+       KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CSR | KVM_REG_RISCV_CSR_GENERAL | KVM_REG_RISCV_CSR_REG(senvcfg),
        KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_TIMER | KVM_REG_RISCV_TIMER_REG(frequency),
        KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_TIMER | KVM_REG_RISCV_TIMER_REG(time),
        KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_TIMER | KVM_REG_RISCV_TIMER_REG(compare),
@@ -545,6 +568,7 @@ static __u64 base_regs[] = {
        KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_PMU,
        KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_EXPERIMENTAL,
        KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_VENDOR,
+       KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_DBCN,
        KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_MULTI_EN | 0,
        KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_MULTI_DIS | 0,
 };
@@ -603,6 +627,10 @@ static __u64 zicntr_regs[] = {
        KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZICNTR,
 };
 
+static __u64 zicond_regs[] = {
+       KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZICOND,
+};
+
 static __u64 zicsr_regs[] = {
        KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZICSR,
 };
@@ -626,6 +654,11 @@ static __u64 aia_regs[] = {
        KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_SSAIA,
 };
 
+static __u64 smstateen_regs[] = {
+       KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CSR | KVM_REG_RISCV_CSR_SMSTATEEN | KVM_REG_RISCV_CSR_SMSTATEEN_REG(sstateen0),
+       KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_SMSTATEEN,
+};
+
 static __u64 fp_f_regs[] = {
        KVM_REG_RISCV | KVM_REG_SIZE_U32 | KVM_REG_RISCV_FP_F | KVM_REG_RISCV_FP_F_REG(f[0]),
        KVM_REG_RISCV | KVM_REG_SIZE_U32 | KVM_REG_RISCV_FP_F | KVM_REG_RISCV_FP_F_REG(f[1]),
@@ -725,6 +758,8 @@ static __u64 fp_d_regs[] = {
        {"zbs", .feature = KVM_RISCV_ISA_EXT_ZBS, .regs = zbs_regs, .regs_n = ARRAY_SIZE(zbs_regs),}
 #define ZICNTR_REGS_SUBLIST \
        {"zicntr", .feature = KVM_RISCV_ISA_EXT_ZICNTR, .regs = zicntr_regs, .regs_n = ARRAY_SIZE(zicntr_regs),}
+#define ZICOND_REGS_SUBLIST \
+       {"zicond", .feature = KVM_RISCV_ISA_EXT_ZICOND, .regs = zicond_regs, .regs_n = ARRAY_SIZE(zicond_regs),}
 #define ZICSR_REGS_SUBLIST \
        {"zicsr", .feature = KVM_RISCV_ISA_EXT_ZICSR, .regs = zicsr_regs, .regs_n = ARRAY_SIZE(zicsr_regs),}
 #define ZIFENCEI_REGS_SUBLIST \
@@ -733,6 +768,8 @@ static __u64 fp_d_regs[] = {
        {"zihpm", .feature = KVM_RISCV_ISA_EXT_ZIHPM, .regs = zihpm_regs, .regs_n = ARRAY_SIZE(zihpm_regs),}
 #define AIA_REGS_SUBLIST \
        {"aia", .feature = KVM_RISCV_ISA_EXT_SSAIA, .regs = aia_regs, .regs_n = ARRAY_SIZE(aia_regs),}
+#define SMSTATEEN_REGS_SUBLIST \
+       {"smstateen", .feature = KVM_RISCV_ISA_EXT_SMSTATEEN, .regs = smstateen_regs, .regs_n = ARRAY_SIZE(smstateen_regs),}
 #define FP_F_REGS_SUBLIST \
        {"fp_f", .feature = KVM_RISCV_ISA_EXT_F, .regs = fp_f_regs, \
                .regs_n = ARRAY_SIZE(fp_f_regs),}
@@ -828,6 +865,14 @@ static struct vcpu_reg_list zicntr_config = {
        },
 };
 
+static struct vcpu_reg_list zicond_config = {
+       .sublists = {
+       BASE_SUBLIST,
+       ZICOND_REGS_SUBLIST,
+       {0},
+       },
+};
+
 static struct vcpu_reg_list zicsr_config = {
        .sublists = {
        BASE_SUBLIST,
@@ -860,6 +905,14 @@ static struct vcpu_reg_list aia_config = {
        },
 };
 
+static struct vcpu_reg_list smstateen_config = {
+       .sublists = {
+       BASE_SUBLIST,
+       SMSTATEEN_REGS_SUBLIST,
+       {0},
+       },
+};
+
 static struct vcpu_reg_list fp_f_config = {
        .sublists = {
        BASE_SUBLIST,
@@ -888,10 +941,12 @@ struct vcpu_reg_list *vcpu_configs[] = {
        &zbb_config,
        &zbs_config,
        &zicntr_config,
+       &zicond_config,
        &zicsr_config,
        &zifencei_config,
        &zihpm_config,
        &aia_config,
+       &smstateen_config,
        &fp_f_config,
        &fp_d_config,
 };
diff --git a/tools/testing/selftests/kvm/x86_64/hwcr_msr_test.c b/tools/testing/selftests/kvm/x86_64/hwcr_msr_test.c
new file mode 100644 (file)
index 0000000..df351ae
--- /dev/null
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023, Google LLC.
+ */
+
+#define _GNU_SOURCE /* for program_invocation_short_name */
+#include <sys/ioctl.h>
+
+#include "test_util.h"
+#include "kvm_util.h"
+#include "vmx.h"
+
+void test_hwcr_bit(struct kvm_vcpu *vcpu, unsigned int bit)
+{
+       const uint64_t ignored = BIT_ULL(3) | BIT_ULL(6) | BIT_ULL(8);
+       const uint64_t valid = BIT_ULL(18) | BIT_ULL(24);
+       const uint64_t legal = ignored | valid;
+       uint64_t val = BIT_ULL(bit);
+       uint64_t actual;
+       int r;
+
+       r = _vcpu_set_msr(vcpu, MSR_K7_HWCR, val);
+       TEST_ASSERT(val & ~legal ? !r : r == 1,
+                   "Expected KVM_SET_MSRS(MSR_K7_HWCR) = 0x%lx to %s",
+                   val, val & ~legal ? "fail" : "succeed");
+
+       actual = vcpu_get_msr(vcpu, MSR_K7_HWCR);
+       TEST_ASSERT(actual == (val & valid),
+                   "Bit %u: unexpected HWCR 0x%lx; expected 0x%lx",
+                   bit, actual, (val & valid));
+
+       vcpu_set_msr(vcpu, MSR_K7_HWCR, 0);
+}
+
+int main(int argc, char *argv[])
+{
+       struct kvm_vm *vm;
+       struct kvm_vcpu *vcpu;
+       unsigned int bit;
+
+       vm = vm_create_with_one_vcpu(&vcpu, NULL);
+
+       for (bit = 0; bit < BITS_PER_LONG; bit++)
+               test_hwcr_bit(vcpu, bit);
+
+       kvm_vm_free(vm);
+}
index e446d76d1c0c38f7ed41ff0ed3dfc736b6b3693c..6c127856209065f5345ff2590383e532891467fe 100644 (file)
@@ -1,7 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * KVM_GET/SET_* tests
- *
  * Copyright (C) 2022, Red Hat, Inc.
  *
  * Tests for Hyper-V extensions to SVM.
index 7f36c32fa76093a6affe275e237edda24f7020c6..18ac5c1952a3a382590d799c8959f600cafc7cd2 100644 (file)
@@ -1,7 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * tools/testing/selftests/kvm/nx_huge_page_test.c
- *
  * Usage: to be run via nx_huge_page_test.sh, which does the necessary
  * environment setup and teardown
  *
index 0560149e66ed3be5bcee95c34315188ee2ba540d..7cbb409801eea71452a87c08846437af2e02dd0d 100755 (executable)
@@ -4,7 +4,6 @@
 # Wrapper script which performs setup and cleanup for nx_huge_pages_test.
 # Makes use of root privileges to set up huge pages and KVM module parameters.
 #
-# tools/testing/selftests/kvm/nx_huge_page_test.sh
 # Copyright (C) 2022, Google LLC.
 
 set -e
index 4c4925a8ab4523452326a417634764f85fce19ca..88b58aab720773b3411e0962fbfd398b9f46ebd7 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 5b669818e39aaa2313d0887c0324aca4b628ed3c..59c7304f805efd0f73ecacca5807e83ad0b45319 100644 (file)
@@ -1,10 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * svm_vmcall_test
- *
  * Copyright © 2021 Amazon.com, Inc. or its affiliates.
- *
- * Xen shared_info / pvclock testing
  */
 
 #include "test_util.h"
index 05898ad9f4d992b3c7eba0a9ec677b21315689e6..9ec9ab60b63ee27d2deb6f90d9b38a71e2deb142 100644 (file)
@@ -1,10 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * svm_vmcall_test
- *
  * Copyright © 2021 Amazon.com, Inc. or its affiliates.
- *
- * Xen shared_info / pvclock testing
  */
 
 #include "test_util.h"
index a5cb4b09a46c421cdeb5d2968f389a388f5a30fb..0899019a7fcb4b04bcedca44227f2c2dd5a83597 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 bf2d2a684edfdbaec2b1852ce0a3094cc57c6eb9..14d26075c8635f67cc5885092de359d5c322f38b 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 ca2359835e751b69c9a4c280129d6ca6200a11e9..a06e73ec856823a9899f7a9234db1aae52d1375f 100644 (file)
@@ -7,6 +7,7 @@
  */
 #define _GNU_SOURCE
 #include <sys/mman.h>
+#include <linux/mman.h>
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
index 8b017070960d3f783462cb79dfea6d5c6dc43f64..4a2881d43989c2653027a20bd4266e1b6fe3a0e2 100644 (file)
@@ -34,6 +34,7 @@ TEST_PROGS += gro.sh
 TEST_PROGS += gre_gso.sh
 TEST_PROGS += cmsg_so_mark.sh
 TEST_PROGS += cmsg_time.sh cmsg_ipv6.sh
+TEST_PROGS += netns-name.sh
 TEST_PROGS += srv6_end_dt46_l3vpn_test.sh
 TEST_PROGS += srv6_end_dt4_l3vpn_test.sh
 TEST_PROGS += srv6_end_dt6_l3vpn_test.sh
index e7d2a530618a16c7c44af32d0db849d7df75b296..66d0db7a2614d32e24e04a19d03a016a3b2d293a 100755 (executable)
@@ -2437,6 +2437,9 @@ ipv4_mpath_list_test()
        run_cmd "ip -n ns2 route add 203.0.113.0/24
                nexthop via 172.16.201.2 nexthop via 172.16.202.2"
        run_cmd "ip netns exec ns2 sysctl -qw net.ipv4.fib_multipath_hash_policy=1"
+       run_cmd "ip netns exec ns2 sysctl -qw net.ipv4.conf.veth2.rp_filter=0"
+       run_cmd "ip netns exec ns2 sysctl -qw net.ipv4.conf.all.rp_filter=0"
+       run_cmd "ip netns exec ns2 sysctl -qw net.ipv4.conf.default.rp_filter=0"
        set +e
 
        local dmac=$(ip -n ns2 -j link show dev veth2 | jq -r '.[]["address"]')
@@ -2449,7 +2452,7 @@ ipv4_mpath_list_test()
        # words, the FIB lookup tracepoint needs to be triggered for every
        # packet.
        local t0_rx_pkts=$(link_stats_get ns2 veth2 rx packets)
-       run_cmd "perf stat -e fib:fib_table_lookup --filter 'err == 0' -j -o $tmp_file -- $cmd"
+       run_cmd "perf stat -a -e fib:fib_table_lookup --filter 'err == 0' -j -o $tmp_file -- $cmd"
        local t1_rx_pkts=$(link_stats_get ns2 veth2 rx packets)
        local diff=$(echo $t1_rx_pkts - $t0_rx_pkts | bc -l)
        list_rcv_eval $tmp_file $diff
@@ -2494,7 +2497,7 @@ ipv6_mpath_list_test()
        # words, the FIB lookup tracepoint needs to be triggered for every
        # packet.
        local t0_rx_pkts=$(link_stats_get ns2 veth2 rx packets)
-       run_cmd "perf stat -e fib6:fib6_table_lookup --filter 'err == 0' -j -o $tmp_file -- $cmd"
+       run_cmd "perf stat -a -e fib6:fib6_table_lookup --filter 'err == 0' -j -o $tmp_file -- $cmd"
        local t1_rx_pkts=$(link_stats_get ns2 veth2 rx packets)
        local diff=$(echo $t1_rx_pkts - $t0_rx_pkts | bc -l)
        list_rcv_eval $tmp_file $diff
index df914353870862c89acbf18ed77737901e3cf20c..1c6457e54625704363566b48999fa88206d7eb7a 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 ee1f89a872b3fd0a2bdd507fe057f8d4a9f914d1..dc895b7b94e19da1e9fc4eca4651d1210f1383a2 100755 (executable)
@@ -1432,7 +1432,9 @@ chk_rst_nr()
        count=$(get_counter ${ns_tx} "MPTcpExtMPRstTx")
        if [ -z "$count" ]; then
                print_skip
-       elif [ $count -lt $rst_tx ]; then
+       # accept more rst than expected except if we don't expect any
+       elif { [ $rst_tx -ne 0 ] && [ $count -lt $rst_tx ]; } ||
+            { [ $rst_tx -eq 0 ] && [ $count -ne 0 ]; }; then
                fail_test "got $count MP_RST[s] TX expected $rst_tx"
        else
                print_ok
@@ -1442,7 +1444,9 @@ chk_rst_nr()
        count=$(get_counter ${ns_rx} "MPTcpExtMPRstRx")
        if [ -z "$count" ]; then
                print_skip
-       elif [ "$count" -lt "$rst_rx" ]; then
+       # accept more rst than expected except if we don't expect any
+       elif { [ $rst_rx -ne 0 ] && [ $count -lt $rst_rx ]; } ||
+            { [ $rst_rx -eq 0 ] && [ $count -ne 0 ]; }; then
                fail_test "got $count MP_RST[s] RX expected $rst_rx"
        else
                print_ok
@@ -2305,6 +2309,7 @@ remove_tests()
                chk_join_nr 1 1 1
                chk_rm_tx_nr 1
                chk_rm_nr 1 1
+               chk_rst_nr 0 0
        fi
 
        # multiple subflows, remove
@@ -2317,6 +2322,7 @@ remove_tests()
                        run_tests $ns1 $ns2 10.0.1.1
                chk_join_nr 2 2 2
                chk_rm_nr 2 2
+               chk_rst_nr 0 0
        fi
 
        # single address, remove
@@ -2329,6 +2335,7 @@ remove_tests()
                chk_join_nr 1 1 1
                chk_add_nr 1 1
                chk_rm_nr 1 1 invert
+               chk_rst_nr 0 0
        fi
 
        # subflow and signal, remove
@@ -2342,6 +2349,7 @@ remove_tests()
                chk_join_nr 2 2 2
                chk_add_nr 1 1
                chk_rm_nr 1 1
+               chk_rst_nr 0 0
        fi
 
        # subflows and signal, remove
@@ -2356,6 +2364,7 @@ remove_tests()
                chk_join_nr 3 3 3
                chk_add_nr 1 1
                chk_rm_nr 2 2
+               chk_rst_nr 0 0
        fi
 
        # addresses remove
@@ -2370,6 +2379,7 @@ remove_tests()
                chk_join_nr 3 3 3
                chk_add_nr 3 3
                chk_rm_nr 3 3 invert
+               chk_rst_nr 0 0
        fi
 
        # invalid addresses remove
@@ -2384,6 +2394,7 @@ remove_tests()
                chk_join_nr 1 1 1
                chk_add_nr 3 3
                chk_rm_nr 3 1 invert
+               chk_rst_nr 0 0
        fi
 
        # subflows and signal, flush
@@ -2398,6 +2409,7 @@ remove_tests()
                chk_join_nr 3 3 3
                chk_add_nr 1 1
                chk_rm_nr 1 3 invert simult
+               chk_rst_nr 0 0
        fi
 
        # subflows flush
@@ -2417,6 +2429,7 @@ remove_tests()
                else
                        chk_rm_nr 3 3
                fi
+               chk_rst_nr 0 0
        fi
 
        # addresses flush
@@ -2431,6 +2444,7 @@ remove_tests()
                chk_join_nr 3 3 3
                chk_add_nr 3 3
                chk_rm_nr 3 3 invert simult
+               chk_rst_nr 0 0
        fi
 
        # invalid addresses flush
@@ -2445,6 +2459,7 @@ remove_tests()
                chk_join_nr 1 1 1
                chk_add_nr 3 3
                chk_rm_nr 3 1 invert
+               chk_rst_nr 0 0
        fi
 
        # remove id 0 subflow
@@ -2456,6 +2471,7 @@ remove_tests()
                        run_tests $ns1 $ns2 10.0.1.1
                chk_join_nr 1 1 1
                chk_rm_nr 1 1
+               chk_rst_nr 0 0
        fi
 
        # remove id 0 address
@@ -2468,6 +2484,7 @@ remove_tests()
                chk_join_nr 1 1 1
                chk_add_nr 1 1
                chk_rm_nr 1 1 invert
+               chk_rst_nr 0 0 invert
        fi
 }
 
diff --git a/tools/testing/selftests/net/netns-name.sh b/tools/testing/selftests/net/netns-name.sh
new file mode 100755 (executable)
index 0000000..7d3d3fc
--- /dev/null
@@ -0,0 +1,87 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+set -o pipefail
+
+NS=netns-name-test
+DEV=dummy-dev0
+DEV2=dummy-dev1
+ALT_NAME=some-alt-name
+
+RET_CODE=0
+
+cleanup() {
+    ip netns del $NS
+}
+
+trap cleanup EXIT
+
+fail() {
+    echo "ERROR: ${1:-unexpected return code} (ret: $_)" >&2
+    RET_CODE=1
+}
+
+ip netns add $NS
+
+#
+# Test basic move without a rename
+#
+ip -netns $NS link add name $DEV type dummy || fail
+ip -netns $NS link set dev $DEV netns 1 ||
+    fail "Can't perform a netns move"
+ip link show dev $DEV >> /dev/null || fail "Device not found after move"
+ip link del $DEV || fail
+
+#
+# Test move with a conflict
+#
+ip link add name $DEV type dummy
+ip -netns $NS link add name $DEV type dummy || fail
+ip -netns $NS link set dev $DEV netns 1 2> /dev/null &&
+    fail "Performed a netns move with a name conflict"
+ip link show dev $DEV >> /dev/null || fail "Device not found after move"
+ip -netns $NS link del $DEV || fail
+ip link del $DEV || fail
+
+#
+# Test move with a conflict and rename
+#
+ip link add name $DEV type dummy
+ip -netns $NS link add name $DEV type dummy || fail
+ip -netns $NS link set dev $DEV netns 1 name $DEV2 ||
+    fail "Can't perform a netns move with rename"
+ip link del $DEV2 || fail
+ip link del $DEV || fail
+
+#
+# Test dup alt-name with netns move
+#
+ip link add name $DEV type dummy || fail
+ip link property add dev $DEV altname $ALT_NAME || fail
+ip -netns $NS link add name $DEV2 type dummy || fail
+ip -netns $NS link property add dev $DEV2 altname $ALT_NAME || fail
+
+ip -netns $NS link set dev $DEV2 netns 1 2> /dev/null &&
+    fail "Moved with alt-name dup"
+
+ip link del $DEV || fail
+ip -netns $NS link del $DEV2 || fail
+
+#
+# Test creating alt-name in one net-ns and using in another
+#
+ip -netns $NS link add name $DEV type dummy || fail
+ip -netns $NS link property add dev $DEV altname $ALT_NAME || fail
+ip -netns $NS link set dev $DEV netns 1 || fail
+ip link show dev $ALT_NAME >> /dev/null || fail "Can't find alt-name after move"
+ip  -netns $NS link show dev $ALT_NAME 2> /dev/null &&
+    fail "Can still find alt-name after move"
+ip link del $DEV || fail
+
+echo -ne "$(basename $0) \t\t\t\t"
+if [ $RET_CODE -eq 0 ]; then
+    echo "[  OK  ]"
+else
+    echo "[ FAIL ]"
+fi
+exit $RET_CODE
index 9c2012d70b08ec7d66738090b0d3465470f6792f..f8499d4c87f3f763e774619666e00ce6a17d333b 100755 (executable)
@@ -3,6 +3,8 @@
 #
 # OVS kernel module self tests
 
+trap ovs_exit_sig EXIT TERM INT ERR
+
 # Kselftest framework requirement - SKIP code is 4.
 ksft_skip=4
 
@@ -142,6 +144,12 @@ ovs_add_flow () {
        return 0
 }
 
+ovs_del_flows () {
+       info "Deleting all flows from DP: sbx:$1 br:$2"
+       ovs_sbx "$1" python3 $ovs_base/ovs-dpctl.py del-flows "$2"
+       return 0
+}
+
 ovs_drop_record_and_run () {
        local sbx=$1
        shift
@@ -198,6 +206,17 @@ test_drop_reason() {
        ip netns exec server ip addr add 172.31.110.20/24 dev s1
        ip netns exec server ip link set s1 up
 
+       # Check if drop reasons can be sent
+       ovs_add_flow "test_drop_reason" dropreason \
+               'in_port(1),eth(),eth_type(0x0806),arp()' 'drop(10)' 2>/dev/null
+       if [ $? == 1 ]; then
+               info "no support for drop reasons - skipping"
+               ovs_exit_sig
+               return $ksft_skip
+       fi
+
+       ovs_del_flows "test_drop_reason" dropreason
+
        # Allow ARP
        ovs_add_flow "test_drop_reason" dropreason \
                'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1
@@ -525,7 +544,7 @@ run_test() {
        fi
 
        if python3 ovs-dpctl.py -h 2>&1 | \
-            grep "Need to install the python" >/dev/null 2>&1; then
+            grep -E "Need to (install|upgrade) the python" >/dev/null 2>&1; then
                stdbuf -o0 printf "TEST: %-60s  [PYLIB]\n" "${tdesc}"
                return $ksft_skip
        fi
index 912dc8c4908582f936fdc1f2c2fb69c6f46d4417..b97e621face958838f1ad5cf2d12dfc5875db4f4 100644 (file)
@@ -28,8 +28,10 @@ try:
     from pyroute2.netlink import nlmsg_atoms
     from pyroute2.netlink.exceptions import NetlinkError
     from pyroute2.netlink.generic import GenericNetlinkSocket
+    import pyroute2
+
 except ModuleNotFoundError:
-    print("Need to install the python pyroute2 package.")
+    print("Need to install the python pyroute2 package >= 0.6.")
     sys.exit(0)
 
 
@@ -1117,12 +1119,14 @@ class ovskey(nla):
                 "src",
                 lambda x: str(ipaddress.IPv4Address(x)),
                 int,
+                convert_ipv4,
             ),
             (
                 "dst",
                 "dst",
-                lambda x: str(ipaddress.IPv6Address(x)),
+                lambda x: str(ipaddress.IPv4Address(x)),
                 int,
+                convert_ipv4,
             ),
             ("tp_src", "tp_src", "%d", int),
             ("tp_dst", "tp_dst", "%d", int),
@@ -1904,6 +1908,32 @@ class OvsFlow(GenericNetlinkSocket):
             raise ne
         return reply
 
+    def del_flows(self, dpifindex):
+        """
+        Send a del message to the kernel that will drop all flows.
+
+        dpifindex should be a valid datapath obtained by calling
+        into the OvsDatapath lookup
+        """
+
+        flowmsg = OvsFlow.ovs_flow_msg()
+        flowmsg["cmd"] = OVS_FLOW_CMD_DEL
+        flowmsg["version"] = OVS_DATAPATH_VERSION
+        flowmsg["reserved"] = 0
+        flowmsg["dpifindex"] = dpifindex
+
+        try:
+            reply = self.nlm_request(
+                flowmsg,
+                msg_type=self.prid,
+                msg_flags=NLM_F_REQUEST | NLM_F_ACK,
+            )
+            reply = reply[0]
+        except NetlinkError as ne:
+            print(flowmsg)
+            raise ne
+        return reply
+
     def dump(self, dpifindex, flowspec=None):
         """
         Returns a list of messages containing flows.
@@ -1998,6 +2028,12 @@ def main(argv):
     nlmsg_atoms.ovskey = ovskey
     nlmsg_atoms.ovsactions = ovsactions
 
+    # version check for pyroute2
+    prverscheck = pyroute2.__version__.split(".")
+    if int(prverscheck[0]) == 0 and int(prverscheck[1]) < 6:
+        print("Need to upgrade the python pyroute2 package to >= 0.6.")
+        sys.exit(0)
+
     parser = argparse.ArgumentParser()
     parser.add_argument(
         "-v",
@@ -2060,6 +2096,9 @@ def main(argv):
     addflcmd.add_argument("flow", help="Flow specification")
     addflcmd.add_argument("acts", help="Flow actions")
 
+    delfscmd = subparsers.add_parser("del-flows")
+    delfscmd.add_argument("flsbr", help="Datapath name")
+
     args = parser.parse_args()
 
     if args.verbose > 0:
@@ -2143,6 +2182,11 @@ def main(argv):
         flow = OvsFlow.ovs_flow_msg()
         flow.parse(args.flow, args.acts, rep["dpifindex"])
         ovsflow.add_flow(rep["dpifindex"], flow)
+    elif hasattr(args, "flsbr"):
+        rep = ovsdp.info(args.flsbr, 0)
+        if rep is None:
+            print("DP '%s' not found." % args.flsbr)
+        ovsflow.del_flows(rep["dpifindex"])
 
     return 0
 
index 297d972558fbaf9e3dffb99b0c23642e2ab132f3..464853a7f98290ec3a7c6bf69786cf8c12e1f789 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 4cb887b574138ddc3a00c8d673a8281be2cfcc68..4b2928e1c19d839a25ba93fe80066e69c8f13aa1 100644 (file)
@@ -1,3 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0-only
 nf-queue
 connect_close
+audit_logread
index 3686bfa6c58d71337f9bb9d8028100fabbe2acd5..ef90aca4cc96af2b4c07c798927683bfa54073ae 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 4faf2ce021d90f69b9304d50c84dad73a2962f6d..7c42b1b2c69b4f6d6177d8eaa74f2d4ee45e11f5 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..99ed5bd
--- /dev/null
@@ -0,0 +1,245 @@
+#!/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
+}
+
+# Run everything in a separate network namespace
+[ "${1}" != "run" ] && { unshare -n "${0}" run; exit $?; }
+
+# give other scripts a chance to finish - audit_logread sees all activity
+sleep 1
+
+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'
+
+for ((i = 3; i <= 500; i++)); do
+       echo "add counter t2 c$i"
+done >$rulefile
+do_test "nft -f $rulefile" \
+'table=t2 family=2 entries=498 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'
+
+for ((i = 3; i <= 500; i++)); do
+       echo "add quota t2 q$i { 10 bytes }"
+done >$rulefile
+do_test "nft -f $rulefile" \
+'table=t2 family=2 entries=498 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'
+
+# resetting counters
+
+do_test 'nft reset counter t1 c1' \
+'table=t1 family=2 entries=1 op=nft_reset_obj'
+
+do_test 'nft reset counters t1' \
+'table=t1 family=2 entries=1 op=nft_reset_obj'
+
+do_test 'nft reset counters t2' \
+'table=t2 family=2 entries=342 op=nft_reset_obj
+table=t2 family=2 entries=158 op=nft_reset_obj'
+
+do_test 'nft reset counters' \
+'table=t1 family=2 entries=1 op=nft_reset_obj
+table=t2 family=2 entries=341 op=nft_reset_obj
+table=t2 family=2 entries=159 op=nft_reset_obj'
+
+# resetting quotas
+
+do_test 'nft reset quota t1 q1' \
+'table=t1 family=2 entries=1 op=nft_reset_obj'
+
+do_test 'nft reset quotas t1' \
+'table=t1 family=2 entries=1 op=nft_reset_obj'
+
+do_test 'nft reset quotas t2' \
+'table=t2 family=2 entries=315 op=nft_reset_obj
+table=t2 family=2 entries=185 op=nft_reset_obj'
+
+do_test 'nft reset quotas' \
+'table=t1 family=2 entries=1 op=nft_reset_obj
+table=t2 family=2 entries=314 op=nft_reset_obj
+table=t2 family=2 entries=186 op=nft_reset_obj'
+
+# 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 843ba56d8e49ecf35777214fff8690b4f6c688e7..254d676a2689835727155a35455fca128b0636f2 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 49f2ad1793fd98a09cb403efbf8aa37d40c85d6f..7ea42fa02eabd94c7f62977eea54f1d453cba5d9 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 2b95e44d20ff93b356850c5e613b5f17a37f1a4a..a284fa874a9f1f9ead2509e021b2debbf4f3825c 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 b16c13688b888baf70485462571e62224158d395..ee71ce52cb6a7279d2eb70434299f7718ed42b7c 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 11e0f05689234fd5598ef7e4660e7019944a9772..c333263f2b2751595cb069e2705e5100f3d9c124 100644 (file)
@@ -5,11 +5,11 @@
 # Additional include paths needed by kselftest.h and local headers
 CFLAGS += -D_GNU_SOURCE -std=gnu99 -I.
 
-TEST_GEN_FILES := testcases/mmap_default testcases/mmap_bottomup
+TEST_GEN_FILES := mmap_default mmap_bottomup
 
-TEST_PROGS := testcases/run_mmap.sh
+TEST_PROGS := run_mmap.sh
 
 include ../../lib.mk
 
-$(OUTPUT)/mm: testcases/mmap_default.c testcases/mmap_bottomup.c testcases/mmap_tests.h
+$(OUTPUT)/mm: mmap_default.c mmap_bottomup.c mmap_tests.h
        $(CC) -o$@ $(CFLAGS) $(LDFLAGS) $^
similarity index 97%
rename from tools/testing/selftests/riscv/mm/testcases/mmap_bottomup.c
rename to tools/testing/selftests/riscv/mm/mmap_bottomup.c
index b29379f7e478634eb95b455b32f013a3422e0a55..1757d19ca89b1bc06e6f9391440f502dd74adcbd 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 #include <sys/mman.h>
-#include <testcases/mmap_test.h>
+#include <mmap_test.h>
 
 #include "../../kselftest_harness.h"
 
similarity index 97%
rename from tools/testing/selftests/riscv/mm/testcases/mmap_default.c
rename to tools/testing/selftests/riscv/mm/mmap_default.c
index d1accb91b72626f373c18c84bbf52251dc002f77..c63c60b9397e7ff9d1949df11c229ae7388388bd 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 #include <sys/mman.h>
-#include <testcases/mmap_test.h>
+#include <mmap_test.h>
 
 #include "../../kselftest_harness.h"
 
index 22374d29ffdd4c0379bcd9fa82a9d0c6158c7afb..f5575ef2007cef53b7eaffbff481ba0572c9835f 100644 (file)
@@ -47,7 +47,7 @@ static int change_event(bool enable)
        return ret;
 }
 
-static int reg_enable(long *enable, int size, int bit)
+static int reg_enable(void *enable, int size, int bit)
 {
        struct user_reg reg = {0};
        int fd = open(data_file, O_RDWR);
@@ -69,7 +69,7 @@ static int reg_enable(long *enable, int size, int bit)
        return ret;
 }
 
-static int reg_disable(long *enable, int bit)
+static int reg_disable(void *enable, int bit)
 {
        struct user_unreg reg = {0};
        int fd = open(data_file, O_RDWR);
@@ -90,17 +90,21 @@ static int reg_disable(long *enable, int bit)
 }
 
 FIXTURE(user) {
-       long check;
+       int check;
+       long check_long;
+       bool umount;
 };
 
 FIXTURE_SETUP(user) {
-       USER_EVENT_FIXTURE_SETUP(return);
+       USER_EVENT_FIXTURE_SETUP(return, self->umount);
 
        change_event(false);
        self->check = 0;
+       self->check_long = 0;
 }
 
 FIXTURE_TEARDOWN(user) {
+       USER_EVENT_FIXTURE_TEARDOWN(self->umount);
 }
 
 TEST_F(user, enablement) {
@@ -134,9 +138,9 @@ TEST_F(user, bit_sizes) {
 
 #if BITS_PER_LONG == 8
        /* Allow 0-64 bits for 64-bit */
-       ASSERT_EQ(0, reg_enable(&self->check, sizeof(long), 63));
-       ASSERT_NE(0, reg_enable(&self->check, sizeof(long), 64));
-       ASSERT_EQ(0, reg_disable(&self->check, 63));
+       ASSERT_EQ(0, reg_enable(&self->check_long, sizeof(long), 63));
+       ASSERT_NE(0, reg_enable(&self->check_long, sizeof(long), 64));
+       ASSERT_EQ(0, reg_disable(&self->check_long, 63));
 #endif
 
        /* Disallowed sizes (everything beside 4 and 8) */
@@ -198,7 +202,7 @@ static int clone_check(void *check)
        for (i = 0; i < 10; ++i) {
                usleep(100000);
 
-               if (*(long *)check)
+               if (*(int *)check)
                        return 0;
        }
 
index 32c827a52d7d82ec9b5c791f7b61753510622958..a85980190beafcf2a442be89994c466f6bea653e 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 6a260caeeddc54ef194608bc9d82fba2892bdfcd..dcd7509fe2e05327f6c567ac4cb41cb3047d9eec 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 f893398cda05a522a433c75cf2b2766be649bac7..5288e768b207a9c57fa7ca020f7560cda4d1bc51 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 690378942f8215e543457ba36d918fdcee26769c..e1c3c063c031cd6fb557086b6e24ec7941e76c34 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 e0ffe69c271c6aa84e59bc6f635ebad5b369773d..7093fd5333beb9ec6195eca05213244e4032a156 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 05e310696dd5c68fbfc99e6751dfc60b1ca6908f..01dbf9a6b5a51ed7592e3bed5a6d8d2d26342625 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);
index 834a90bd3270e59d6456e3c51f40fcae35e4c4bc..822ecaa8e4df26f3e5881ee31d68cc7d12218f1c 100644 (file)
@@ -24,11 +24,23 @@ enum dma_data_direction {
 #define dma_map_page(d, p, o, s, dir) (page_to_phys(p) + (o))
 
 #define dma_map_single(d, p, s, dir) (virt_to_phys(p))
+#define dma_map_single_attrs(d, p, s, dir, a) (virt_to_phys(p))
 #define dma_mapping_error(...) (0)
 
 #define dma_unmap_single(d, a, s, r) do { (void)(d); (void)(a); (void)(s); (void)(r); } while (0)
 #define dma_unmap_page(d, a, s, r) do { (void)(d); (void)(a); (void)(s); (void)(r); } while (0)
 
+#define sg_dma_address(sg) (0)
+#define dma_need_sync(v, a) (0)
+#define dma_unmap_single_attrs(d, a, s, r, t) do { \
+       (void)(d); (void)(a); (void)(s); (void)(r); (void)(t); \
+} while (0)
+#define dma_sync_single_range_for_cpu(d, a, o, s, r) do { \
+       (void)(d); (void)(a); (void)(o); (void)(s); (void)(r); \
+} while (0)
+#define dma_sync_single_range_for_device(d, a, o, s, r) do { \
+       (void)(d); (void)(a); (void)(o); (void)(s); (void)(r); \
+} while (0)
 #define dma_max_mapping_size(...) SIZE_MAX
 
 #endif